【发布时间】:2011-08-15 13:38:33
【问题描述】:
我希望以 10 次方的频率被打断,因此从 /dev/rtc 启用中断并不理想。我想在两次中断之间睡 1 毫秒或 250 微秒。
从 /dev/hpet 启用周期性中断效果很好,但它似乎不适用于某些机器。显然,我不能在实际上没有 HPET 的机器上使用它。但我也无法让它在一些将 hpet 用作时钟源的机器上工作。例如,在 Core 2 Quad 上,内核文档中包含的示例程序在设置为 poll 时会在 HPET_IE_ON 处失败。
最好使用Linux提供的itimer接口,而不是直接与硬件设备驱动程序接口。在某些系统上,定时器提供了随着时间的推移更加稳定的周期性中断。也就是说,由于 hpet 不能以我想要的频率中断,中断开始从墙上时间漂移。但是我看到一些系统的睡眠时间比使用定时器的时间长(10 多毫秒)。
这是一个使用定时器中断的测试程序。在某些系统上,它只会打印出一个警告,即它在目标时间内睡了大约 100 微秒左右。在其他情况下,它将打印出多批警告,表明它在目标时间上睡了 10 多毫秒。使用 -lrt 编译并使用 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;
}
【问题讨论】:
-
这可能是内核错误。我的 itimer 示例似乎在所有使用 2.6.32 的机器上都可以正常工作,但在 2.6.35 或 2.6.38 上却不行。