Linux環境でのハードリアルタイムを実現する「RTAI」リアルタイムOS列伝(27)(3/3 ページ)

» 2022年10月13日 07時00分 公開
[大原雄介MONOist]
前のページへ 1|2|3       

プログラミングそのものは通常のLinuxと基本は同じ

 さてそのRTAIであるが、プログラミングそのものは通常のLinux上のものと基本は同じである。特にUser Mode(ユーザーモード)で動作するプログラムは、ほとんどLinuxの通常のプログラムと同じである。例えば、前ページで挙げた図6と図7のレイテンシ測定ツールは、表示部はUser Modeで動作するので、そのソースもリスト1のようになる。

/*
 * COPYRIGHT (C) 2001  Paolo Mantegazza <mantegazza@aero.polimi.it>
 * COPYRIGHT (C) 2002  Robert Schwebel  <robert@schwebel.de>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 * 
 * 
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <rtai_fifos.h>
static int end;
static void endme(int dummy) { end = 1;}
int main(int argc, char *argv[])
{
	int fd0;
	char nm[RTF_NAMELEN+1];
	long long max = -1000000000, min = 1000000000;
	struct sample { long long min; long long max; int index, ovrn; } samp;
	int n = 0, period, avrgtime;
	setlinebuf(stdout);
	signal(SIGINT, endme);
	if ((fd0 = open(rtf_getfifobyminor(1, nm, sizeof(nm)), O_RDONLY)) < 0) {
		fprintf(stderr, "Error opening %s\n",nm);
		exit(1);
	}
	if (read(fd0, &period, sizeof(period)));
	if (read(fd0, &avrgtime, sizeof(avrgtime)));
	printf("RTAI Testsuite - KERNEL space latency test (output data in nanoseconds)\n");
	printf("\n*** latency verification tool with RTAI own real time kernel tasks ***\n");
	printf("***    period = %i (ns),  avrgtime = %i (s)    ***\n\n", period, avrgtime);
	while (!end) {
		if ((n++ % 21)==0) {
#if 0
			time(&timestamp); 
			tm_timestamp=localtime(&timestamp);
			printf("%04d/%02d/%0d %02d:%02d:%02d\n", tm_timestamp->tm_year+1900, tm_timestamp->tm_mon+1, tm_timestamp->tm_mday, tm_timestamp->tm_hour, tm_timestamp->tm_min, tm_timestamp->tm_sec);
#endif
			printf("RTH|%11s|%11s|%11s|%11s|%11s|%11s\n", "lat min", "ovl min", "lat avg", "lat max", "ovl max", "overruns");
		}
		if (read(fd0, &samp, sizeof(samp)));
		if (min > samp.min) min = samp.min;
		if (max < samp.max) max = samp.max;
		printf("RTD|%11lld|%11lld|%11d|%11lld|%11lld|%11d\n", samp.min, min, samp.index, samp.max, max, samp.ovrn);
		fflush(stdout);
	}
	close(fd0);
	return 0;
}
リスト1 レイテンシ測定ツールのソースコード

 ただし、表示はUser Modeで動作するにしても、肝心の時間測定はKernel Mode(カーネルモード)で動作させる必要がある。このKernel Modeで動作するモジュールとはFIFOを使って通信する格好であり、そのFIFOをopen()で開いているわけだが、その際に指定されるrtf_getfifobyminor()がRTAI独自という程度の話である。一方、Kernel Modeの方は、そもそもPOSIX APIが使えない(POSIX APIはUser Modeでの動作を前提にしている)ので、その代わりにRTAIが提供するAPIを利用する形になっている。

 例えば、時間測定を行うfun()という関数の定義はリスト2のようになる。FIFOへの書き込みはrtf_put()を、デバッグメッセージ出力はrt_printk()を使うといった具合に見慣れないAPIが並ぶが、違いとしてはその程度である。つまり、ハードリアルタイム処理が必要な部分だけをKernel Modeで動作するモジュールとして切り出し、他の部分はUser Modeで記述するような形でアプリケーションを記述することになる。

/* Periodic realtime thread */
 
void fun(long thread)
{
	int diff = 0;
	int i;
	int average;
	int min_diff = 0;
	int max_diff = 0;
	int warmedup;
	rtf_put(DEBUG_FIFO, &period, sizeof(period));
	rtf_put(DEBUG_FIFO, &avrgtime, sizeof(avrgtime));
#ifdef CONFIG_RTAI_FPU_SUPPORT
	if (use_fpu) {
		for(i = 0; i < MAXDIM; i++) {
			a[i] = b[i] = 3.141592;
		}
	}
#endif
	warmedup = samp.ovrn = 0;
	while (1) {
		min_diff =  1000000000;
		max_diff = -1000000000;
		average = 0;
		for (i = 0; i < loops; i++) {
			cpu_used[rtai_cpuid()]++;
			expected += period_counts;
			if (!rt_task_wait_period()) {
				diff = (int) count2nano(rt_get_time() - expected);
			} else {
				samp.ovrn++;
				diff = 0;
			}
			if (diff < min_diff) { min_diff = diff; }
			if (diff > max_diff) { max_diff = diff; }
			average += diff;
#ifdef CONFIG_RTAI_FPU_SUPPORT
			if (use_fpu) {
				dotres = dot(a, b, MAXDIM);
			}
#endif
		}
		if (warmedup) {
			samp.min = min_diff;
			samp.max = max_diff;
			samp.index = average / loops;
			rtf_put(DEBUG_FIFO, &samp, sizeof (samp));
		}
		warmedup = 1;
	}
	rt_printk("\nDOT PRODUCT RESULT = %lu\n", (unsigned long)dotres);
}
リスト2 時間測定を行うfun()の定義

 そういう意味ではRTAIは、RTOSそのものというよりはLinuxにRTOS的環境を提供するもの、という分類が正確なのかもしれない。しかし、逆にRTOS的なものが必要ない部分では通常のLinuxそのものの環境が利用できるわけで、それこそ冒頭でちょっと触れたRTAI-LABみたいなものも容易に構築できるのだ。

 RTAIの難点はターゲットの少なさだろうか。かつてはArmのサポートもあったが、一度廃止になっている。最近また作業を再開しているようだが、実質x86プロセッサのみと考えておいた方がよい。開発チームには10人の名前が挙がっているが、逆にこの程度の開発チームだからそれほど頻繁なアップデートも行われない。最新リリースは2021年5月にリリースされた「RTAI 5.3」で、Linux Kernel 4.19への対応を果たしているが、Linux Kernel 5.xへの対応がいつになるのかは不明だ。あとRTAIはGNUの形で提供されているので、商用での利用には難しいことも考えられる。

 とはいえ、割と手軽にLinux上にハードリアルタイム環境を付加できる、という点ではRTAIはなかなか他にないソリューションではある。このあたりにメリットを感じるユーザーは、試してみるのも面白いのではないかと思う。

前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.