0

Let's suppose that I wrote the following in main:

int main() {
    int status;
    if ((p1 = fork()) != 0) {
        if ((p2 = fork()) != 0) {
            wait(&status);
            wait(&status);
        } else {
            processB();
        }
    }
    return 3;
}

plus:

int processB() {
    return 1;
}

when process p2 ends, what will be the value it saves in &status?

If it ended using exit(100) for example then it will return 100, but I don't know what will happen in this case?

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    `} }} ` missing `return` in `main` means `main` returns `0`. – KamilCuk Apr 14 '21 at 15:22
  • Fixed, thanks for pointing this to me –  Apr 14 '21 at 15:32
  • Why don't you print `status` after each `wait()` call? – Barmar Apr 14 '21 at 15:40
  • @Barmar did and didn't understand where it came from –  Apr 14 '21 at 15:48
  • So your question isn't what will be the value, but *why* will it be that value. – Barmar Apr 14 '21 at 15:50
  • 1
    Your code has a race condition. There is no guarantee of which child process will exit first so your two wait calls could put either p1 or p2's exit status into `status`. The return value of each wait call will be the process ID, so you could match it against either p1 or p2 to see which one you got, if that was important to you. – Zan Lynx Apr 15 '21 at 02:40

1 Answers1

3

The exit status from the process is encoded in 16 bits. The high-order 8 bits contain the return value from main() or the value passed to exit() (or one of its relatives); the low-order 8 bits contain the signal that killed the process and a flag indicating that a core dump was created. The low order bits are zero if the process exited normally. The return value from wait() is the PID of the dead process.

Use code similar to this to print out the information in a semi-legible format:

int corpse;
int status;
while ((corpse = wait(&status)) > 0)
    printf("PID %5d exited with status 0x%.4X\n", corpse, status);

If your program has return 3; at the end of main(), then the value reported via the status pointer to wait() will be 0x0300 (768 = 3 * 256). If your program calls exit(100);, the value returned by wait() will be 0x6400 (100 = 6 * 16 + 4). If your program is killed by an interrupt (SIGINT, 2), the value returned by wait() will be 0x0002. (Technically, the actual values are system-dependent, but this is historically accurate and I know of no system where this is not what happens.)

See also ExitCodes bigger than 255 — Possible?.

POSIX defines the <sys/wait.h> header with a bunch of relevant macros, such as:

  • WIFEXITED
  • WEXITSTATUS
  • WIFSIGNALED
  • WTERMSIG
  • WIFSTOPPED
  • WSTOPSIG

And implementations often define a macro to detect core dumps — usually WCOREDUMP.

See also the POSIX specification for wait() (which also specifies waitpid()).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • so it's 3 in my case? –  Apr 14 '21 at 15:31
  • But here it return 768... https://onlinegdb.com/H19ZiKVId (full code) –  Apr 14 '21 at 15:32
  • Got that, If I was told if a process gets signal x it ends with x+128, will this affect the answer? –  Apr 14 '21 at 15:48
  • That's an artefact of the shell. When the shell gets a 'child died from a signal' status, it converts the value returned by `wait()`, which might be 0x0006 (for SIGABRT), into 128 + 6 = 134, and records that in `$?`. The `wait()` function does not do that. (See POSIX shell specification on [Exit Status and Errors](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08) for more information.) – Jonathan Leffler Apr 14 '21 at 15:49
  • Other related questions include: [Return code for POSIX signals that cannot be handled](https://stackoverflow.com/q/13410661/15168) — [Reporting which signal terminated a child](https://stackoverflow.com/q/50299429/15168) — [Why is the `fork()` value `-1` and why is the `wait()` exit status not 0?](https://stackoverflow.com/q/28257681/15168) — [Unsure how to find out whether the child process is terminated by completion or via a signal](https://stackoverflow.com/q/52886449/15168). – Jonathan Leffler Apr 14 '21 at 16:06
  • @JonathanLeffler I made more research and not sure about your answer, from what I read processB ends in exit(main) since main returns 3 then processB returns 128+3=131 –  Apr 14 '21 at 18:15
  • Your professor is wrong. The value is returned from the function but ignored by the calling code. If `return 1;` was in `main()`, not the function, then the exit status would be 1. If the code in the function was `exit(1);`, then the exit status would be 1. If the code in `nain()` was either `return processB();` or `exit(processB());`, then the exit status would be 1. As written, the exit status will be 3. – Jonathan Leffler Apr 14 '21 at 18:19
  • Plus, in case a process called kill what will be stored in the higher 8 bits? you said: "The high-order 8 bits contain the return value from main() or the value passed to exit()" but there is no main or exit in this case... –  Apr 14 '21 at 18:24
  • The upper bits are zero if a signal is received, but that's also true if the process exited normally with a success status. – Jonathan Leffler Apr 14 '21 at 18:35
  • So upper and lower are 0 which means total result is 0... a contradiction to what you wrote –  Apr 14 '21 at 18:55
  • No. I said the signal number (and the core dump bit) would be stored in the lower 8 bits. If there is no signal, then the lower 8 bits are all zero. If there is a signal, the upper 8 bits are all zero. However, testing for the upper 8 bits all being zero doesn't prove that the child died from a signal; it could have exited successfully (with `exit(0);` or an explicit or implicit `return 0;` from `main()`). If the child died from a signal (there is no signal 0, even though you can pass 0 to `kill()` to test if you could signal the PID), then the lower 8 bits are non-zero. – Jonathan Leffler Apr 14 '21 at 18:58
  • And remember that the 128+x part of things is what the shell does, not what the operating system kernel does. The shell is not the kernel. And what you have as `processB()` is not a separate program; it is a function in the same program as all the other code — albeit called from one of the children of the original process. (Be aware of the difference between 'program' and 'process'.) – Jonathan Leffler Apr 14 '21 at 19:01
  • Debugging multi-process programs like this is easier if you add printing statements that identify the PID of the process as well as the other information to be printed. For example, before `return 3;` in `main()`, you might add `fprintf(stderr, "%5d: return from main with value 3\n", (int)getpid());` (or you can print to `stdout` if you prefer, but in general, it's best to call `fflush(stdout)` after diagnostic printing. Don't save the value from `getpid()` in a variable for printing; you need to be sure you print the current PID. – Jonathan Leffler Apr 14 '21 at 19:09
  • 1
    768 (decimal) is x0300 (hexadecimal). As described above the high order 8 bits, i.e. 0x03, have the return value. The low order 8 bits are 0x00, since the process ended voluntarily, i.e. it was not killed. (Deleted original comment because of serious typo: I had written *... 16 bits ...* instead of *... 8 bits ...*) – phunsoft Apr 14 '21 at 20:39