<!doctype linuxdoctr system>
<article>
<title>RTLinux HOWTO</title>
<author>
<url url="mailto:dinildivakaran@rediffmail.com" name="Dinil Divakaran">
</author>
<!-- always have a version number and a date (YYYY-MM-DD format) -->
<date>1.1, 2002-08-29</date>
<!-- 日本語版 -->
<trans>日本語訳: yomoyomo &lt;ymgrtq@ma.neweb.ne.jp&gt;
<tdate> v1.1j 2003 年 01 月 18 日
<!-- 日本語版 -->
<abstract>
<!--
RTLinux Installation and writing realtime programs in Linux
-->
RTLinux の導入と Linux でリアルタイムなプログラムを書くことについて
</abstract>
<toc>
<sect>
<!--
Introduction
-->
はじめに
<sect1>
<!--
Purpose
-->
目的
<p>
<!--
This document aims at getting the novice user up and running with RTLinux in as painless a
manner as possible.
-->
この文書は、初心者のユーザを助け、できるだけ簡単に RTLinux を稼働
できるようにすることを目的とします。

<sect1>
<!--
Who should read this HOWTO
-->
この HOWTO を読むべき人
<p>
<!--
This document is meant for all those who wish to know the working of a 
realtime kernel. For those of you already familiar with module programming,
the document wouldn't appear as a difficult one. And for others, you needn't
worry; since only the basic concepts of module programming are required,
which we would indeed discuss, as and when required.
-->
この文書は、リアルタイムカーネルの動作を知りたいと思っている人達すべてを
対象にしています。既にモジュールプログラミングに精通している人達は、
この文書を難しいものとは感じないでしょう。そうでない人達にしても、
心配する必要はありません。モジュールプログラミングの基本概念しか
必要ありませんし、それについては必要なところで実際に議論しますので。

<sect1>
<!--
Acknowledgement
-->
謝辞
<p>
<!--
First of all I would like to thank my advisor, Pramode C. E, for his
encouragement and help. Also I express my sincere appreciation to Victor Yodaiken.
This document would not have been possible without all the information
gathered from different papers contributed by Victor Yodaiken. I am 
also grateful to Michael Barabanov for his thesis on "A Linux-base
Real-Time Operating System".   
-->
まず何より、私を励まし助けてくれた、私の相談相手である
Pramode C. E に感謝したいと思います。また、Victor Yodaiken
にも心からの感謝を述べさせてもらいます。この文書は、Victor Yodaiken
が寄稿した種々の論文から取り入れた情報なしには成立しなかったでしょう。
また、"A Linux-based Real-Time Operating System" という論文を書いた
Michael Barabanov にも感謝します。
<!--
訳者ノート:Michael Barabanov の論文のタイトルが間違っていたので訂正した。
-->

<sect1>
<!--
Feedback
-->
フィードバック
<p>
<!--
Any doubt or comment about this document, is always welcome. Please 
feel free to email <url url="mailto:dinildivakaran@rediffmail.com" name="me">. If 
there is any mistake in this document, please let me know so that I can correct it in the
next revision. Thanks. 
-->
この文書に関する疑問や意見はどんなものでも常に歓迎します。遠慮なく
<url url="mailto:dinildivakaran@rediffmail.com" name="私に">
メールしてください。この文書中に何か間違いを見つけたら、
次版で修正できるように私に知らせてください。ご協力感謝します。
<sect1>
<!--
Distribution Policy
-->
配布の方針
<p>
Copyright (C)2002 Dinil Divakaran.
<p>
<!--
This document  is free; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version.
-->
この文書はフリーです。Free Software Foundation により発行されている
GNU General Public License バージョン2、もしくは(任意で)
それ以降のバージョンの条件に従ってこの文書を再配布したり修正できます。
<p>
<!--
This document 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
General Public License for more details.
-->
この文書は役に立つことを期待して配布されるものですが、
いかなる保証も行いません。商品性や特定用途への適合性についての暗黙の
保証すらありません。詳しくは、GNU General Public License
をご覧ください。

<sect>
<!--
Installing RTLINUX
-->
RTLINUX のインストール
<p>
<!--
The first step in the compilation of RTLinux kernel, is to download a 
pre-patched kernel 2.2.18 (x86 only) 
<url url="http://ftp.kernel.org/pub/linux/kernel/v2.2/linux-2.2.18.tar.gz" name="2.2.18"> 
(x86 only) 
or <url url="http://ftp.kernel.org/pub/linux/kernel/v2.4/linux-2.4.0-test1.tar.gz" 
name="2.4.0-test1"> (x86, PowerPC, Alpha) into /usr/src/ and untar it. Also put a fresh 
copy of 
RTLinux kernel (version 3.0) from
<url url="http://www.rtlinux.org" name="www.rtlinux.org"> in /usr/src/rtlinux/.
(We will use $ to represent the prompt).
-->
RTLinux カーネルのコンパイルの第一段階は、
予めパッチのあたったカーネル
<url url="http://ftp.kernel.org/pub/linux/kernel/v2.2/linux-2.2.18.tar.gz" name="2.2.18">
(x86 only) か
<url url="http://ftp.kernel.org/pub/linux/kernel/v2.4/linux-2.4.0-test1.tar.gz" name="2.4.
0-test1">
(x86, PowerPC, Alpha) をダウンロードして /usr/src/
で展開することです。また
<url url="http://www.rtlinux.org" name="www.rtlinux.org">
から RTLinux カーネル(バージョン3.0)を新たにコピーして /usr/src/rtlinux/
に置いてください。(この文書では、プロンプトを表すのに $ を使います)

<enum>
<item>
<!--
Now, configure the Linux kernel :
-->
それでは Linux カーネルを設定してください:

<!--
<verb>
		$ cd /usr/src/linux
		$ make config
			or
		$ make menuconfig
			or
		$ make xconfig
</verb>
-->
<verb>
		$ cd /usr/src/linux
		$ make config
			か
		$ make menuconfig
			もしくは
		$ make xconfig
</verb>

<item>
<!--
For building the kernel image, type :
-->
カーネルイメージをビルドするには、以下のように入力してください:

<verb>
		$ make dep
		$ make bzImage
		$ make modules
		$ make modules_install
		$ cp arch/i386/boot/bzImage /boot/rtzImage
</verb>

<item>
<!--
Next step is to configure LILO. Type in the following lines in the file
/etc/lilo.conf
-->
次に LILO の設定を行います。/etc/lilo.conf ファイルに以下の4行を
追加してください。

<verb>
		image=/boot/rtzImage
		label=rtl
		read-only
		root=/dev/hda1
</verb>

<!--
WARNING: replace /dev/hda1 in the above with your root filesystem. The
easiest way to find out which filesystem it should be, take a look
at the existing entry in your /etc/lilo.conf for "root=".
-->
警告: 上記の /dev/hda1 を、あなたの環境におけるルートファイルシステム
に置き換えてください。しかるべきファイルシステムを見つける最も簡単な方法は、
/etc/lilo.conf ファイルの既存のエントリにおける "root="
を見ることです。

<item>
<!--
Now, restart your computer and load the RTLinux kernel by typing 'rtl'
at the LILO prompt. Then 'cd' to /usr/src/rtlinux/ and configure RTLinux.
-->
それではコンピュータを再起動し、LILO プロンプトで 'rtl' と入力して
RTLinux カーネルをロードしてください。それから /usr/src/rtlinux/
に 'cd' し、RTLinux を設定します。

<!--
<verb>
		$ make config  
			or
		$ make menuconfig
			or
		$ make xconfig
</verb>
-->
<verb>
		$ make config  
			か
		$ make menuconfig
			もしくは
		$ make xconfig
</verb>

<item>
<!--
Finally, for compiling RTLinux
-->
ようやく RTLinux のコンパイルです

<verb>
		$ make
		$ make devices
		$ make install
</verb>

</enum>

<!--
The last step will create the directory:
-->
最後の手順により、以下のディレクトリが作成されます:

<!--
	/usr/rtlinux-xx (xx denotes the version)
-->
	/usr/rtlinux-xx (xx はバージョンを意味する)

<!--
which contains the default installation directory for RTLinux which is
needed to create and compile user programs (that is, it contains the
include files, utilities, and documentation). It will also create a
symbolic link:
-->
ここは RTLinux のデフォルトのインストール先となるディレクトリで、
ユーザプログラムを作成したりコンパイルするのに必要なもの
(include ファイル、ユーティリティ、ドキュメントなど) が入ります。
また、最後の手順により /usr/rtlinux-xx を指す以下のシンボリックリンク
が作成されます。

	/usr/rtlinux

<!--
which points to /usr/rtlinux-xx.  In order to maintain future
compatibility, please make sure that all of your own RTLinux programs
use /usr/rtlinux as its default path.
-->
将来にわたる互換性を確保するために、
あなた自身が作成したすべての RTLinux 用プログラムにおいて、
デフォルトのパスに /usr/rtlinux を適用するようにしてください。

<!--
NOTE : If you change any Linux kernel options, please don't forget to do:
-->
注記: 何か Linux カーネルのオプションを変更する場合は、
以下の手順を行うことをお忘れなく:

<verb>
		$ cd /usr/src/rtlinux
		$ make clean
		$ make
		$ make install
</verb>

<sect>
<!--
Why RTLinux
-->
なぜ RTLinux なのか
<p>
<!--
The reasons for the design of RTLinux can be understood by examining the
working of the standard Linux kernel. The Linux kernel separates the hardware 
from the user-level tasks. The kernel uses scheduling algorithms and assigns 
priority to each task for providing good average performances or throughput. 
Thus the kernel has the ability to suspend any
user-level task, once that task has outrun the time-slice allotted to it
by the CPU. This scheduling algorithms along with device drivers, 
uninterruptible system calls, the use of interrupt disabling and virtual
memory operations are sources of unpredictability. That is to say,
these sources cause hindrance to the realtime performance of a task. 
-->
標準の Linux カーネルの動作を調べれば、RTLinux を設計した理由が分かります。
Linux カーネルはハードウェアをユーザレベルのタスクから切り離します。
カーネルはスケジューリングアルゴリズムを用い、平均的に優れた性能、
スループットを提供するよう各タスクに優先度を割り当てます。従って、
どのユーザレベルのタスクであっても、そのタスクが CPU
により割り当てられているタイムスライスを超過したら、
Linux カーネルはタスクを停止できます。このスケジューリングアルゴリズム
に加え、デバイスドライバ、割り込み不可能なシステムコール、
割り込み無効化や仮想メモリ操作などが予測不可能性(unpredictability)
の原因になります。つまり、以上の要素がタスクのリアルタイム性能の
障害になっています。

<p>
<!--
You might already be familiar with the non-realtime performance, say, 
when you are listening to the music played using 'mpg123' or any other player.
After executing this process for 
a pre-determined time-slice, the standard Linux kernel could preempt the 
task and give the CPU to another one 
(e.g. one that boots up the X server or Netscape). Consequently, 
the continuity of the music is lost. Thus, in trying to ensure fair distribution of
CPU time among all processes, the kernel can prevent other events from 
occurring. 
-->
Linux がリアルタイムな性能を保証しないことは、例えば 'mpg123'
などのプレイヤーで音楽を聴いているなら、既にご承知のことかもしれません。
予め決められたタイムスライスでプロセスを実行した後で、標準の
Linux カーネルはタスクを中断して CPU に別のタスク(例えば、X サーバや
Netscape の立ち上げを行うタスク)を割り当てることが可能です。
結果として、音楽の連続性が失われてしまいます。このように、
CPU 時間をすべてのプロセスに公平に分配しようと試みることにより、
カーネルは他のイベントが起こらないようにできるのです。

<p>
<!--
A realtime kernel should be able to guarantee the timing requirements of
the processes under it.
The RTLinux kernel accomplishes realtime performances by removing such
sources of unpredictability as discussed above. We can consider the RTLinux
kernel as sitting between the standard Linux kernel and the hardware. The 
Linux kernel sees the realtime layer as the actual hardware. Now, the
user can both introduce and set priorities to each and every task. The user
can achieve correct timing for the processes by deciding on the 
scheduling algorithms, priorities, frequency of execution etc. The 
RTLinux kernel assigns lowest priority to the standard Linux kernel. Thus
the user-task will be executed in realtime.
-->
リアルタイムカーネルならば、そのカーネルの元で動くプロセスが要求する
タイミングを保証することが可能なはずです。RTLinux カーネルは、
上で議論した予測不可能性の原因となるものを除去することにより
リアルタイム性能を実現しています。RTLinux カーネルは、標準の
Linux カーネルとハードウェアの間に位置すると考えることができます。
Linux カーネルは、リアルタイム層を事実上のハードウェアとみなします。
つまりユーザは、一つ一つのタスクの導入とその優先度の設定の両方が行えます。
ユーザはスケジューリングアルゴリズム、優先度、
実行頻度などを決めることでプロセスの正確な実行タイミングを実現できます。
RTLinux カーネルは、標準の Linux カーネルに最低の優先度を割り当てます。
こうすることでユーザタスクがリアルタイムに実行されることになります。

<p>
<!--
The actual realtime performance is obtained by intercepting all
hardware interrupts. Only for those interrupts that are related to
the RTLinux, the appropriate interrupt service routine is run. All other
interrupts are held and passed to the Linux kernel as software interrupts when
the RTLinux kernel is idle and then the standard Linux kernel runs. The RTLinux
executive is itself nonpreemptible.
-->
実際のリアルタイム性能は、すべてのハードウェア割り込みを遮断
することにより達成されます。RTLinux に関連する割り込みに対してのみ、
適切な割り込みサービスルーチンが動作します。それ以外の割り込みは
全て一旦保留され、RTLinux カーネルがアイドル状態になり標準の Linux
カーネルが稼働したときにソフトウェア割り込みとしてカーネルにわたります。
RTLinux の実行部そのものはノンプリエンプティブです。

<p>
<!--
Realtime tasks are privileged (that is, they have direct access to hardware), and they
do not use virtual memory. Realtime tasks are written as special Linux
modules that can be dynamically loaded into memory. The 
initialization code for a realtime tasks initializes the realtime task 
structure and informs RTLinux kernel of its deadline,
period, and release-time constraints. 
-->
リアルタイムタスクは優先され(つまりそれらはハードウェアに直接アクセスする)、
仮想メモリは利用しません。リアルタイムタスクは、
メモリに動的にロード可能な、特殊な Linux モジュールとして書かれます。
リアルタイムタスクの初期化コードは、リアルタイムタスク構造体を初期化し、
RTLinux カーネルにその期限、周期、そして解放時間制限を通知します。

<p>
<!--
RTLinux co-exists along with the Linux kernel since it leaves the Linux
kernel untouched. Via a set of relatively simple modifications,
it manages to convert the existing Linux kernel into a hard realtime environment
without hindering future Linux development.
-->
Linux カーネルには手を加えないので、RTLinux は Linux
カーネルと共存します。比較的単純な修正を一通り行えば、将来の Linux
開発の妨げになることなく、既存の Linux カーネルをハードリアルタイム環境に
うまく変えることができます。

<sect>
<!--
Writing RTLinux Programs
-->
RTLinux のプログラムを書く
<sect1>
<!--
Introduction to writing modules
-->
モジュールの書き方入門
<p>
<!--
So what are modules? A Linux module is nothing but an object file, usually 
created with the -c flag argument to gcc. The module itself is created by
compiling an ordinary C language file without the main() function. Instead 
there will be a pair of init_module/cleanup_module functions:
-->
さてモジュールとは何でしょうか? Linux のモジュールは、通常 gcc に
-c フラグ引数を付けて生成されたオブジェクトファイルに過ぎません。
モジュール自体は、main() 関数のない普通の C 言語ファイルをコンパイル
することにより生成されます。main() 関数がない代わりに、init_module
関数と cleanup_module 関数のペアが含まれます:

<itemize>
<item>
<!--
The init_module() which is called when the module is inserted into the kernel.
It should return 0 on success and a negative value on failure. 
-->
init_module() は、そのモジュールをカーネルに組みこむ際にコールされます。
成功時には 0 を返し、失敗したときには負の値を返します。
<item>
<!--
The cleanup_module() which is called just before the module is removed.
-->
cleanup_module() は、そのモジュールを削除する直前にコールされます。
</itemize>

<!--
Typically, init_module() either registers a handler for something with the 
kernel, or it replaces one of the kernel function with its own code 
(usually code to do something and then call the original function). 
The cleanup_module() function is supposed to undo whatever init_module() did, 
so the module can be unloaded safely.
-->
通常 init_module() では、カーネルに何か処理を行うハンドラを登録するか、
カーネルの関数の一つを独自のコード(通常は何か行い、
それから元の関数をコールするコード)に置き換えるかします。
cleanup_module() 関数は、init_module() が行ったことすべてを元に戻す
ことになっているので、モジュールを安全に外すことが可能です。

<!--
For example, if you have written a C file called module.c 
(with init_module() and cleanup_module() replacing the main() function), 
the code can be converted into a module by typing :
-->
例えば、module.c という名前の C 言語ファイル(main() 関数の代わりに
init_module() と cleanup_module() がある)を書いたとしたら、
以下のように入力すれば、そのコードがモジュールに変換されます:

<verb>
	$ gcc -c {SOME-FLAGS} my_module.c
</verb>

<!--
This command creates a module file named module.o, which can now be inserted
into the kernel by using the 'insmod' command :
-->
このコマンドにより module.o という名前のモジュールファイルが生成されます。
module.o は 'insmod' コマンドを使用してカーネルに組みこめます:

<verb>
	$ insmod module.o
</verb>

<!--
Similarly, for removing the module, you can use the 'rmmod' command :
-->
同様にモジュールを削除するには 'rmmod' を使えばよいです:

<verb>
	$ rmmod module
</verb>

<sect1>
<!--
Creating RTLinux Threads
-->
RTLinux におけるスレッドの作成
<p>
<!--
A realtime application is usually composed of several ``threads'' of execution.
Threads are light-weight processes which share a common address space.
In RTLinux, all threads share the Linux kernel address space. 
The advantage of using threads is that switching between threads 
is quite inexpensive when compared with context switch. We can have 
complete control over the execution of a thread by using different functions
as will be shown in the examples following.
-->
通常リアルタイムアプリケーションは、複数の実行「スレッド」で構成されます。
スレッドは、共通のアドレス空間を共有する軽量のプロセスです。RTLinux では、
すべてのスレッドが Linux カーネルのアドレス空間を共有します。
スレッドを使うことの利点は、コンテキストスイッチに比べて
スレッド間の切り替えが極めて軽いことにあります。
以下の例で紹介する各種関数を利用すれば、スレッドの実行を完全に制御できます。

<sect1>
<!--
An example program
-->
例プログラム
<p>
<!--
The best way to understand the working of a thread is to trace a realtime 
program. For example, the program shown below will execute once every second,
and during each iteration it will print 'Hello World'.
-->
スレッドの動作を理解するのに最も良いのは、リアルタイムプログラムを
トレースすることです。例えば、以下に示すプログラムは、1秒に一度実行し、
その度に 'Hello World' と出力します。

プログラムコード (file - hello.c) :

<verb>
#include &lt;rtl.h&gt;
#include &lt;time.h&gt;
#include &lt;pthread.h&gt;

pthread_t thread;

void * thread_code(void)
{
        pthread_make_periodic_np(pthread_self(), gethrtime(), 1000000000);

        while (1)
        {
                pthread_wait_np ();
                rtl_printf("Hello World\n");
        }

        return 0;
}

int init_module(void) 
{
   return pthread_create(&amp;thread, NULL, thread_code, NULL);
}

void cleanup_module(void) 
{
   pthread_delete_np(thread);
}
</verb>

<!--
So, let us start with the init_module(). The init_module() invokes 
pthread_create(). This is for creating a new thread that executes 
concurrently with the calling thread. <em>This function must only be 
called from the Linux kernel thread (i.e., using init_module()).</em>
-->
それでは init_module() から始めましょう。init_module() が
pthread_create() をコールしています。pthread_create() は、
コールするスレッドと同時に動作する、新規のスレッドを作成する関数です。
<em>この関数は、Linux カーネルスレッドからしか
(つまり、init_module() を用いてしか)コールしてはいけません。</em>

<verb>
	int  pthread_create(pthread_t  * thread,
	                    pthread_attr_t * attr,
	                    void * (*thread_code)(void *),
	                    void * arg);
</verb>

<!--
The new thread created is of type pthread_t, defined in
the header pthread.h. This thread executes the function thread_code(),
passing it <em>arg</em> as its argument. The <em>attr</em>
argument specifies thread attributes to be applied to the new thread. 
If <em>attr</em> is NULL, default attributes are used.
-->
作成された新規スレッドの型は pthread_t で、これは pthread.h
ヘッダファイルで定義されています。このスレッドは、関数 thread_code()
を実行し、それに <em>arg</em> を引数として渡します。引数 <em>attr</em>
は、新規スレッドに適用されるスレッド属性を指定します。もし <em>attr</em>
が NULL なら、デフォルトの属性が適用されます。

<!--
So here, thread_code() is invoked with no argument. thread_code
has three components - initialization, run-time and termination.
-->
ここでは thread_code() は引数なしでコールされます。thread_code は、
初期化、ランタイム、そして終了という三つの構成要素から成ります。

<!--
In the initialization phase, is the call to pthread_make_periodic_np().
-->
初期化フェーズでは、pthread_make_periodic_np() をコールします。

<verb>
	int pthread_make_periodic_np(pthread_t thread, 
	                             hrtime_t start_time, 
	                             hrtime_t period);
</verb>

<!--
pthread_make_periodic_np marks the <em>thread</em> as ready for execution. 
The thread will start its execution at <em>start_time</em> and will run at 
intervals specified by <em>period</em> given in nanoseconds.
-->
pthread_make_periodic_np は、実行の準備ができたスレッド
<em>thread</em> を指定します。スレッドは <em>start_time</em>
で指定された時間に実行を開始し、ナノ秒単位で指定された
<em>period</em> の間動作します。

<!--
gethrtime returns the time in nanoseconds since the system bootup. 
-->
gethrtime は、システムがブートしてからの時間をナノ秒単位で返します。

<verb>
       hrtime_t gethrtime(void);
</verb>

<!--
This time is never reset or adjusted. gethrtime always gives monotonically 
increasing values. hrtime_t is a 64-bit signed integer.
-->
この時間はリセットされることも修正されることもありません。gethrtime
は常に、単調に増加する値を返します。hrtime_t は64ビットの符号付き整数型です。

<!--
By calling the function pthread_make_periodic_np(), the thread tells the 
scheduler to periodically execute this thread at a frequency of 1 Hz. This marks 
the end of the initialization section for the thread.
-->
pthread_make_periodic_np() 関数をコールすると、
スレッドは自分を 1Hz の頻度で定期的に実行するよう、スケジューラに
命令します。これでスレッドの初期化部は終わります。

<!--
The while() loop begins with a call to the function pthread_wait_np(), which 
suspends execution of the currently running realtime thread until the start of 
the next period. The thread was previously marked for execution using 
pthread_make_periodic_np. Once the thread is called again, it executes the rest of the 
contents inside the while loop, until it encounters another call to
pthread_wait_np().
-->
while() ループは pthread_wait_np() 関数のコールで始まります。
この関数は、次の周期が開始するまで、現在動作しているリアルタイムスレッド
の実行を停止します。このスレッドは前に pthread_make_periodic_np
により実行指定がされています。スレッドが再びコールされると、
pthread_wait_np() があらためてコールされるまで while
ループ内の残りの処理を実行します。

<!--
Because we haven't included any way to exit the loop, this thread will continue 
to execute forever at a rate of 1Hz. The only way to stop the program is by removing 
it from the kernel with the rmmod command. This invokes the cleanup_module(),
which calls pthread_delete_np() to cancel the thread and deallocate its resources.
-->
ループを抜ける手段を入れていないので、このスレッドは 1Hz 間隔で
永久に実行され続けることになります。プログラムを停止する唯一の手段は、
rmmod コマンドによりそれをカーネルから削除することです。
rmmod は cleanup_module() をコールしますが、これが スレッドを中止し、
そのリソースを解放する pthread_delete_np() をコールするのです。

<sect>
<!--
Compiling and Executing 
-->
コンパイルと実行
<p>
<!--
In order to execute the program, hello.c, (after booting rtlinux, ofcourse)  
you must do the following :
-->
hello.c プログラムを実行するには(もちろんですが、rtlinux のブート後にです)、
以下の手順を行わなければなりません:

<enum>
<item>
<!--
Compile the source code and create a module using the GCC compiler.
To simplify things, however, it is better to create a Makefile. Then you only need 
to type 'make' to compile the code.

Makefile can be created by typing in the following lines in a file named 'Makefile'.
-->
GCC コンパイラを使ってソースコードをコンパイルし、モジュールを生成します。
とはいえ、Makefile を作成して作業を簡略化するほうが良いです。
そうすればソースコードをコンパイルするのに 'make'
と入力するだけで済みます。Makefile は、'Makefile'
という名前のファイルに以下の内容を入力することで作成できます。

<verb>
     include rtl.mk
     all: hello.o
     clean:
         rm -f *.o
     hello.o: hello.c
         $(CC) ${INCLUDE} ${CFLAGS} -c hello.c
</verb>

<item>
<!--
Locate and copy the rtl.mk file into the same directory as your hello.c and Makefile. 
The rtl.mk file is an include file which contains 
all the flags needed to compile the code. You can copy it from the RTLinux source 
tree and place it alongside of the hello.c file.
-->
rtl.mk ファイルを見つけ、hello.c や Makefile があるのと同じディレクトリに
置いてください。rtl.mk ファイルは、コードをコンパイルするのに必要な
すべてのフラグを含む include ファイルです。rtl.mk ファイルは
RTLinux のソースツリーからコピーして hello.c ファイルと同じディレクトリ
に格納できます。
<item>
<!--
For compiling the code, use the command 'make'.
-->
コードをコンパイルするには、'make' コマンドを使用してください。

<verb>
	$ make 
</verb>

<item>
<!--
The resulting object binary must be inserted into the kernel, where it will be executed by 
RTLinux. Use the command 'rtlinux' (you need to be the 'root' to do so).
-->
この結果できるオブジェクトバイナリは、カーネルの RTLinux
により実行される部分に組みこまなくてはなりません。'rtlinux'
コマンドを使用してください
(それには 'root' になる必要があります)。

<verb>
	$ rtlinux start hello
</verb>

</enum>




<!--
You should now be able to see your hello.o program printing its message 
every second. Depending on the configuration of your machine, you should 
either be able to see it directly in your console, or by typing:
-->
これで hello.o プログラムがメッセージを毎秒出力するのを確認できるはずです。
マシンの設定によっては、コンソールで直接見ることができるはずですが、
そうでなければ以下のコマンドを入力すれば見ることができます:

<verb>
	$ dmesg
</verb>

<!--
To stop the program, you need to remove it from the kernel. To do so, type:
-->
プログラムを停止するには、これをカーネルから削除する必要があります。
それを行うには、以下のコマンドを入力してください:

<verb>
	$ rtlinux stop hello
</verb>

<!--
Alternate ways for inserting and removing the module is to use <em>insmod</em>
and <em>rmmod</em> respectively.
-->
モジュールの組みこみ、削除を行う別のやり方として、それぞれ
<em>insmod</em> と <em>rmmod</em> を利用するというのもあります。

<p>
<!--
Here, we have made our example program too simple. Contrary to what we have 
seen, there may be multiple threads in a program. Priority can be set at thread
creation or modified later. Also, we can select the scheduling algorithm that 
should be used. In fact, we can write our own scheduling algorithms!
-->
ここまでは例となるプログラムが簡単過ぎました。これまで見てきたものと違い、
実際には一つのプログラム中に複数のスレッドが存在するかもしれません。
優先度をスレッド作成時に設定したり、それを後で修正することが可能です。
また、しかるべきスケジューリングアルゴリズムを選択することも可能です。
実は、独自のスケジューリングアルゴリズムを書くことも可能なんです!

<p>
<!--
In our example, we can set priority of the thread as 1, and select FIFO scheduling
by inserting the following lines in the beginning of the function, thread_code() :
-->
我々の例では、thread_code() 関数の先頭に以下の3行を挿入することで、
スレッドの優先度を1に設定し、FIFO スケジューリングを選択できます。

<verb>
        struct sched_param p;
        p . sched_priority = 1;
        pthread_setschedparam (pthread_self(), SCHED_FIFO, &amp;p);

</verb>
<sect>
<!--
Inter-Process Communication
-->
プロセス間通信
<p>
<!--
The example program that we have seen above is what is known as a realtime process.
Not every part of a application program need be written in realtime. It is found 
that only that part of a program which requires precise time restrictions should 
be written as a realtime process. Others can be written and executed in user space.
User spaces processes are often easier to write, execute and debug than realtime 
threads. But then, there should be a way to communicate between user space Linux
processes and realtime thread.
-->
これまで見てきた例プログラムは、リアルタイムプロセスと呼ばれるものです。
アプリケーションプログラムのすべての部分をリアルタイム用に書く必要は
ありません。プログラムの中でも正確な時間制限を要求される部分だけが
リアルタイムプロセスとして書かれるべきであることが分かります。
それ以外はユーザ空間で実行するように書いてかまいません。
ユーザ空間のプロセスは、多くの場合リアルタイムスレッドよりも作成、実行、
そしてデバッグが容易です。しかしその一方で、ユーザ空間にある Linux
プロセスとリアルタイムスレッドの間で通信を行う手段を用意すべきです。

<p>
<!--
There are several ways for inter-process communication. We will discuss the 
most important and common way of communication - the realtime FIFO.
-->
プロセス間通信を行う手段はいくつかあります。通信を行う最も有力で
一般的な手段であるリアルタイム FIFO について議論します。

<sect1>
<!--
Realtime FIFO
-->
リアルタイム FIFO

<p>
<!--
Realtime FIFOs are unidirectional queues (First In First Out). So at one end a
process writes data into the FIFO, and from the other end of the FIFO, 
information is read by another process. Usually, one of these processes is 
the realtime thread and the other is a user space process. 
-->
リアルタイム FIFO は、一方向のキューです(First In First Out:先入れ先出し)。
つまり一方からプロセスが FIFO にデータを書くと、FIFO
のもう一方から情報が別のプロセスに読みこまれます。通常、
そうしたプロセスの片側がリアルタイムスレッドで、
もう一方がユーザ空間のプロセスになります。

<p>
<!--
The Realtime FIFOs are actually character devices (/dev/rtf*) with a major
number of 150. Realtime threads uses integers to refer to each FIFO (for 
example - 2 for /dev/rtf2). There is a limit to the number of FIFOs. There 
are functions such as rtf_create(), rtf_destroy(), rtf_get(), rtf_put() 
etc for handling the FIFOs.
-->
リアルタイム FIFO は、実際にはメジャーナンバー150のキャラクターデバイス
(/dev/rtf*)です。リアルタイムスレッドは、各 FIFO
を参照するのに整数を用います(例えば /dev/rtf2 なら2)。
FIFO の数には制限があります。FIFO を扱う関数には、rtf_create(),
rtf_destroy(), rtf_get(), rtf_put() などがあります。

<!--
On the other hand, the Linux user process sees the realtime FIFOs as normal
character devices. Therefore the functions such as open(), close(), read() and
write() can be used on these devices. 
-->
一方、Linux のユーザプロセスはリアルタイム FIFO を普通のキャラクターデバイス
とみなします。そのため、open(), close(), read() そして write()
といった関数がこれらのデバイスに対して利用できます。

<sect1>
<!--
Application Using FIFO
-->
FIFO を利用するアプリケーション

<p>
<!--
First, let us consider a simple C program (filename pcaudio.c) to play music 
(of just two tones) through the PC speaker. For the time being, let us assume 
that for playing the note, we need only write to the character device /dev/rtf3. 
(Later, we will see a realtime time process that reads from this FIFO (/dev/rtf3) 
and sends to the PC speaker)
-->
まず PC のスピーカーから(二つの音だけからなる)音楽を演奏する簡単な C
プログラム(ファイル名は pcaudio.c)を考えてみましょう。当面は、
音符を鳴らすにはキャラクターデバイス /dev/rtf3 に書きこむだけで
よいことにしましょう(後で、この FIFO (/dev/rtf3)から読みこみ、
PC のスピーカーに送信するリアルタイム時間プロセスを考えます)。


<verb>
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;

#define DELAY 30000

void make_tone1(int fd)
{
        static char buf = 0;
        write (fd, &amp;buf, 1);
}

void make_tone2(int fd)
{
        static char buf = 0xff;
        write (fd, &amp;buf, 1);
}

main()
{
        int i, fd = open ("/dev/rtf3", O_WRONLY);
        while (1)
        {
                for (i=0;i&lt;DELAY;i++);
                make_tone1(fd);
                for (i=0;i&lt;DELAY;i++);
                make_tone2(fd);
        }
}

</verb>

<!--
Now, if the above shown program (pcaudio.c) is compiled and run, it should create 
regular sound patters corresponding to a square wave. 
But before that we need a module for reading from '/dev/rtf3' and sending the 
corresponding data to the PC speaker. This realtime program can be found 
at the rtlinux source tree (/usr/src/rtlinux/examples/sound/) . Insert the module 
sound.o using the command 'insmod'. 
-->
さて、上に示したプログラム(pcaudio.c)をコンパイルして走らせると、
方形波に相当する規則的な音を生成するはずです。
しかしその前に '/dev/rtf3' から読みこみを行い、対応するデータを PC
のスピーカーに送信するモジュールが必要です。このリアルタイムプログラムは、
rtlinux のソースツリー
(/usr/src/rtlinux/examples/sound/)で見つけられます。'insmod'
コマンドを用いて sound.o モジュールを組みこんでください。

<!--
Since we have inserted a module for reading from the device, we can now execute
our program (compile using 'gcc' and then execute the corresponding 'a.out'. 
So the process produces somewhat regular 
tones, when there is no other (time consuming) process in the system. But,
when the X server is started in another console, there comes more prolonged
silence in the tone. Finally, when a 'find' command (for a file in /usr
directory) is executed, the sound pattern is completely distorted. The 
reason behind this is that, we are writing the data onto the FIFO in 
non-realtime.
-->
デバイスから読みこみを行うモジュールを組みこんだので、
プログラムを実行できるようになりました('gcc' でコンパイルし、
それによってできた 'a.out' を実行してください)。
システム内に他の(時間を消費する)プロセスがない場合は、
プロセスはある程度規則的な音を生成します。しかし、別のコンソールで
X サーバが起動されていると、無音部が長くなります。また 'find'
コマンドを(/usr ディレクトリにあるファイルに対して)実行したりすると、
音像はすっかりゆがんでしまいます。こうなるのは、我々が非リアルタイム的に
FIFO 上にデータを書きこんでいるからです。

<p>
<!--
We will, now, see how to run this process in realtime, so that the sound 
is produced without any kind of 
disturbance. First, we will convert the above program into a realtime program.
(Filename rtaudio.c)
-->
それでは、音が何の障害もなく生成されるように、リアルタイムにこのプロセス
を走らせる方法を考えます。まず上記のプログラムをリアルタイムなプログラム
に変換します(ファイル名は rtaudio.c)。

<verb>
#include &lt;rtl.h>
#include &lt;pthread.h&gt;
#include &lt;rtl_fifo.h&gt;
#include &lt;time.h&gt;

#define FIFO_NO 3
#define DELAY 30000
pthread_t thread;

void * sound_thread(int fd)
{
        int i;
        static char buf = 0;
        while (1)
        {
                for(i=0; i&lt;DELAY; i++);
                buf = 0xff;
                rtf_put(FIFO_NO, &amp;buf, 1);

                for(i=0;i&lt;DELAY;i++);
                buf = 0x0;
                rtf_put(FIFO_NO, &amp;buf, 1);
        }
        return 0;
}

int init_module(void)
{
        return pthread_create(&amp;thread, NULL, sound_thread, NULL);
}

void cleanup_module(void)
{
        pthread_delete_np(thread);
}

</verb>


<p>
<!--
If not already done, 'plug in' the module sound.o into the kernel. Compile
the above program by writing a Makefile for it (as said earlier), 
thus producing the module 'rtaudio.o'. 
Before inserting this module, one more thing. Note that the
above program runs into infinite loop. Since, we have not included code
for the thread to sleep or stop, the thread will not cease its execution. In short,
your PC speaker will go on producing the tone, and you will have to restart
your computer for doing anything else.
-->
まだ行ってないなければ、sound.o モジュールをカーネルの中に「プラグイン」
してください。(前に解説した通りに)それ用の Makefile を書き、
上に示したプログラムをコンパイルして 'rtaudio.o'
モジュールを作成してください。
このモジュールを組みこむ前に、もう一つ行っておくことがあります。
上記のプログラムが無限ループの中を回ることに注意してください。
つまり、スレッドのスリープか停止を行うコードを入れないと、
そのスレッドは実行を止めません。簡単に言えば、PC
のスピーカーは音を鳴らし続け、何か他のことを行うにはコンピュータを
再起動しなくてはならなくなります。

<p>  
<!--
So, let us change the code a little bit (only in the function sound_thread()) 
by asking the thread itself to make the delay between tones.
-->
そこで、スレッド自身が音の間に遅延を入れるように、(sound_thread()
関数の)コードを少しだけ変えてみましょう。

<verb>
void * sound_thread(int fd)
{
        static char buf = 0;
        pthread_make_periodic_np (pthread_self(), gethrtime(), 500000000);

        while (1)
        {
                pthread_wait_np();
                buf = (int)buf^0xff;
                rtf_put(FIFO_NO, &amp;buf, 1);
        }
        return 0;

}
</verb>

<!--
This time we can stop the process by just removing the module by using 
the 'rmmod' command.
-->
今度は、'rmmod' コマンドを用いてモジュールを削除するだけでプロセスを
停止させられます。

<p>
<!--
Here, we have seen how realtime FIFOs can be used for inter-process 
communication. Also the real need for RTLinux can be understood from the
above example.
-->
ここまでリアルタイム FIFO がプロセス間通信でどのように利用できるかを
見てきました。また RTLinux が本当に必要であることが、
上記の例からお分かりいただけたでしょう。

<sect>
<!--
What next
-->
次に行うこと
<p>
<!--
This document has gone through the basics of programming in RTLinux. Once you have 
understood the basic concept it is not difficult to make steps by your
own. So you can go through all other examples available along with the 
rtlinux source. Then you should be 
able to write modules and test them. For more information regarding
module programming, you can refer to 'Linux Kernel Module Programming Guide'
by <em>Ori Pomerantz</em>.
-->
この文書において、RTLinux におけるプログラミングの基礎について一通り
解説しました。一度基本概念を理解してしまえば、自力で先に進むのは難しく
ありません。したがって RTLinux のソースとともに入手できる他のすべての例
プログラムを調べることができるわけです。そうすれば、モジュールを書き、
テストを行うことが可能になるはずです。モジュールのプログラミングに関する
情報がもっと欲しい場合は、<em>Ori Pomerantz</em>
による 'Linux Kernel Module Programming Guide'
を参照するのが良いでしょう。

<!-- 日本語版 -->
<sect>日本語訳について

<p>日本語訳は Linux Japanese FAQ Project が作成しました。
翻訳に関するご意見は JF プロジェクト &lt;JF@linux.or.jp&gt;
または、yomoyomo &lt;ymgrtq@ma.neweb.ne.jp&gt;
宛に連絡してください。

<p>本日本語訳について、誤訳・誤記の指摘をして下さった
つぎの方々に感謝します(50音順)。

<itemize>
<item>中野武雄さん &lt;nakano@apm.seikei.ac.jp&gt;
<item>山口つかささん &lt;tyamagch@bd.mbn.or.jp&gt;
<item>山下義之さん &lt;dica@eurus.dti.ne.jp&gt;
</itemize>

</sect>
<!-- 日本語版 -->
</article>
