Open3
WasmLinux: vfork → execveの実装(未遂)
というわけで山場だ。。 "v"fork → execve の流れを実装する。vforkとexecveでスクラップ分けた方が良いかな。。
vforkはforkの厳密なサブセットで、NOMMUなシステムでは唯一のfork(2)風機構となっている。ただマジでNOMMU耐性を考えるなら posix_spawnを使った方が良い。vforkの制約は通常の人間には非常に理解しづらい。
テストプログラム
適当に書く。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int
main(int ac, char** av, char** envp){
pid_t pid;
int i,r;
const char* next[] = {"dummy", "u", "m", 0};
/* Dump args */
i = 0;
while(av[i]){
fprintf(stderr, "[%d/%d]: %s\n", i, ac, av[i]);
i++;
}
if(ac >= 2 && av[1][0] == 'u'){
printf("execve-ed. my pid is %d\n", getpid());
return 0;
}else{
pid = vfork();
if(! pid){
/* child process */
printf("Going to execve()...(I'm %d)\n", getpid());
r = execve(av[0], next, NULL);
printf("Should not reach here %d,%d\n", r, errno);
}else{
/* parent process */
printf("Forked to %d\n", pid);
return 0;
}
}
return 0;
}
無限再帰しないように適当に引数を渡すようにする。実行すると:
$ ./a.exe
[0/1]: ./a
Forked to 1858
Going to execve()...(I'm 1858)
[0/3]: dummy
[1/3]: u
[2/3]: m
execve-ed. my pid is 1858
のような感じに出力される。
さくせん
setjmp
longjmp
で実装する。
-
vfork
が呼ばれる -
setjmp
する - 新規プロセスコンテキストを作成し、カレントスレッドのコンテキストを差し替え
- 一旦ゼロを返して
execve
されるまで実行する ★ ← コレがダメ -
evecve
が呼び出されたら、新規ホストスレッドを生成し、3.で作成したコンテキストはそちらで使うようにし、カレントスレッドのコンテキストを元に戻す -
longjmp
(新規プロセスのPID) する -
setjmp
の戻り値を戻して実行継続する
残念ながらコレはC++例外では実装できず、C標準のsetjmp/longjmpが必要になる。
これダメじゃん。。 setjmp
を呼出した関数から 戻ってはいけない 。vforkにも同じ制約があるが vfork → setjmp をマクロにしないといけない。
いやまぁもちろんAsyncifyすれば良いだけだけど、このためだけにパフォーマンスペナルティ払うのもちょっとなぁ。。