How to get the full returned value of a child process?
Asked Answered
M

3

6

I need to catch the returned value of a child process..

The problem is: with using the waitpid() function I can catch only 8 bits of the returned value

WEXITSTATUS(wstatus) returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main(). This macro should be employed only if WIFEXITED returned true.

How can I catch the full int value that is returned from main() ?

EDIT: Stackoverflow forced me to edit the question as it linked another answered question but it has nothing to do with mine!

Manhattan answered 22/6, 2018 at 7:23 Comment(0)
Z
7

The waitid function allows you to retrieve the full (int) exit status of a process, as part of the siginfo_t structure that it fills out.

POSIX also requires that the full exit value be passed in the si_status member of the siginfo_t structure passed to the SIGCHLD handler, if it is appropriately established via a call to sigaction with SA_SIGINFO specified in the flags:

If si_code is equal to CLD_EXITED, then si_status holds the exit value of the process; otherwise, it is equal to the signal that caused the process to change state. The exit value in si_status shall be equal to the full exit value (that is, the value passed to _exit(), _Exit(), or exit(), or returned from main()); it shall not be limited to the least significant eight bits of the value.

(Emphasis mine).

Note that upon testing, it appears that Linux does not honour this requirement and returns only the lower 8 bits of the exit code in the si_status member. Other operating systems may correctly return the full status; FreeBSD does. See test program here.

Be wary, though, that is not completely clear that you will receive an individual SIGCHLD signal for every child process termination (multiple pending instances of a signal can be merged), so this technique is not completely infallible. It is probably better to find another way to communicate a value between processes if you need more than 8 bits.

Zaremski answered 22/6, 2018 at 13:52 Comment(1)
Exit codes bigger than 255 — possible? shows a similar example tested on macOS.Renfro
F
6

The short answer is that you pretty much can't. Traditionally, the exit status of a process under Unix/Linux is propagated as an 8-bit value. You can return any integer from main that you like, you can call exit with any integer that you like, but only the low-order 8 bits are available to the parent via any of the wait functions.

The reason WEXITSTATUSis documented as returning only the low-order 8 bits of the status is that those are the only bits that there are.

If you're trying to pass arbitrary data from a subprocess back to its parent, the exit status is not the way to do it. Me, I normally print data to the standard output, and have the caller capture it using popen or the equivalent.


Addendum: I thought the kernel didn't even record the full int-sized exit status, and that it was therefore impossible to retrieve it by any means, but as davmac explains in another answer, you might be able to get your hands on it in a SIGCHLD handler.

Fann answered 22/6, 2018 at 13:22 Comment(5)
"The short answer is that you can't" - not completely true, see my answer below.Zaremski
@Zaremski Oh! Thanks. I didn't know that. (I've always shied strongly away from SIGCHLD, because my personal belief is that it's impossible for mere mortals to implement SIGCHLD handlers without drowning in neverending race conditions, but the si_status thing is good to know.)Fann
"I've always shied strongly away from SIGCHLD" - to be honest that is probably wise. You're right that signal handling is tricky to get right in general.Zaremski
Well, this is interesting - I wrote a test program to check, and it turns out that Linux doesn't honour this particular POSIX requirement. :( See my updated answer. This makes your answer completely correct after all.Zaremski
@Zaremski I don't have a problem with signal handling in general, but yes, SIGCHLD is a viper's nest. What a mess. (And this discrepancy wrt Linux and the lower 8 bits only makes it worse.)Fann
B
0

I believe the only ways you can get it is by straceing the process and looking for the exit system calls, which now seem to be exit_group, by debugging, or possibly by using some ugly hacks like LD_PRELOAD. I.e. nothing unintrusive.

For zombie processes the exit code can be found in the last column of /proc/<pid>/stat but it is already & 0xFF.

Berley answered 22/6, 2018 at 7:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.