Я хочу, чтобы меня прерывали на частотах, кратных десяти, поэтому включение прерываний из / dev / rtc не идеально. Я хотел бы поспать 1 миллисекунду или 250 микросекунд между прерываниями.
Включение периодических прерываний из / dev / hpet работает довольно хорошо, но на некоторых машинах это не работает. Очевидно, что я не могу использовать его на машинах, которые на самом деле не имеют HPET. Но я не могу заставить его работать на некоторых машинах, у которых hpet также доступен как источник синхронизации. Например, в Core 2 Quad пример программы, включенной в документацию по ядру, завершается с ошибкой в HPET_IE_ON при установке на опрос.
Было бы лучше использовать интерфейс itimer, предоставляемый Linux, вместо непосредственного взаимодействия с драйвером аппаратного устройства. А в некоторых системах itimer обеспечивает периодические прерывания, которые более стабильны во времени. То есть, поскольку hpet не может прерывать с той частотой, которую я хочу, прерывания начинают дрейфовать со времени стены. Но я вижу, что некоторые системы спят намного дольше (10+ миллисекунд), чем они должны использовать itimer.
Вот тестовая программа, использующая itimer для прерываний. В некоторых системах он выводит только одно предупреждение, что он спал около 100 микросекунд или около того в течение целевого времени. На других, он будет распечатывать пакеты с предупреждением, что он спал 10+ миллисекунд в течение целевого времени. Скомпилируйте с -lrt и запустите с sudo chrt -f 50 [имя]
#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;
}