c - return 状态/值的适当范围
c - Proper range of return status / value
最近在看一本关于linux编程的书时,收到这样一条信息:
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 become 255
in 2's complement.
以上是关于子进程的退出状态。
我的问题是:
- 为什么父进程只得到子进程退出状态的8位?
- 普通函数的return值呢?仅使用
0 ~ 127
是否合理或有好处?因为有时我确实使用 -1
作为 return 值来指示错误,我是否应该在以后更正它。
更新 - 通过 wait() / waitpid() 获取状态:
我在书(TLPI)中阅读了更多的chps,发现return status & wait()/waitpid()中有更多值得一提的技巧,我应该在询问之前阅读更多的chps这个问题。无论如何,我已经自己添加了一个答案来描述它,以防将来对某人有所帮助。
Why the parent process only get the 8 bits of the child process's exit status?
因为POSIXsays so。 POSIX 这么说是因为原始 Unix 就是这样工作的,许多从它派生并模仿它的操作系统继续工作。
What about return value of normal functions?
他们没有关系。 Return 合理就好。 -1
与任何其他值一样好,实际上是在大量标准 C 和 POSIX API 中指示错误的标准方法。
来自@n.m的回答。很好
不过后来看书chps多了(TLPI),发现return status & wait()/waitpid()里面还有更多值得一提的trick,可能是子进程在退出时不能使用完整的 int 的另一个重要或根本原因。
等待状态
基本上:
- 子进程应该以 1 个字节范围内的值退出,该值设置为 wait() / waitpid() 的状态参数的一部分,
- 并且仅使用状态的 2 LSB 字节,
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
*
剖析return状态:
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;
}
编译:
gcc -Wall wait_status_test.c
执行:
./a.out
并等待它正常终止,在 fork(), 之后打印子进程 id
./a.out
,然后kill -9 <child_process_id>
在它完成休眠之前,
./a.out
,然后kill -STOP <child_process_id>
在它结束睡眠之前,然后kill -CONT <child_process_id>
恢复它,
最近在看一本关于linux编程的书时,收到这样一条信息:
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.
以上是关于子进程的退出状态。
我的问题是:
- 为什么父进程只得到子进程退出状态的8位?
- 普通函数的return值呢?仅使用
0 ~ 127
是否合理或有好处?因为有时我确实使用-1
作为 return 值来指示错误,我是否应该在以后更正它。
更新 - 通过 wait() / waitpid() 获取状态:
我在书(TLPI)中阅读了更多的chps,发现return status & wait()/waitpid()中有更多值得一提的技巧,我应该在询问之前阅读更多的chps这个问题。无论如何,我已经自己添加了一个答案来描述它,以防将来对某人有所帮助。
Why the parent process only get the 8 bits of the child process's exit status?
因为POSIXsays so。 POSIX 这么说是因为原始 Unix 就是这样工作的,许多从它派生并模仿它的操作系统继续工作。
What about return value of normal functions?
他们没有关系。 Return 合理就好。 -1
与任何其他值一样好,实际上是在大量标准 C 和 POSIX API 中指示错误的标准方法。
来自@n.m的回答。很好
不过后来看书chps多了(TLPI),发现return status & wait()/waitpid()里面还有更多值得一提的trick,可能是子进程在退出时不能使用完整的 int 的另一个重要或根本原因。
等待状态
基本上:
- 子进程应该以 1 个字节范围内的值退出,该值设置为 wait() / waitpid() 的状态参数的一部分,
- 并且仅使用状态的 2 LSB 字节,
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 *
剖析return状态:
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;
}
编译:
gcc -Wall wait_status_test.c
执行:
./a.out
并等待它正常终止,在 fork(), 之后打印子进程 id
./a.out
,然后kill -9 <child_process_id>
在它完成休眠之前,./a.out
,然后kill -STOP <child_process_id>
在它结束睡眠之前,然后kill -CONT <child_process_id>
恢复它,