Linux環境でのハードリアルタイムを実現する「RTAI」:リアルタイムOS列伝(27)(3/3 ページ)
IoT(モノのインターネット)市場が拡大する中で、エッジ側の機器制御で重要な役割を果たすことが期待されているリアルタイムOS(RTOS)について解説する本連載。第27回は、Linux上でRTOS環境を提供する「RTAI」紹介する。
プログラミングそのものは通常の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(×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はなかなか他にないソリューションではある。このあたりにメリットを感じるユーザーは、試してみるのも面白いのではないかと思う。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- 連載記事「リアルタイムOS列伝」バックナンバー
- Windows環境と共存可能なRTOS「RTX/RTX64」の生存戦略
IoT(モノのインターネット)市場が拡大する中で、エッジ側の機器制御で重要な役割を果たすことが期待されているリアルタイムOS(RTOS)について解説する本連載。第26回は、多くの機器に採用されているWindows環境との共存が可能なRTOS「RTX/RTX64」を紹介する。 - NXP/Freesclaeのプロセッサならタダで使えるRTOS「MQX」はそつがない作り
IoT(モノのインターネット)市場が拡大する中で、エッジ側の機器制御で重要な役割を果たすことが期待されているリアルタイムOS(RTOS)について解説する本連載。第25回は、NXP/FreesclaeのMCUやMPUであればロイヤルティーフリーで利用できるRTOS「MQX」を紹介する。 - ルネサスの「RX110」でも動くPOSIX互換の「UNISON RTOS」はウェアラブル向け
IoT(モノのインターネット)市場が拡大する中で、エッジ側の機器制御で重要な役割を果たすことが期待されているリアルタイムOS(RTOS)について解説する本連載。第24回は、POSIX互換のリアルタイムカーネル「Nanoexec」を用いたウェアラブル端末向けRTOS「UNISON RTOS」を紹介する。 - 省フットプリントで安定かつ高速な「scmRTOS」からRTOSの基礎を学ぶ
IoT(モノのインターネット)市場が拡大する中で、エッジ側の機器制御で重要な役割を果たすことが期待されているリアルタイムOS(RTOS)について解説する本連載。第23回は、20年近い歴史を持ち、省フットプリントと高速を特徴とする古典的RTOS「scmRTOS」を紹介する。 - RTOS的に使えるがRTOSではない「QP」はMATLABの代替候補にもなり得る?
IoT(モノのインターネット)市場が拡大する中で、エッジ側の機器制御で重要な役割を果たすことが期待されているリアルタイムOS(RTOS)について解説する本連載。第22回は、厳密にはRTOSではないものの、RTOS的な利用も可能なフレームワーク「QP」を紹介する。