使用方法 wait()
o waitpid()
Unter Unix und Derivaten ist es nicht möglich, mit POSIX-Funktionen wie wait()
y waitpid()
. Die zurückgegebene Exit-Status-Information besteht aus zwei 8-Bit-Feldern, von denen eines den Exit-Status und das andere Informationen über die Todesursache enthält (0 bedeutet, dass das Programm ordnungsgemäß unter Programmkontrolle beendet wurde, andere Werte zeigen an, dass es durch ein Signal beendet wurde, und geben an, ob ein Kern ausrangiert wurde).
使用方法 sigaction()
con SA_SIGINFO
Wenn Sie hart arbeiten und die POSIX-Spezifikation von sigaction()
y <signal.h>
y Signal-Aktionen werden Sie feststellen, dass Sie den 32-Bit-Wert, der an exit()
durch einen Kindprozess. Dies ist jedoch nicht ganz einfach.
#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();
}
Bei der Ausführung (Programm sigexit73
zusammengestellt von sigexit73.c
), ergibt dies eine Ausgabe wie:
$ 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)
$
Mit dem eine Millisekunde dauernden Aufruf von nanosleep()
entfernt wird, kann die Ausgabe wie folgt aussehen:
$ 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)
$
Beachten Sie, dass es nur drei Zeilen gibt, die mit Signal
hier, und auch nur drei Zeilen mit der Endung waited
Einige der Signale und Ausstiegsstatus sind verloren gegangen. Dies liegt wahrscheinlich an Zeitproblemen zwischen dem SIGCHLD
Signale, die an den übergeordneten Prozess gesendet werden.
Der springende Punkt ist jedoch, dass 4 Byte Daten in der exit()
Status, wenn der Code mit sigaction()
, SIGCHLD
, SA_SIGINFO
um den Status zu verfolgen.
Nur für das Protokoll, die Tests wurden auf einem MacBook Pro mit macOS Mojave 10.14.6 durchgeführt, mit GCC 9.2.0 und XCode 11.3.1. Der Code ist auch verfügbar in meinem SOQ (Stack Overflow Questions) Repository auf GitHub als Datei sigexit73.c
im src/so-1843-7779 Unterverzeichnis.
2 Stimmen
Diese doppelte Frage hat eine viel bessere (aber nicht akzeptierte) Antwort .
0 Stimmen
Dies liegt daran, dass eine vorzeichenlose kurze Ganzzahl (8 Bit) zurückgegeben wird. 0000000 = 0 11111111 = 255