I want to be interrupted at frequencies that have ten, so turning on interrupts from / dev / rtc is not ideal. I would like to sleep 1 millisecond or 250 ฮผs between interrupts.
Enabling periodic interrupts from / dev / hpet works very well, but it doesn't seem to work on some machines. Obviously, I can't use it on machines that don't actually have HPET. But I can't get it to work on some machines that have hpet available as a synchronization source. For example, on Core 2 Quad, the sample program included in the kernel documentation cannot be executed using HPET_IE_ON when configured to poll.
It would be better to use the itimer interface provided by Linux, instead of interacting directly with the device driver. And on some systems, itimer provides periodic interrupts that are more stable over time. That is, since hpet cannot be interrupted with exactly the frequency I want, interrupts begin to drift from the wall time. But I see that some systems sleep longer (10+ milliseconds) than they should use itimer.
Here's a test program using itimer for interrupts. On some systems, it will print only one warning that it has slept for about 100 microseconds or so during the target time. In other cases, he gives a batch of warnings that he slept for 10+ milliseconds during the target time. Compile with -lrt and run using sudo chrt -f 50 [name]
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <error.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/time.h> #include <time.h> #include <signal.h> #include <fcntl.h> #define NS_PER_SECOND 1000000000LL #define TIMESPEC_TO_NS( aTime ) ( ( NS_PER_SECOND * ( ( long long int ) aTime.tv_sec ) ) \ + aTime.tv_nsec ) int main() { // Block alarm signal, will be waited on explicitly sigset_t lAlarm; sigemptyset( &lAlarm ); sigaddset( &lAlarm, SIGALRM ); sigprocmask( SIG_BLOCK, &lAlarm, NULL ); // Set up periodic interrupt timer struct itimerval lTimer; int lReceivedSignal = 0; lTimer.it_value.tv_sec = 0; lTimer.it_value.tv_usec = 250; lTimer.it_interval = lTimer.it_value; // Start timer if ( setitimer( ITIMER_REAL, &lTimer, NULL ) != 0 ) { error( EXIT_FAILURE, errno, "Could not start interval timer" ); } struct timespec lLastTime; struct timespec lCurrentTime; clock_gettime( CLOCK_REALTIME, &lLastTime ); while ( 1 ) { //Periodic wait if ( sigwait( &lAlarm, &lReceivedSignal ) != 0 ) { error( EXIT_FAILURE, errno, "Failed to wait for next clock tick" ); } clock_gettime( CLOCK_REALTIME, &lCurrentTime ); long long int lDifference = ( TIMESPEC_TO_NS( lCurrentTime ) - TIMESPEC_TO_NS( lLastTime ) ); if ( lDifference > 300000 ) { fprintf( stderr, "Waited too long: %lld\n", lDifference ); } lLastTime = lCurrentTime; } return 0; }