wait()
またはを使用するwaitpid()
Unixおよび派生物では、wait()
およびのようなPOSIX関数を使用することはできませんwaitpid()
。返される終了ステータス情報は、2つの8ビットフィールドで構成されます。1つは終了ステータスを含み、もう1つは死因に関する情報を含みます(0はプログラム制御下での正常な終了を意味し、他の値はシグナルがそれを強制終了したことを示し、コアがダンプされました)。
で使用sigaction()
するSA_SIGINFO
一生懸命働いて、sigaction()
and<signal.h>
とSignal Actionsexit()
のPOSIX仕様を読むと、子プロセスから渡された32ビット値を取得できることがわかります。ただし、それは完全に単純ではありません。
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
static siginfo_t sig_info = { 0 };
static volatile sig_atomic_t sig_num = 0;
static void *sig_ctxt = 0;
static void catcher(int signum, siginfo_t *info, void *vp)
{
sig_num = signum;
sig_info = *info;
sig_ctxt = vp;
}
static void set_handler(int signum)
{
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = catcher;
sigemptyset(&sa.sa_mask);
if (sigaction(signum, &sa, 0) != 0)
{
int errnum = errno;
fprintf(stderr, "Failed to set signal handler (%d: %s)\n", errnum, strerror(errnum));
exit(1);
}
}
static void prt_interrupt(FILE *fp)
{
if (sig_num != 0)
{
fprintf(fp, "Signal %d from PID %d (status 0x%.8X; UID %d)\n",
sig_info.si_signo, (int)sig_info.si_pid, sig_info.si_status,
(int)sig_info.si_uid);
sig_num = 0;
}
}
static void five_kids(void)
{
const int base = 0xCC00FF40;
for (int i = 0; i < 5; i++)
{
pid_t pid = fork();
if (pid < 0)
break;
else if (pid == 0)
{
printf("PID %d - exiting with status %d (0x%.8X)\n",
(int)getpid(), base + i, base + i);
exit(base + i);
}
else
{
int status = 0;
pid_t corpse = wait(&status);
if (corpse != -1)
printf("Child: %d; Corpse: %d; Status = 0x%.4X - waited\n", pid, corpse, (status & 0xFFFF));
struct timespec nap = { .tv_sec = 0, .tv_nsec = 1000000 }; // 1 millisecond
nanosleep(&nap, 0);
prt_interrupt(stdout);
fflush(0);
}
}
}
int main(void)
{
set_handler(SIGCHLD);
five_kids();
}
sigexit73
(からコンパイルされたプログラムsigexit73.c
)を実行すると、次のような出力が生成されます。
$ sigexit73
PID 26599 - exiting with status -872349888 (0xCC00FF40)
Signal 20 from PID 26599 (status 0xCC00FF40; UID 501)
Child: 26600; Corpse: 26599; Status = 0x4000 - waited
PID 26600 - exiting with status -872349887 (0xCC00FF41)
Signal 20 from PID 26600 (status 0xCC00FF41; UID 501)
Child: 26601; Corpse: 26600; Status = 0x4100 - waited
PID 26601 - exiting with status -872349886 (0xCC00FF42)
Signal 20 from PID 26601 (status 0xCC00FF42; UID 501)
Child: 26602; Corpse: 26601; Status = 0x4200 - waited
PID 26602 - exiting with status -872349885 (0xCC00FF43)
Signal 20 from PID 26602 (status 0xCC00FF43; UID 501)
Child: 26603; Corpse: 26602; Status = 0x4300 - waited
PID 26603 - exiting with status -872349884 (0xCC00FF44)
Signal 20 from PID 26603 (status 0xCC00FF44; UID 501)
$
1ミリ秒の呼び出しをnanosleep()
削除すると、出力は次のようになりがちです。
$ sigexit73
sigexit23
PID 26621 - exiting with status -872349888 (0xCC00FF40)
Signal 20 from PID 26621 (status 0xCC00FF40; UID 501)
Child: 26622; Corpse: 26621; Status = 0x4000 - waited
PID 26622 - exiting with status -872349887 (0xCC00FF41)
PID 26623 - exiting with status -872349886 (0xCC00FF42)
Signal 20 from PID 26622 (status 0xCC00FF41; UID 501)
Child: 26624; Corpse: 26623; Status = 0x4200 - waited
Signal 20 from PID 26623 (status 0xCC00FF42; UID 501)
Child: 26625; Corpse: 26622; Status = 0x4100 - waited
PID 26624 - exiting with status -872349885 (0xCC00FF43)
PID 26625 - exiting with status -872349884 (0xCC00FF44)
$
ここから始まる行は3行だけであり、 ;Signal
で終わる行も3行しかないことに注意してください。waited
一部のシグナルと終了ステータスが失われます。SIGCHLD
これは、親プロセスに設定されているシグナル間のタイミングの問題が原因である可能性があります。
ただし、重要な点はexit()
、コードがステータスを追跡するためsigaction()
にSIGCHLD
、を使用する場合、ステータスで4バイトのデータを送信できることです。SA_SIGINFO
念のため、テストは、GCC9.2.0とXCode11.3.1を使用して、macOSMojave10.14.6を実行しているMacBookProで実行されました。このコードは、GitHubのSOQsigexit73.c
(Stack Overflow Questions)リポジトリでも、src/so-1843-7779サブディレクトリのファイルとして入手できます。