uClinuxは、MMUを持たないCPUをサポートしているLinuxカーネルです。uClinuxはMMUを持たないことで
- ページングによるメモリ保護が無い
- アプリケーションから他のプロセスやカーネルのメモリ空間を壊すことができる
- fork()が使えない
- 代りにvforkを使う
- 共有ライブラリが使えない
- スワップが使えない
- プログラムを全てメモリにコピーする必要がある
- busyboxのように一部しか使わないプログラムでも、全部ロード
など、制限があります。
(SUSv2 / POSIX ドラフトより引用) vfork() 関数は fork(2) と同じ働きをするが、 vfork() で作成されたプロセスが vfork() からの返り値を格納している pid_t 型の変数以外を変更したり、 vfork() を呼び出している関数から return したり、 _exit(2) や exec(3) 族の関数をコールする前に他の関数をコールした場合の動作が未定義であるという点が異なる。 と記載されています。 例えばというコードがあったとしましょう。Linuxであれば、子プロセスと親プロセスのプロセス空間は別ですので、13行目の1 #include <unistd.h> 2 #include <stdlib.h> 3 #include <stdio.h> 4 5 int main() 6 { 7 int a = 0; 8 pid_t ret; 9 10 ret = vfork(); 11 if (ret == 0) { 12 /* chlid */ 13 a = 1; 14 _exit(1); 15 } 16 else if (ret < 0) 17 /* error */ 18 exit(-1); 19 20 /* parent */ 21 printf("a = %d\n", a); 22 return 0; 23 }
13 a = 1;
は、親プロセスには影響がありません。しかしvfork()の場合は、動作保証されていません。
vfork()を使って子プロセスを生成するときは、vfork()の直後にexec()を実行するようにしてください。
### 親プロセスはスケジュールされず停止する
vfork()では子プロセスが
- _exit()
- exec()
を呼ぶまで親プロセスの実行が停止されます。つまり、子プロセスでblockしてしまうとdeadlockする可能性があります。
fork()を使った例で良く見るのが、pipeによる親との通信です。vfork()の場合これが問題になります。pipeにデータが無い状態で vfork()し、子プロセスがpipeからデータを読みだそうとしてblockします。forkであればこの時点で親プロセスがスケジュールされ pipeにデータを書き出すことができますが、vforkで生成された場合は親プロセスがスケジュールされないため、deadlockになります。
-->