just a quick question regarding C and processes. In my program, I create another child process and use a two-directional pipe to communicate between the child and parent. The child calls execl() to run yet another program.
My question is: I want the parent to wait n amount of seconds and then check if the program that the child has run has exited (and with what status). Something like waitpid() but if the child doesn't exit in n seconds, I'd like to do something different.
You can use waitpid() with WNOHANG as option to poll, or register a signal handler for SIGCHLD.
You can use an alarm to interrupt waitpid() after N seconds (don't use this approach in a multithreaded environment though)
signal(SIGALRM,my_dummy_handler);
alarm(10);
pid_t p = waitpid(...);
if(p == -1) {
if(errno == EINTR) {
//timeout occured
} else {
//handle other error
}
Related
In this example from the CSAPP book chap.8:
\#include "csapp.h"
/* WARNING: This code is buggy! \*/
void handler1(int sig)
{
int olderrno = errno;
if ((waitpid(-1, NULL, 0)) < 0)
sio_error("waitpid error");
Sio_puts("Handler reaped child\n");
Sleep(1);
errno = olderrno;
}
int main()
{
int i, n;
char buf[MAXBUF];
if (signal(SIGCHLD, handler1) == SIG_ERR)
unix_error("signal error");
/* Parent creates children */
for (i = 0; i < 3; i++) {
if (Fork() == 0) {
printf("Hello from child %d\n", (int)getpid());
exit(0);
}
}
/* Parent waits for terminal input and then processes it */
if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
unix_error("read");
printf("Parent processing input\n");
while (1)
;
exit(0);
}
It generates the following output:
......
Hello from child 14073
Hello from child 14074
Hello from child 14075
Handler reaped child
Handler reaped child //more than one child reaped
......
The if block used for waitpid() is used to generate a mistake that waitpid() is not able to reap all children. While I understand that waitpid() is to be put in a while() loop to ensure reaping all children, what I don't understand is that why only one waitpid() call is made, yet was able to reap more than one children(Note in the output more than one child is reaped by handler)? According to this answer: Why does waitpid in a signal handler need to loop?
waitpid() is only able to reap one child.
Thanks!
update:
this is irrelevant, but the handler is corrected in the following way(also taken from the CSAPP book):
void handler2(int sig)
{
int olderrno = errno;
while (waitpid(-1, NULL, 0) > 0) {
Sio_puts("Handler reaped child\n");
}
if (errno != ECHILD)
Sio_error("waitpid error");
Sleep(1);
errno = olderrno;
}
Running this code on my linux computer.
The signal handler you designated runs every time the signal you assigned to it (SIGCHLD in this case) is received. While it is true that waitpid is only executed once per signal receival, the handler still executes it multiple times because it gets called every time a child terminates.
Child n terminates (SIGCHLD), the handler springs into action and uses waitpid to "reap" the just exited child.
Child n+1 terminates and its behaviour follows the same as Child n. This goes on for every child there is.
There is no need to loop it as it gets called only when needed in the first place.
Edit: As pointed out below, the reason as to why the book later corrects it with the intended loop is because if multiple children send their termination signal at the same time, the handler may only end up getting one of them.
signal(7):
Standard signals do not queue. If multiple instances of a
standard signal are generated while that signal is blocked, then
only one instance of the signal is marked as pending (and the
signal will be delivered just once when it is unblocked).
Looping waitpid assures the reaping of all exited children and not just one of them as is the case right now.
Why is looping solving the issue of multiple signals?
Picture this: you are currently inside the handler, handling a SIGCHLD signal you have received and whilst you are doing that, you receive more signals from other children that have terminated in the meantime. These signals cannot queue up. By constantly looping waitpid, you are making sure that even if the handler itself can't deal with the multiple signals being sent, waitpid still picks them up as it's constantly running, rather than only running when the handler activates, which can or can't work as intended depending on whether signals have been merged or not.
waitpid still exits correctly once there are no more children to reap. It is important to understand that the loop is only there to catch signals that are sent when you are already in the signal handler and not during normal code execution as in that case the signal handler will take care of it as normal.
If you are still in doubt, try reading these two answers to your question.
How to make sure that `waitpid(-1, &stat, WNOHANG)` collect all children processes
Why does waitpid in a signal handler need to loop? (first two paragraphs)
The first one uses flags such as WNOHANG, but this only makes waitpid return immediately instead of waiting, if there is no child process ready to be reaped.
I have to run my processes in strong order, child then parent, what if child gets blocked, how to stop parent?
if ((pid = fork()) == -1) { /* create a child process */
perror("fork() failed\n");
exit(1);
}
if (pid == 0) {
/* child process */
func1(NULL);
fflush(stdout);
return 0;
} else {
/* parent process */
wait(NULL);
func2(NULL);
fflush(stdout);
}
Aaand as an alternative to an active cpu-busy loop with a timeout doing waitpid() with WNOHANG in a loop, you should prefer to implement it in such a way that cpu is free.
Do not call wait from parent, instead enable SIGCHLD and setup timeout with a timer and call pause() and wait for and dispatch events from signals with pause(). An example how to do it is even in man 3 wait.
Also on Linux you can use pidfd_open(pid, 0) and call poll() on it for POLLIN with a timeout.
From the comment you gave: You don't want to stop the parent on a blocked child, which is done by wait(). In contrary, you don't want the parent to be blocked in wait().
Use waitpid() for this. It receives a third argument, which can include WNOHANG. This will make waitpid() return immediately, without waiting for some child to change its state. However, you need to implement some kind of loop, a check for desired states, and probably a timeout.
For further information please consult the documentation.
I have simple C program which executes an application using fork() and execl(). If execl() fails to run the application, then I have to call a function in the parent process and exit from the child process. If execl() successfully runs the application, then I have show a success log from the parent process. So, parent process should wait for the child's execl() call (just the call, not till the end of execution of the application), get some information about it status, and then make decisions and continue its own execution. Here is my code.
int main()
{
int iExecRetVal, pid;
pid = fork();
if (pid == -1)
{
}
else if (pid > 0)
{
}
else
{
iExecRetVal = execl("./flute-static", "./flute-static", "-send", "-a192.168.190.1/6666", "JFlute.1.2.tar.gz", NULL);
if (iExecRetVal == -1)
{
/*execl() failed, need some error handling in the parent process*/
}
_exit(0);
}
/*Parent's normal execution*/
}
int HandleSuccessFromParent()
{
/*Should be called when exec call was successful*/
}
int HandleFailureFromParent()
{
/*Should be called when exec call was NOT successful*/
}
We know execl() does not return on success. So, how to call HandleSuccessFromParent() and HandleFailureFromParent() functions properly after the execl() call in the child. Please help me.
The child process needs to exit with an error status (non-zero; 1 is common, EXIT_FAILURE is standard C).
The parent process needs to wait for the child to finish, and capture the child's exit status, using wait() or
waitpid().
If you need to know whether the child died but don't want to wait for it to complete, use waitpid() with WNOHANG after a small pause to let the child try and run (a sub-second delay is likely to be long enough).
One possible solution involves ptrace. The outline is as follows:
Let the child call ptrace(PTRACE_TRACEME). Let the parent enable PTRACE_O_TRACEEXEC option and waitpid on the child. In this setup waitpid would return upon successful execl. Test the status to see if it has a SIGTRAP flag set. Let the child continue with PTRACE_DETACH.
Please consider this code in c:
int main()
{
pid_t cpid;
cpid = fork();
if (cpid == -1)
{
perror("fork");
return 0;
}
if (cpid == 0)
{
printf("I'm child\n");
_exit(0);
}
else
{
while(1)
{
printf("I'm parent\n");
sleep(1);
}
}
return 0;
}
After running the code, I expect it to run child and exits it once it's done.
But when I run
pgrep executable_name
or
ps fax
it shows the child process id and I don't know if its just a history crap of working process or it really does not end/terminate the child process?
thanks in advance
The child will remain until its parent dies or the parent cleans it up with the wait system calls. (In the time between the child terminating and it being cleaned up, it is referred to as a zombie process.)
The reason is that the parent might be interested in the child's return value or final output, so the process entry stays active until that information is queried.
edit:
Example code for using the sigchld handler to immediately clean up processes when they die without blocking:
http://arsdnet.net/child.c
Be mindful of the fact that system calls (like sleep, select, or file read/writes) can be interrupted by signals. This is a normal thing you should handle anyway in unix - they fail and set errno to EINTR. When this happens, you can just try again to finish the operation. This is why my example code calls sleep twice in the parent - the first long sleep is interrupted by the child dying, then the second, shorter sleep lets us confirm the process is actually cleaned up before the parent dies.
BTW signal handlers usually shouldn't do much, they should return as soon as possible and avoid things that aren't thread safe; printfing in them is usually discouraged. I did it here just so you can watch everything as it happens.
You need to call wait() in the parent, otherwise the child process will never be reaped (it becomes a zombie).*
* Unless the parent itself also exits.
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.