プログラミングインタフェース

タイミング機能

この節では、SunOS におけるリアルタイムアプリケーションで利用できるタイミング機能について説明します。このようなメカニズムをリアルタイムアプリケーションで使用するには、この節で説明する各ルーチンのマニュアルページの詳細な情報が必要です。

SunOS のタイミングインタフェースは、「タイムスタンプ」と「インターバルタイマー」の 2 つの機能に分類できます。「タイムスタンプインタフェース」は経過時間を測定する方法を提供します。したがって、タイムスタンプインタフェースを使用すると、アプリケーションはある状態の持続時間やイベント間の時間を測定できます。「インターバルタイマー」を使用すると、アプリケーションはさまざまな活動を指定された時刻に呼び起こし、時間の経過に基づいてスケジューリングできます。

タイムスタンプインタフェース

タイムスタンプは 2 つのインタフェースによって提供されます。gettimeofday(3C) は、グリニッジ標準時間 1970 年 1 月 1 日午前 0 時からの秒数とマイクロ秒数によって時間を表し、現在の時間を timeval 構造体に提供します。clock_gettime は、CLOCK_REALTIMEclockid を使用して、gettimeofday(3C) が戻すタイムインターバルと同じ時間を秒とナノ秒で表し、現在の時間を timespec 構造体に提供します。

SunOS はハードウェア定期タイマーを使用します。このハードウェア定期タイマーが唯一の時間情報源であるワークステーションもあります。ハードウェア定期タイマーが唯一の時間情報源である場合、タイムスタンプの精度はハードウェア定期タイマーの精度に制限されます。その他のプラットフォームでは、タイマーレジスタの精度が 1 マイクロ秒である場合、そのタイムスタンプの精度は 1 マイクロ秒であることを意味します。

インターバルタイマーインタフェース

リアルタイムアプリケーションは、インターバルタイマーを使用して動作をスケジューリングすることがよくあります。インターバルタイマーには「単発」型と「周期」型の 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) を使用して、定期割り込みを生成する方法と、タイマー割り込みの到着を制御する方法を示します。


例 12–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, &times, 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);
	}
}