From a existing question here, someone gave this example code:
int status;
child_pid = fork();
if (child_pid == 0) {
// in child; do stuff including perhaps exec
} else if (child_pid == -1) {
// failed to fork
} else {
if (waitpid(child_pid, &status, 0) == child_pid) {
// child exited or interrupted; now you can do something with status
} else {
// error etc
}
}
Could anyone explain to me what the second parameter of waitpid() is used for?
from man pages :
If status is not NULL, wait() and waitpid() store status infor-
mation in the int to which it points. This integer can be
inspected with the following macros (which take the integer
itself as an argument, not a pointer to it, as is done in wait()
and waitpid()!):
WIFEXITED(status)
returns true if the child terminated normally, that is,
by calling exit(3) or _exit(2), or by returning from
main().
WEXITSTATUS(status)
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 only be employed if WIFEXITED returned true.
WIFSIGNALED(status)
returns true if the child process was terminated by a
signal.
WTERMSIG(status)
returns the number of the signal that caused the child
process to terminate. This macro should only be employed
if WIFSIGNALED returned true.
WCOREDUMP(status)
returns true if the child produced a core dump. This
macro should only be employed if WIFSIGNALED returned
true. This macro is not specified in POSIX.1-2001 and is
not available on some Unix implementations (e.g., AIX,
SunOS). Only use this enclosed in #ifdef WCOREDUMP ...
#endif.
WIFSTOPPED(status)
returns true if the child process was stopped by delivery
of a signal; this is only possible if the call was done
using WUNTRACED or when the child is being traced (see
ptrace(2)).
WSTOPSIG(status)
returns the number of the signal which caused the child
to stop. This macro should only be employed if WIF-
STOPPED returned true.
WIFCONTINUED(status)
(since Linux 2.6.10) returns true if the child process
was resumed by delivery of SIGCONT.
So it stores status of the "how the child terminated".
You can use the macros to investigate how exactly the child terminated, and you can define some actions depending to the child's termination status.
It is a bit-field for options, the only one available is WNOWAIT, which means to leave the child in a waitable state; a later wait call can be used to again retrieve the child status information.
See: http://linux.die.net/man/2/waitpid
pid = fork();
if(pid < 0)
{
printf("fork failed\n");
return -1;
}
else if(pid == 0)
{
sleep(5);
printf("Child process\n");
return 2;
}
else
{
printf("Parent process\n");
kill(pid, SIGKILL);
waitpid(pid, &ret, 0);
if(WIFEXITED(ret))
printf("Child process returned normally\n");
if(WIFSIGNALED(ret))
printf("Child process terminated by signal\n");
return 1;
}
As you can see that the return value can be used to check how a particular process terminated and take actions on the basis of that.
If you comment the kill line from the code, the child process will terminate properly.
Related
I'm executing the code below and the call to waitpid() always returns -1, thus the code bellow ends with an infinite loop. The call works if I replace WNOHANG with 0.
void execute(cmdLine* pCmdLine) {
int status = 0;
pid_t pid = fork();
if(pid == 0) {
if(execvp(pCmdLine->arguments[0], pCmdLine->arguments) == -1) {
if(strcmp(pCmdLine->arguments[0], "cd") != 0) {
perror("execute failed\n");
}
_exit(1);
}
} else {
if(pCmdLine->blocking == 1) {
waitpid(pid, &status, 0);
}
while(waitpid(pid, &status, WNOHANG) == -1) {
printf("still -1\n");
}
}
}
}
Well, you have misunderstood the workings of the wait system call.
As with malloc/free, you can only successfully waitpid() only once per fork()ed process... so the while loop is never necessary if you are going to wait for the exit code of the child, you have to call it only once. Wait will only return -1 in your case because of two reasons:
fork() didn't succeed, so you are waiting for an invalid pid. Indeed, you should be calling wait() for pid == -1, which is invalid. In case you wait() and there's no process to be waited for (in case the pid variable has a positive number, but of an already wait()ed subprocess, you also get -1), you get an error from any of the wait() family of system calls. The mission of zombie processes in UN*X systems is just this, to ensure that a wait() for an already finished child is still valid and the calling process gets the exit code signalled by the child on exit().
You expressely say you are not going to wait for the process to finish. It should be clear that if you are not going to wait for the process to terminate, this is what you are doing with the WNOHANG parameter, then the child process can be still running (which is your case) and had not yet done an exit() syscall. You only want the exit code in case the child process has already finished. If this is the case, then you had better to write:
while(waitpid(pid, &status, WNOHANG) == -1 && errno == EAGAIN)
do_whatever_you_want_because_you_decided_not_to_wait();
The wait system call has no way to tell you that the &status variable has not been filled with the exit code of the child process than signalling an error, and in that case, it always sets errno to EAGAIN.
but, from my point of view, if you have nothing to do in the meanwhile, then you had better not to use WNOHANG. That will save cpu cycles and a lot of heat energy thrown to the environment.
Here
while(waitpid(pid,&status,WNOHANG)==-1) { }
when if there is no more child process exists then waitpid returns -1 and it makes while(true) always and that cause infinite loop.
From the manual page of waitpid().
waitpid(): on success, returns the process ID of the child whose
state has changed; if WNOHANG was specified and one or more
child(ren) specified by pid exist, but have not yet changed state,
then 0 is returned. On error, -1 is returned.
That means, when there are no more child to wait for, it returns -1. So either make it like
if() { /* child process. can be multiple */
}
else { /* parent process */
while(waitpid(pid,&status,WNOHANG) != -1) { /* when there is no more child process exists then it terminate */
}
}
or
if() { /* child process. can be multiple */
}
else { /* parent process */
while(waitpid(pid,&status,WNOHANG) == -1); /* dummy while ..when there is no more child process exists then it terminate */
}
I need to be able to get the returned value from a child process without having to hold the execution of the parent for it.
Notice the a runtime error could happen in the child process.
Here is my program that I'm trying to make:
//In parent process:
do
{
read memory usage from /proc/ID/status
if(max_child_memory_usage > memory_limit)
{
kill(proc, SIGKILL);
puts("Memory limit exceeded");
return -5; // MLE
}
getrusage(RUSAGE_SELF,&r_usage);
check time and memory consumption
if(memory limit exceeded || time limit exceeded)
{
kill(proc, SIGKILL);
return fail;
}
/*
need to catch the returned value from the child somehow with
this loop working.
Notice the a runtime error could happen in the child process.
*/
while(child is alive);
The waitpid function has an option called WNOHANG which causes it to return immediately if the given child has not yet returned:
pid_t rval;
int status;
do {
...
rval = waitpid(proc, &status, WNOHANG);
} while (rval == 0);
if (rval == proc) {
if (WIFEXITED(status)) {
printf("%d exited normal with status %d\n", WEXITSTATUS(status));
} else {
printf("%d exited abnormally\n");
}
}
See the man page for waitpid for more details on checking various abnormal exit conditions.
The solutions using the WNOHANG flag would work only if you need to check just once for the exit status of the child. If however you would like to procure the exit status when the child exits, no matter how late that is, a better solution is to set a signal handler for the SIGCHLD signal.
When the child process terminates whether normally or abnormally, SIGCHLD will be sent to the parent process. Within this signal handler, you can call wait to reap the exit status of the child.
void child_exit_handler(int signo){
int exit_status;
int pid = wait(&exit_status);
// Do things ...
}
// later in the code, before forking and creating the child
signal(SIGCHLD, child_exit_handler);
Depending on other semantics of your program, you may want to use waitpid instead. (SIGCHLD may also be called if the program was stopped, not terminated. The man page for wait(2) describes macros to check for this.)
I have this code:
int status;
t = wait(&status);
When the child process works, the value of status is 0, well.
But why does it return 256 when it doesn't work? And why changing the value of the argument given to exit in the child process when there is an error doesn't change anything (exit(2) instead of exit(1) for example)?
Edit : I'm on linux, and I compiled with GCC.
Given code like this...
int main(int argc, char **argv) {
pid_t pid;
int res;
pid = fork();
if (pid == 0) {
printf("child\n");
exit(1);
}
pid = wait(&res);
printf("raw res=%d\n", res);
return 0;
}
...the value of res will be 256. This is because the return value from wait encodes both the exit status of the process as well as the reason the process exited. In general, you should not attempt to interpret non-zero return values from wait directly; you should use of the WIF... macros. For example, to see if a process exited normally:
WIFEXITED(status)
True if the process terminated normally by a call to _exit(2) or
exit(3).
And then to get the exit status:
WEXITSTATUS(status)
If WIFEXITED(status) is true, evaluates to the low-order 8 bits
of the argument passed to _exit(2) or exit(3) by the child.
For example:
int main(int argc, char **argv) {
pid_t pid;
int res;
pid = fork();
if (pid == 0) {
printf("child\n");
exit(1);
}
pid = wait(&res);
printf("raw res=%d\n", res);
if (WIFEXITED(res))
printf("exit status = %d\n", WEXITSTATUS(res));
return 0;
}
You can read more details in the wait(2) man page.
The status code contains various information about how the child process exited. Macros are provided to get information from the status code.
From wait(2) on linux:
If status is not NULL, wait() and waitpid() store status information in the int to which it points. This integer can be inspected with the following macros (which take the integer itself as an argu-
ment, not a pointer to it, as is done in wait() and waitpid()!):
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)
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.
WIFSIGNALED(status)
returns true if the child process was terminated by a signal.
WTERMSIG(status)
returns the number of the signal that caused the child process to terminate. This macro should be employed only if WIFSIGNALED returned true.
WCOREDUMP(status)
returns true if the child produced a core dump. This macro should be employed only if WIFSIGNALED returned true. This macro is not specified in POSIX.1-2001 and is not available on some UNIX
implementations (e.g., AIX, SunOS). Only use this enclosed in #ifdef WCOREDUMP ... #endif.
WIFSTOPPED(status)
returns true if the child process was stopped by delivery of a signal; this is possible only if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)).
WSTOPSIG(status)
returns the number of the signal which caused the child to stop. This macro should be employed only if WIFSTOPPED returned true.
WIFCONTINUED(status)
(since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
SUGGESTION: try one of the following "Process Completion Status" macros:
http://www.gnu.org/software/libc/manual/html_node/Process-Completion-Status.html
EXAMPLE:
int status = 0;
..
int retval = wait (&status);
if (WIFEXITED(status))
printf("OK: Child exited with exit status %d.\n", WEXITSTATUS(status));
else
printf("ERROR: Child has not terminated correctly.\n");
So, I'm exiting from the child thread back to the parent. I am using the _exit() system call. I was wondering a few things. One was what parameter for the _exit for my child. Here is the code that my child process is executing:
printf("\n****Child process.****\n\nSquence: ");
do{
//Print the integer in the sequence.
printf("%d\t",inputInteger);
if((inputInteger%2) == 0){
//printf("inputInteger = %d\n", inputInteger);
inputInteger = inputInteger / 2;
}else{
inputInteger = 3*inputInteger +1;
//printf("%d\t",inputInteger);
}
}while(inputInteger != 1);
//Makes sure we print off 1!
printf("%d\n\n", inputInteger);
//Properly exit
_exit(status);
I use status because back in my parent thread I use it in the waitpid() system call. Here is the code for parent process that is executed after the child is completed.
waitpid_check = waitpid(processID, &status, 0);
printf("\n****Parent process.****\n");
if(waitpid_check == -1){
printf("Error in waitpid.\n");
exit(EXIT_FAILURE);
}
if(WIFEXITED(status)){
printf("Child process terminated normally!\n");
}
Here I'm using waitpid() system call that ensures that the child was exited, then use status to check if it was exited properly. I was wondering if I was going about this in the right way of creating the child and exiting it.
Then I was also wondering if I was correctly checking the exiting of the child in the parent.
Thanks for your help!
From the waitpid linux manual.
"If status is not NULL, wait() and waitpid() store status information in the int to which
it points."
You don't need the return value of wait paid to check if the child failed. You need to check to value of status. There are a handful of macros to check status.
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)
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 only be employed if WIFEXITED returned true.
WIFSIGNALED(status)
returns true if the child process was terminated by a signal.
WTERMSIG(status)
returns the number of the signal that caused the child process to terminate. This macro should only be employed if WIFSIGNALED returned true.
WCOREDUMP(status)
returns true if the child produced a core dump. This macro should only be employed if WIFSIGNALED returned true. This macro is not specified in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS). Only use this enclosed in #ifdef WCOREDUMP ... #endif.
WIFSTOPPED(status)
returns true if the child process was stopped by delivery of a signal; this is only possible if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)).
WSTOPSIG(status)
returns the number of the signal which caused the child to stop. This macro should only be employed if WIFSTOPPED returned true.
WIFCONTINUED(status)
(since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
As for whether or not you are exiting the child process right that really depends. You would exit like you would in any other program since when you fork a process you are really just duplicating an address space and the child when run as its own independent program (of course with the same open FD's, already declared values etc as parent). Below is typical implementation for this problem (although NULL is being passed to the wait instead of a status so I think you are doing it right.)
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed\n");
return 1;
}
else if (pid == 0) { /* child process */
printf("I am the child %d\n",pid);
execlp("/bin/ls","ls",NULL);
}
else { /* parent process */
/* parent will wait for the child to complete */
printf("I am the parent %d\n",pid);
wait(NULL);
printf("Child Complete\n");
}
return 0;
I'd love to help but I'm really rusty on these calls. If you've read through the documentation on these API calls and you're checking everywhere for error returns, then you should be in good shape.
The idea seems good at a high level.
One thing to keep in mind is you might want to surround the meat of your child method in a try/catch. With threads, you often don't want an exception to mess up your main flow.
You won't have that problem with multiple processes, but think about whether you want _exit to be called in the face of an exception, and how to communicate (to the parent or to the user) that an exception occurred.
After creating a child process and exiting it immediately (_exit()), I want to perform a wait and check the status. Now I wonder if in the 'else' branch of the if/else construct I also need to check for WIFSIGNALED. As far as I understand, if I perform a wait, a) an error could have occured (-1), the child could have terminated normally by an (exit() or _exit()), or it could have been terminated by a signal, so the check could be omitted, right?
//remainder omitted
int status;
pid_t t_pid = wait(&status);
if (t_pid == -1) {
perror("wait");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("child terminated normally, status = %d\n",
WEXITSTATUS(status)
);
} else { // <-- do it have to check for WIFSIGNALED() here?
printf("child was terminated by a signal, signum = %d\n",
WTERMSIG(status)
);
}
I don't know.
But you could make your child die "abnormally". kill(getpid()) in the child?
http://publib.boulder.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=/com.ibm.ztpf-ztpfdf.doc_put.cur/gtpc2/cpp_wifsignaled.html
From the sound of the words in the docs I'd say you are doing it correctly.
Yes, you are correct - if wait succeeded then either WIFEXITED() or WIFSIGNALED() will be true.
Yes. POSIX.1 states:
If the information pointed to by
stat_loc was stored by a call to
waitpid() that did not specify the
WUNTRACED or WCONTINUED flags, or by a
call to the wait() function, exactly
one of the macros WIFEXITED(*stat_loc)
and WIFSIGNALED(*stat_loc) shall
evaluate to a non-zero value.
Using waitpid() with WUNTRACED or WCONTINUED, it is possible to get a status where WIFSTOPPED(*stat_loc) or WIFCONTINUED(*stat_loc) is true instead.