2008-04-11 20:57:22 +04:00
/*
* Tests for prctl ( PR_GET_TSC , . . . ) / prctl ( PR_SET_TSC , . . . )
*
* Tests if the control register is updated correctly
* at context switches
*
* Warning : this test will cause a very high load for a few seconds
*
*/
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <signal.h>
# include <inttypes.h>
# include <wait.h>
# include <sys/prctl.h>
# include <linux/prctl.h>
/* Get/set the process' ability to use the timestamp counter instruction */
# ifndef PR_GET_TSC
# define PR_GET_TSC 25
# define PR_SET_TSC 26
# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
# endif
2014-09-25 22:23:15 +04:00
static uint64_t rdtsc ( void )
{
2008-04-11 20:57:22 +04:00
uint32_t lo , hi ;
/* We cannot use "=A", since this would use %rax on x86_64 */
__asm__ __volatile__ ( " rdtsc " : " =a " ( lo ) , " =d " ( hi ) ) ;
return ( uint64_t ) hi < < 32 | lo ;
}
2014-09-25 22:23:15 +04:00
static void sigsegv_expect ( int sig )
2008-04-11 20:57:22 +04:00
{
/* */
}
2014-09-25 22:23:15 +04:00
static void segvtask ( void )
2008-04-11 20:57:22 +04:00
{
if ( prctl ( PR_SET_TSC , PR_TSC_SIGSEGV ) < 0 )
{
perror ( " prctl " ) ;
exit ( 0 ) ;
}
signal ( SIGSEGV , sigsegv_expect ) ;
alarm ( 10 ) ;
rdtsc ( ) ;
fprintf ( stderr , " FATAL ERROR, rdtsc() succeeded while disabled \n " ) ;
exit ( 0 ) ;
}
2014-09-25 22:23:15 +04:00
static void sigsegv_fail ( int sig )
2008-04-11 20:57:22 +04:00
{
fprintf ( stderr , " FATAL ERROR, rdtsc() failed while enabled \n " ) ;
exit ( 0 ) ;
}
2014-09-25 22:23:15 +04:00
static void rdtsctask ( void )
2008-04-11 20:57:22 +04:00
{
if ( prctl ( PR_SET_TSC , PR_TSC_ENABLE ) < 0 )
{
perror ( " prctl " ) ;
exit ( 0 ) ;
}
signal ( SIGSEGV , sigsegv_fail ) ;
alarm ( 10 ) ;
for ( ; ; ) rdtsc ( ) ;
}
2016-02-14 03:05:31 +03:00
int main ( void )
2008-04-11 20:57:22 +04:00
{
int n_tasks = 100 , i ;
fprintf ( stderr , " [No further output means we're allright] \n " ) ;
for ( i = 0 ; i < n_tasks ; i + + )
if ( fork ( ) = = 0 )
{
if ( i & 1 )
segvtask ( ) ;
else
rdtsctask ( ) ;
}
for ( i = 0 ; i < n_tasks ; i + + )
wait ( NULL ) ;
exit ( 0 ) ;
}