プロセス起動 - ToguchiYuto/linuxsystemprogram GitHub Wiki
- バイナリをメモリへロードし、そのアドレス空間に存在した内容を置き換えて、指定されたプログラムを実行するためのシステムコール
- プロセスを新規作成し、親プロセスをもとに子プロセスを複製するためのシステムコール
- forkを実行し、プロセスのコピーを作成したあと、execを実行し、アドレス空間を書き換えてプログラムを実行するのが一般的な利用方法
- forkの戻り値は子プロセスのプロセスIDになる。子プロセスでforkを実行すると戻り値は0になる。
execlは引数を渡すことができる。 以下のプログラムを実行すると実行時に読み込まれたプログラムを/bin/lsで上書きする。 そのため、execlが正常に完了するとexeclより下に記載されたプログラムは実行されない。 そのため、forkを実行したあと、execlを実行し、子プロセスで処理を実行したあと、親プロセスの処理を動作させるという利用方法を実施する。 execlは既存のプロセスIDは変更しないのでそのまま利用される。
#include <unistd.h>
#include <stdio.h>
void main(){
int ret;
ret = execl("/bin/ls", "ls", "/home/debug/linux_system_program/workdir", NULL);
if(ret == -1){
perror("execl error");
}
printf("check\n");
}
以下の実行結果からもprintfが実行されていないことがわかる。
[debug@localhost linux_system_program]$ ./a.out
test.out
[debug@localhost linux_system_program]$
forkを実行するとforkを実行したプロセスのコピーを子プロセスとして作成する。 作成された子プロセスは、forkが実行された場所から処理が実行される。 以下のプログラムの結果を確認するとStart Processが一度だけ表示されていることから子プロセスではStart Processを表示するprintfは実行されていないことがわかる。 forkを実行した親プロセスでは、forkの戻り値として子プロセスのPIDが返される。 子プロセスでは、0が戻り値として返される。 そのため、forkを実行した後の処理では、親プロセスで実施する処理と子プロセスで実施する処理を分けて記述する必要がある。 親プロセスでprintfが実行され、PID by fork 19584 in Parent Processが表示される。 このPIDは子プロセスのPIDになる。 forkによって生成された子プロセスは、forkに戻り値が返されるところから処理が実施され、PID by fork 0 in Child Processが表示される。 子プロセスでは、execlが実行され、lsが実行される。execlが正常に完了するとプログラムが書き換わるため、execl以降に記載された内容は実行されません。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
void main(){
printf("Start Process\n");
int ret;
pid_t pid;
pid = fork();
if (pid == -1){
perror("error fork");
}
if(pid){
printf("PID by fork %d in Parent Process\n",pid);
}
if(!pid){
printf("PID by fork %d in Child Process\n",pid);
sleep(1000);
ret = execl("/bin/ls", "ls", "/home/debug/linux_system_program/workdir", NULL);
if(ret == -1){
perror("execl error");
}
}
sleep(5);
}
[debug@localhost linux_system_program]$ ./a.out
Start Process
PID by fork 19584 in Parent Process
PID by fork 0 in Child Process
test.out
[debug@localhost linux_system_program]$
以下の結果から親プロセスであるa.outのPIDは19583であり、19583からforkが実行されたことで19584が生成されていることがわかる。 19584では、execlが実行され、a.outがlsに書き換えられ、lsが実行される。
systemd(1)─┬─NetworkManager(858)─┬─dhclient(1080)
│ ├─{NetworkManager}(865)
│ └─{NetworkManager}(868)
...
├─sshd(1293)─┬─sshd(1759)───sshd(1765)─┬─bash(1766)───a.out(19583)───ls(19584)
│ │ └─bash(19646)───sleep(20304)