`waitpid()' always returns -1 - c

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 */
}

Related

Best practice for waiting for a child process termination in C

I am writing a C library that at some point forks another process and then waits for its completion.
I'd like to write the code that waits for the child process completion in the most robust and generic way, to take care of all possible scenarios, such as the calling process spawning other child processes, receiving signals etc.
Does the following C code use waitpid properly, i.e. in the most robust way?
void waitForChildProcess(int child_pid) {
int rc, err;
do {
//waiting only for my own child and only for its termination.
//The status value is irrelevant (I think) because option '0' should mean
//to only wait for a child termination event
// and I don't care about the child's exit code:
rc = waitpid(child_pid, NULL, 0);
err = errno;
} while (rc == -1 && err == EINTR); //ignoring a signal
}
Yes, waitpid(child_pid, ...) is the most robust way.
It will return child_pid if the child process has exited, -1 with errno set if an error occurs (ECHILD if the child process does not exist (was never created or has already been reaped) or is not a child of this process, EINVAL if the options (third parameter) had an invalid value, or EINTR if a signal was delivered to a signal handler that was not installed with SA_RESTART flags), or 0 if WNOHANG option (third parameter) was specified and the child process has not yet exited.
I would recommend a slight change, however:
/* Wait for child process to exit.
* #child_pid Process ID of the child process
* #status Pointer to where the child status
* is stored; may be NULL
* #return 0 if success
* -1 if an error occurs, see errno.
*/
int waitForChildProcess(pid_t child_pid, int *status)
{
int rc;
if (child_pid <= 1) {
errno = EINVAL;
return -1;
}
do {
rc = waipid(child_pid, status, 0);
} while (rc == -1 && errno == EINTR);
if (rc == child_pid)
return 0;
/* This should not happen, but let's be careful. */
if (rc != -1)
errno = ECHILD;
return -1;
}
In Linux and POSIXy systems, process ID's are positive integers. As you can see in the man 2 waitpid man page, zero and negative PIDs refer to process groups, and -1 to any child process. Process 1 is special, init; it is the one that never exits and sets up the rest of the userspace. So, the smallest PID a child of the current process can ever have is 2.
I do consider it sensible to use the proper types for these: pid_t for process IDs, and for example size_t for memory sizes of objects (including the return value of say strlen().)
Providing the status pointer (so that the caller can check it with WIFEXITED()+WEXITSTATUS() or WIFSIGNALED()+WTERMSIG()) is a convenience, since any callers not interested in it can provide a NULL. (NULL is explicitly allowed for the status pointer for wait() and waitpid().)
Technically, with options==0, waitpid() should only ever return either the child PID, or -1 (with errno set). However, since the check is so cheap, I prefer to treat everything else as an ECHILD error, since that gives the most robust results.
The caller is free to ignore the return value. However, if they want to know, the return value is 0 if successful, otherwise -1 with errno set (and strerror(errno) provides the textual reason).

Get returned value of a child process without holding parent execution

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.)

How to print parent process when all child exited in C [duplicate]

In my program I am forking (in parallel) child processes in a finite while loop and doing exec on each of them. I want the parent process to resume execution (the point after this while loop ) only after all children have terminated. How should I do that?
i have tried several approaches. In one approach, I made parent pause after while loop and sent some condition from SIGCHLD handler only when waitpid returned error ECHILD(no child remaining) but the problem I am facing in this approach is even before parent has finished forking all processes, retStat becomes -1
void sigchld_handler(int signo) {
pid_t pid;
while((pid= waitpid(-1,NULL,WNOHANG)) > 0);
if(errno == ECHILD) {
retStat = -1;
}
}
**//parent process code**
retStat = 1;
while(some condition) {
do fork(and exec);
}
while(retStat > 0)
pause();
//This is the point where I want execution to resumed only when all children have finished
Instead of calling waitpid in the signal handler, why not create a loop after you have forked all the processes as follows:
while (pid = waitpid(-1, NULL, 0)) {
if (errno == ECHILD) {
break;
}
}
The program should hang in the loop until there are no more children. Then it will fall out and the program will continue. As an additional bonus, the loop will block on waitpid while children are running, so you don't need a busy loop while you wait.
You could also use wait(NULL) which should be equivalent to waitpid(-1, NULL, 0). If there's nothing else you need to do in SIGCHLD, you can set it to SIG_DFL.
I think you should use the waitpid() call. It allows you to wait for "any child process", so if you do that the proper number of times, you should be golden.
If that fails (not sure about the guarantees), you could do the brute-force approach sitting in a loop, doing a waitpid() with the NOHANG option on each of your child PIDs, and then delaying for a while before doing it again.

What does the second parameter of waitpid() mean?

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.

Waiting for all child processes before parent resumes execution UNIX

In my program I am forking (in parallel) child processes in a finite while loop and doing exec on each of them. I want the parent process to resume execution (the point after this while loop ) only after all children have terminated. How should I do that?
i have tried several approaches. In one approach, I made parent pause after while loop and sent some condition from SIGCHLD handler only when waitpid returned error ECHILD(no child remaining) but the problem I am facing in this approach is even before parent has finished forking all processes, retStat becomes -1
void sigchld_handler(int signo) {
pid_t pid;
while((pid= waitpid(-1,NULL,WNOHANG)) > 0);
if(errno == ECHILD) {
retStat = -1;
}
}
**//parent process code**
retStat = 1;
while(some condition) {
do fork(and exec);
}
while(retStat > 0)
pause();
//This is the point where I want execution to resumed only when all children have finished
Instead of calling waitpid in the signal handler, why not create a loop after you have forked all the processes as follows:
while (pid = waitpid(-1, NULL, 0)) {
if (errno == ECHILD) {
break;
}
}
The program should hang in the loop until there are no more children. Then it will fall out and the program will continue. As an additional bonus, the loop will block on waitpid while children are running, so you don't need a busy loop while you wait.
You could also use wait(NULL) which should be equivalent to waitpid(-1, NULL, 0). If there's nothing else you need to do in SIGCHLD, you can set it to SIG_DFL.
I think you should use the waitpid() call. It allows you to wait for "any child process", so if you do that the proper number of times, you should be golden.
If that fails (not sure about the guarantees), you could do the brute-force approach sitting in a loop, doing a waitpid() with the NOHANG option on each of your child PIDs, and then delaying for a while before doing it again.

Resources