リアルタイムアプリケーションは、インターバルタイマーを使用して動作をスケジューリングすることがよくあります。インターバルタイマーには「単発」型と「周期」型の 2 つの種類があります。
単発タイマーは、現在時間または絶対時間に相対的な有効期限に設定されるタイマーで、有効期限が終了すると解除されます。この単発タイマーは、データを記憶領域に転送したあとのバッファーの消去や操作のタイムアウトの管理に便利です。
周期タイマーには、初期有効期限 (絶対時間または相対時間) と繰り返しインターバルが設定されています。インターバルタイマーの有効期限が経過するたびに、インターバルタイマーは繰り返して再ロードされます。そして、インターバルタイマーは自動的に再設定されます。このタイマーはデータの記録やサーボの制御に便利です。インターバルタイマー機能を呼び出すとき、システムのハードウェア定期タイマーの精度より小さな時間値は、ハードウェア定期タイマーのインターバルの次の倍数に丸められます。このインターバルは通常 10 ミリ秒です。
SunOS には、2 種類のタイマーインタフェースがあります。setitimer(2) および getitimer(2) インタフェースは「BSD タイマー」という固定設定タイマーを動作させ、timeval 構造体を使用して、時間インターバルを指定します。timer_create(3RT) で作成される POSIX タイマーは POSIX クロック CLOCK_REALTIME を動作させます。POSIX タイマーの動作は timespec 構造体によって表されます。
getitimer(2) および setitimer(2) 関数はそれぞれ、指定された BSD インターバルタイマーの値を取得および確立します。プロセスは 3 つの BSD インターバルタイマーを利用できます (ITIMER_REAL で指定されるリアルタイムタイマーを含む)。BSD タイマーが設定されており、有効になっている (期限切れになることが許可されている) 場合、システムはタイマーを設定したプロセスに適切なシグナルを送信します。
timer_create(3RT) ルーチンは TIMER_MAX 個までの POSIX タイマーを作成できます。呼び出し側はタイマーの有効期限が経過したときに、どのシグナルとそれに関連する値をプロセスに送信するかを指定できます。timer_settime(3RT) および timer_gettime(3RT) ルーチンはそれぞれ、指定された POSIX インターバルタイマーの値を取得および確立します。必要なシグナルの配信が保留状態の間でも、POSIX タイマーは期限切れになることがあります。タイマーの有効期限がカウントされるので、timer_getoverrun(3RT) でそのカウントを取得します。timer_delete(3RT) で POSIX タイマーの割り当てを解除します。
次の例に、setitimer(2) を使用して、定期割り込みを生成する方法と、タイマー割り込みの到着を制御する方法を示します。
#include <unistd.h> #include <signal.h> #include <sys/time.h> #define TIMERCNT 8 void timerhandler(); int timercnt; struct timeval alarmtimes[TIMERCNT]; main() { struct itimerval times; sigset_t sigset; int i, ret; struct sigaction act; siginfo_t si; /* block SIGALRM */ sigemptyset (&sigset); sigaddset (&sigset, SIGALRM); sigprocmask (SIG_BLOCK, &sigset, NULL); /* set up handler for SIGALRM */ act.sa_action = timerhandler; sigemptyset (&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction (SIGALRM, &act, NULL); /* * set up interval timer, starting in three seconds, * then every 1/3 second */ times.it_value.tv_sec = 3; times.it_value.tv_usec = 0; times.it_interval.tv_sec = 0; times.it_interval.tv_usec = 333333; ret = setitimer (ITIMER_REAL, ×, NULL); printf ("main:setitimer ret = %d\n", ret); /* now wait for the alarms */ sigemptyset (&sigset); timerhandler (0, si, NULL); while (timercnt < TIMERCNT) { ret = sigsuspend (&sigset); } printtimes(); } void timerhandler (sig, siginfo, context) int sig; siginfo_t *siginfo; void *context; { printf ("timerhandler:start\n"); gettimeofday (&alarmtimes[timercnt], NULL); timercnt++; printf ("timerhandler:timercnt = %d\n", timercnt); } printtimes () { int i; for (i = 0; i < TIMERCNT; i++) { printf("%ld.%0l6d\n", alarmtimes[i].tv_sec, alarmtimes[i].tv_usec); } }