さてその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(×tamp);
tm_timestamp=localtime(×tamp);
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;
}
ただし、表示は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);
}
そういう意味では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はなかなか他にないソリューションではある。このあたりにメリットを感じるユーザーは、試してみるのも面白いのではないかと思う。
Windows環境と共存可能なRTOS「RTX/RTX64」の生存戦略
NXP/Freesclaeのプロセッサならタダで使えるRTOS「MQX」はそつがない作り
ルネサスの「RX110」でも動くPOSIX互換の「UNISON RTOS」はウェアラブル向け
省フットプリントで安定かつ高速な「scmRTOS」からRTOSの基礎を学ぶ
RTOS的に使えるがRTOSではない「QP」はMATLABの代替候補にもなり得る?Copyright © ITmedia, Inc. All Rights Reserved.
組み込み開発の記事ランキング
コーナーリンク
よく読まれている編集記者コラム