ソフト・マクロのCPUでLinuxを動かす(後編) ──OSの実装とネットワーク対応機器への応用
●○● Column ●○●
◆uCLinux用アプリケーション・ソフトウェア開発時の注意点◆
uCLinuxで動作するソフトウェアの開発では,一般のLinux向けソフトウェアと比べて注意しなければならないいくつかのポイントがあるので,ここで説明します.
なお,OSアーキテクチャそのものに密接に関係する技術に基づく部分であるため,実際にソフトウェア開発を行っていない方々には耳慣れない用語もあり,難しい内容になってしまうことをご了承ください.逆にいうと,以下に挙げる点を除けば,uCLinuxといえど普通のLinuxとほとんど変わらない知識・技術でソフトウェア開発が可能であるといえます.ベースとなる技術の詳細について知りたい場合は専門の書籍などが多数出版されているので,それらを参照してください.
● forkシステム・コールの制限
LinuxのプログラマがuCLinuxでプログラムを書こうとしてとまどう部分として,新しいプロセスを生成するためのforkシステム・コールを使用できない点が挙げられます.中には「forkが使えないならマルチタスクを実行できない」と言い切る人もいるほどで,この点が必要以上にuCLinuxの評判を落とすことになった原因であると思います.確かに現在のuCLinuxでは forkが実装されていません.まずは,この理由について正確に知る必要があります.
簡単な答えは,「Linuxのforkシステム・コールの実装には,copy-on-writeが使われているから」です.copy-on-writeとは,あるオブジェクト(forkにおいては,広い意味でプロセス実体そのもの)への書き込みが行われるまで,そのオブジェクトを読み込み専用にして効率的に共有する技術です.
OSの世界ではMMUのメモリ保護機能を使ってデータ(多くの場合ページ単位)を読み込み専用にしておき,書き込みが発生したときにメモリ保護違反の例外を意図的に起こします.この例外をカーネルが検知し,例外対象のデータを書き込み用にコピーします.このようにMMUをベースにしたcopy-on-writeをforkの実装に使用しているため,MMUを使わないuCLinuxではそのままforkを実装できません.もちろんcopy-on-writeを用いないforkも可能ですが,uCLinuxでは実装されていません.
しかし,uCLinuxでは子プロセスを生成できないというわけではありません.では,uCLinuxではどのようにして子プロセスの生成を行うかというと,vforkシステム・コールを使います.vforkも子プロセスの生成に使用するシステム・コールです.forkとの大きな違いは,以下の2点です.
- 親プロセスは,子プロセスがexecveまたは_exitシステム・コールを呼ぶでまで停止(suspend)する.
- 子プロセスは,スタックも含めたすべてのメモリを親プロセスと共有する.
具体的には,子プロセス内ではvforkの戻り値以外の変数を変更できなかったり,ほかの関数を呼べなかったりします.また,現在の関数からのreturnやexitができないといった細かな違いもあるので,forkからの置き換えを考える場合には注意が必要です.
● スタックの大きさについて
MicroBlaze版のuCLinuxでは,ほかのuCLinuxのアーキテクチャと同じくFlatBinary Formatと呼ばれる実行ファイル用のフォーマットを採用しています.
このバイナリ・フォーマットの特徴は,一般的なELFフォーマットよりもシンプルかつ軽量であること,スタック・サイズがコンパイル時に固定長で指定されること,圧縮に対応していること,そしてXIP(eXecute in Place)に対応していることといった点です.
MMUを持っているアーキテクチャでは,デマンド・ページングを使ってスタック用のメモリが動的に割り当てられるため,スタックの大きさを気にしながらプログラムを書くケースはあまりないと思います.一方,uCLinux上でプログラムを記述する場合や,既存のアプリケーションをuCLinuxに移植する場合などについては,留意する必要があります.
C言語による開発の場合,スタック領域は関数中の自動変数(auto変数,staticやregisterといった特別な記憶クラス指定子を付けない通常の変数のこと)に使用されるため,大きな変数を宣言している既存のアプリケーションを移植する場合などには,コンパイル時に十分なスタック・サイズを指定するか,ソース・コード自体を書き換えて変数自体をスタック領域とは別の領域に移動しなくてはならない場合があります.