システムインタフェース

タイマ

この節では、SunOS 5.0 から 5.8 で実時間アプリケーションのために使用できるタイミング機能について説明します。実時間アプリケーションでこの機能を活用したい場合は、この節に示されているルーチンについてマニュアルページを参照してください。

SunOS 5.0 から 5.8 のタイミング機能は、「タイムスタンプ」と「インタバル」タイマという 2 つの機能に分けられます。タイムスタンプ機能は経過時間を測定して、アプリケーションが、ある状態の持続時間やイベント間の時間を測定できるようにします。インタバルタイマ機能は、アプリケーションを指定した時間に呼び起こして、アプリケーションが時間の経過に基づいて動作をスケジュールできるようにします。アプリケーションは、タイムスタンプ機能をポーリングして自分をスケジュールすることもできますが、そのようなアプリケーションは、プロセッサを独占して他のシステム関数に悪影響を与えます。

タイムスタンプ機能

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

SunOS 5.0 から 5.8 はハードウェア定期タイマを使用します。ある種のワークステーションでは、これが唯一の時間情報で、タイムスタンプの精度はその定期タイマの解像度までに制限されます。その他のプラットフォームでは、1 マイクロ秒の解像度を持つタイマレジスタによって、SunOS 5.0 から 5.8 ではタイムスタンプ精度は 1 マイクロ秒となっています。

インタバルタイマ機能

実時間アプリケーションは、インタバルタイマを使用して活動をスケジュールすることがよくあります。インタバルタイマには、「単発」型と「周期」型の 2 種類があります。

単発タイマは、現在時間または絶対時間に相対的な有効時間に設定されるタイマです。タイマは、有効時間が終了すると解除されます。このようなタイマは、データを記憶領域に転送した後のバッファの消去や操作のタイムアウトの管理に便利です。

周期タイマには、初期有効時間 (絶対時間または相対時間) と繰り返しインタバルが設定されています。インタバルタイマの有効時間が経過するたびに、タイマは繰り返し再ロードされ、自動的に再度有効になります。このタイマはデータロギングやサーボ制御に便利です。インタバルタイマ機能を呼び出す際は、システムのハードウェア定期タイマの解像度より小さな時間値は、ハードウェア定期タイマインタバル (10 ミリ秒) の時間値より大きい最小の倍数に丸められます。

SunOS 5.0 から 5.8 には、setitimer(2) インタフェースと getitimer(2) インタフェースの 2 組のタイマインタフェースがあります。これらのインタフェースは、タイムインタバルを指定する timeval 構造体を使用して、BSD タイマと呼ばれる固定設定タイマを動作させます。POSIX タイマである timer_create(3RT)CLOCK_REALTIME は、POSIX クロック CLOCK_REALTIME を動作させます。POSIX タイマの動作は、timespec 構造体によって表されます。

getitimer(2) 関数と setitimer(2) 関数は、それぞれ指定された BSD インタバルタイマの値の取り出しと設定を行います。プロセスは ITIMER_REAL で指定する実時間タイマを含め、3 つの BSD インタバルタイマを利用できます。BSD タイマを使用して有効になっている場合は、システムによってタイマにふさわしいシグナルがタイマを設定したプロセスに送信されます。

timer_create(3RT) は、{TIMER_MAX} 個までの POSIX タイマを生成できます。呼び出し側はタイマの有効時間が経過したときに、どのシグナルと関連値をプロセスに送るかを指定できます。timer_settime(3RT)timer_gettime(3RT) は、指定された POSIX インタバルタイマの値を、それぞれ設定および検索します。必要なシグナルが保留状態にある間に POSIX タイマの有効時間が経過すると配信がカウントされ、timer_getoverrun(3RT) はそのような有効時間切れのカウントを検索します。timer_delete(3RT) は、POSIX タイマの割り当てを解除します。

例 8-1 に、setitimer(2) を使用して定期割り込みを発生させる方法とタイマ割り込みの到着の制御方法を示します。


例 8-1 タイマ割り込みの制御


#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;

	/* SIGALRM をブロッキングする */
	sigemptyset (&sigset);
	sigaddset (&sigset, SIGALRM);
	sigprocmask (SIG_BLOCK, &sigset, NULL);

	/* SIGALRM のためのハンドラを設定する */
	act.sa_action = timerhandler;
	sigemptyset (&act.sa_mask);
	act.sa_flags = SA_SIGINFO;
	sigaction (SIGALRM, &act, NULL);
	/*
	 * 3 秒後に開始し、そのあとは 3 分の 1 秒おきに開始するように 
	 * インタバルタイマを設定する
	 */
	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);

	/* 現在はアラーム待ち */
	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);
	}
}