c - 适当的返回状态/值范围

时间:2015-08-31 15:26:58

标签: c process fork return-value

最近,在阅读有关linux编程的书时,我收到了一条消息:

  

给_exit()的status参数定义了进程的终止状态,当调用wait()时,该进程的父进程可以使用该进程。虽然定义为int,但实际上只有父8的状态的底部8位可用。并且仅建议使用0 ~ 127,因为由于某种原因,128~255可能在shell中混淆。由于-1将在2的补码中成为255

以上是关于子进程的退出状态。

我的问题是:

  • 为什么父进程只获取子进程退出状态的8位?
  • 正常功能的返回值怎么样?仅使用0 ~ 127是否合理或可行?因为我确实使用-1作为返回值来指示错误,所以我今后应该更正。

更新 - 状态由wait()/ waitpid()获取:

我在书中读到了更多的chps(TLPI),并发现在返回状态中有更多技巧。 wait()/ waitpid()值得一提,我应该在提出问题之前阅读更多的chps。无论如何,我自己添加一个答案来描述它,以防将来可能对某人有所帮助。

2 个答案:

答案 0 :(得分:4)

  

为什么父进程只获得子进程的8位退出状态?

因为POSIX says so。 POSIX之所以如此,是因为原始Unix的工作方式,以及许多操作系统都是从它衍生出来的,并在它继续工作之后建模。

  

正常功能的返回值怎么样?

他们是无关的。返回任何合理的东西。 -1与任何其他值一样好,实际上是在大量标准C和POSIX API中指示错误的标准方法。

答案 1 :(得分:1)

来自@n.m的回答。很好。

但是后来,我在书中读到了更多的chps(TLPI),并发现在返回状态中还有更多技巧。 wait()/ waitpid()值得一提,这可能是为什么子进程在退出时不能使用完整位的另一个重要或根本原因。

等待状态

basicly:

  • 子进程应该以1字节范围内的值退出,该字节被设置为wait()/ waitpid()的状态参数的一部分,
  • 并且只使用状态的2个LSB字节,

状态的字节使用情况:

    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
    * 

剖析返回状态:

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>恢复它,
相关问题