Recently, when reading a book about linux programming, I got a message that:
The status argument given to _exit() defines the termination status of the process, which is available to the parent of this process when it calls wait(). Although defined as an int, only the bottom 8 bits of status are actually made available to the parent. And only
0 ~ 127
is recommanded to use, because 128 ~ 255 could be confusing in shell due to some reason. Due to that-1
will become255
in 2's complement.
The above is about the exit status of a child process.
My question is:
0 ~ 127
? Because I do use -1
as return value to indicate error sometimes, should I correct that in future.Update - status get by wait() / waitpid():
I read more chps in the book (TLPI), and found there are more trick in the return status & wait()/waitpid() that worth mention, I should have read more chps before ask the question. Anyhow, I have add an answer by myself to describe about it, in case it might help someone in future.
A return statement ends the execution of a function, and returns control to the calling function. Execution resumes in the calling function at the point immediately following the call. A return statement can return a value to the calling function.
The return value is stored in registers - on x64 it goes in RAX. On x86, 64-bit structures like DateTime are returned in EAX:EDX.
If a function is defined as having a return type of void , it should not return a value. In C++, a function which is defined as having a return type of void , or is a constructor or destructor, must not return a value. If a function is defined as having a return type other than void , it should return a value.
Every command returns an exit status (sometimes referred to as a return status or exit code). A successful command returns a 0, while an unsuccessful one returns a non-zero value that usually can be interpreted as an error code.
Why the parent process only get the 8 bits of the child process's exit status?
Because POSIX says so. And POSIX says so because that's how original Unix worked, and many operating system derived from it and modeled after it continue to work.
What about return value of normal functions?
They are unrelated. Return whatever is reasonable. -1
is as good as any other value, and is in fact a standard way to indicate an error in a huge lot of standard C and POSIX APIs.
The answer from @n.m. is good.
But later on, I read more chps in the book (TLPI), and found there are more trick in the return status & wait()/waitpid() that worth mention, and that might be another important or root reason why child process can't use full bits of int when exit.
basicly:
byte usage of status:
event byte 1 byte 0 ============================================================ * normal termination exit status (0 ~ 255) 0 * killed by signal 0 termination signal (!=0) * stopped by signal stop signal 0x7F * continued by signal 0xFFFF *
dissect returned status:
header 'sys/wait.h', defines a set of macros that help to dissect a wait status, macros: * WIFEXITED(status) return true if child process exit normally, * * WIFSIGNALED(status) return true if child process killed by signal, * WTERMSIG(status) return signal number that terminate the process, * WCOREDUMP(status) returns ture if child process produced a core dump file, tip: this macro is not in SUSv3, might absent on some system, thus better check whether it exists first, via: #ifdef WCOREDUMP // ... #endif * * WIFSTOPPED(status) return true if child process stopped by signal, * WSTOPSIG(status) return signal number that stopp the process, * * WIFCONTINUED(status) return true if child process resumed by signal SIGCONT, tip: this macro is part of SUSv3, but some old linux or some unix might didn't impl it, thus better check whether it exists first, via: #ifdef WIFCONTINUED // ... #endif *
wait_status_test.c
// dissect status returned by wait()/waitpid()
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#define SLEEP_SEC 10 // sleep seconds of child process,
int wait_status_test() {
pid_t cpid;
// create child process,
switch(cpid=fork()) {
case -1: // failed
printf("error while fork()\n");
exit(errno);
case 0: // success, child process goes here
sleep(SLEEP_SEC);
printf("child [%d], going to exit\n",(int)getpid());
_exit(EXIT_SUCCESS);
break;
default: // success, parent process goes here
printf("parent [%d], child created [%d]\n", (int)getpid(), (int)cpid);
break;
}
// wait child to terminate
int status;
int wait_flag = WUNTRACED | WCONTINUED;
while(1) {
if((cpid = waitpid(-1, &status, wait_flag)) == -1) {
if(errno == ECHILD) {
printf("no more child\n");
exit(EXIT_SUCCESS);
} else {
printf("error while wait()\n");
exit(-1);
}
}
// disset status
printf("parent [%d], child [%d] ", (int)getpid(), (int)cpid);
if(WIFEXITED(status)) { // exit normal
printf("exit normally with [%d]\n", status);
} else if(WIFSIGNALED(status)) { // killed by signal
char *dumpinfo = "unknow";
#ifdef WCOREDUMP
dumpinfo = WCOREDUMP(status)?"true":"false";
#endif
printf("killed by signal [%d], has dump [%s]\n", WTERMSIG(status), dumpinfo);
} else if(WIFSTOPPED(status)) { // stopped by signal
printf("stopped by signal [%d]\n", WSTOPSIG(status));
#ifdef WIFCONTINUED
} else if(WIFCONTINUED(status)) { // continued by signal
printf("continued by signal SIGCONT\n", WSTOPSIG(status));
#endif
} else { // this should never happen
printf("unknow event\n");
}
}
return 0;
}
int main(int argc, char *argv[]) {
wait_status_test();
return 0;
}
Compile:
gcc -Wall wait_status_test.c
Execute:
./a.out
and wait it to terminate normally, child process id is printed after fork(),./a.out
, then kill -9 <child_process_id>
before it finish sleep,./a.out
, then kill -STOP <child_process_id>
before it finish sleep, then kill -CONT <child_process_id>
to resume it,If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With