検索
連載

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

IoT(モノのインターネット)市場が拡大する中で、エッジ側の機器制御で重要な役割を果たすことが期待されているリアルタイムOS(RTOS)について解説する本連載。第27回は、Linux上でRTOS環境を提供する「RTAI」紹介する。

Share
Tweet
LINE
Hatena
前のページへ |       

プログラミングそのものは通常の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はなかなか他にないソリューションではある。このあたりにメリットを感じるユーザーは、試してみるのも面白いのではないかと思う。

Copyright © ITmedia, Inc. All Rights Reserved.

前のページへ |       
ページトップに戻る