10의 제곱 주파수에서 인터럽트되기를 원하므로/dev/rtc에서 인터럽트를 활성화하는 것이 이상적이지 않습니다. 인터럽트간에 1 밀리 초 또는 250 마이크로 초를 자고 싶습니다. 는/dev/HPET에서주기적인 인터럽트를 사용Linux에서 가장 정확한 실시간 정기 인터럽트를 얻으려면 어떻게해야합니까?
는꽤 잘 작동하지만, 일부 컴퓨터에서 작동하지 않습니다. 분명히 HPET가없는 컴퓨터에서는 사용할 수 없습니다. 하지만 클럭 소스로 사용할 수있는 일부 컴퓨터에서도 작동하지 않습니다. 예를 들어 Core 2 Quad에서 poll으로 설정하면 HPET_IE_ON에서 커널 설명서에 포함 된 예제 프로그램이 실패합니다.
대신 직접 하드웨어 장치 드라이버와 인터페이스의 리눅스가 제공하는 itimer 인터페이스를 사용하는 것이 좋을 것입니다. 그리고 일부 시스템에서는 itimer가 주기적으로보다 안정적인 인터럽트를 제공합니다. 즉, hpet은 내가 원하는 빈도로 정확히 인터럽트 할 수 없으므로 인터럽트가 벽 시간에서 벗어나기 시작합니다. 그러나 일부 시스템은 itimer를 사용해야하는 것보다 더 길게 (10 밀리 초 이상) 수면 방식을보고 있습니다.
다음은 인터럽트에 itimer를 사용하는 테스트 프로그램입니다. 일부 시스템에서는 대상 시간 동안 약 100 마이크로 초 정도 잤다는 경고 만 출력합니다. 다른 사람들은 목표 시간 동안 10 밀리 초 이상 잤다는 경고를 출력 할 것입니다. 커널 스케줄러를 호출 할 때 -lrt로 컴파일하고 50 -f sudo는 CHRT 실행 [이름]에 관계없이 사용하는 타이밍 메커니즘의
#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;
}
이것은 커널 버그 일 수 있습니다. 내 itimer 예제는 2.6.32를 사용하는 모든 컴퓨터에서 정상적으로 작동하지만 2.6.35 또는 2.6.38에서는 정상적으로 작동하지 않는 것 같습니다. – Matt