I'm writing a process related program in C and I'm having a small problem waking up a process:
I have a parent process that I put to sleep with waitpid(), but I need it to carry on either when its children complete, or when a certain time is reached. My plan was to call alarm(timeout), and then call waitpid(-1,&status,0), so essentially the process would wait until a child finished, and if the child didnt finish within the timeout time, a signal would be sent and the parent would exit after killing the child. The issue I'm having is that this alarm() call just prints "Alarm clock" to the console, and it doesnt seem to be waking up the parent in time. Thanks!
You need to install a signal handler for SIGALRM. alarm() sends a SIGALRM signal when it expires, and if you don't handle that signal it will terminate your process.
static int g_timeout;
void alrm_handler(int signo)
{
g_timeout = 1;
}
And in your main code, e.g.:
signal(SIGALRM, alrm_handler);
alarm(10);
pid_t p = waitpid(-1,&status,0);
if (p == -1) {
if (errno == EINTR && g_timeout) {
//timeout occured
} else {
//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 a program with a signal handler:
signal(SIGINT, signalhandler);
Then the program forks and the child needs a different signal handler so:
pid = fork();
/* What happens here? */
if(pid==0)
{
signal(SIGINT, signalhandler_for_child);
}
So what happens if a SIGINT is called right after the fork but before the new sign handler is assigned?
Can this happen or there is no possibility to be interrupted before the child gets the new signal handler.
If it is possible. How could I queue the signal to the child so it gets time to get the new handler?
I know that the probabilities, if they exist, must be almost 0, but I want to make sure the application is robust in this aspect.
So what happens if a SIGINT is called right after the fork but before the new sign handler is assigned?
The signal handler installed in the parent will be called. Child process inherits it.
Can this happen or there is no possibility to be interrupted before the child gets the new signal handler.
Cetainly can happen.
If it is possible. How could I queue the signal to the child so it gets time to get the new handler?
To ensure, you need to block SIGINT before calling fork() and then reinstall a different for SIGINT
in the child process and then unblock SGINT.
/* block SIGINT here. */
pid = fork();
if (pid == 0) {
/* Install a new SIGINT handler here. */
/* Unblock SIGINT. */
...
} else if (pid > 0) {
/* The SIGINT handler is already in place. So just unblock SIGINT. */
...
} else {
/* error */
}
Look at sigprocmask() and pthread_sigmask() for blocking and unblocking signals.
You may also find the GNU documentation on signal blocking useful.
I'm trying to do an assignment for one of my classes and no professors/fellow classmates are getting back to me. So before you answer, please don't give me any exact answers! Only explanations!
What I have to do is write a c program (timeout.c) that takes in two command line arguments, W and T, where W is the amount of time in seconds the child process should take before exiting, and T is the amount of time the parent process should wait for the child process, before killing the child process and printing out a "Time Out" message. Basically, if W > T, there should be a timeout. Otherwise, the child should finish its work and then no timeout message is printed.
What I wanted to do was just have the parent process sleep for T seconds, and then kill the child process and print out the timeout, however printing out the timeout message would happen no in both cases. How do I check to see that the child process is terminated? I was told to use alarm() for this, however I have no idea of what use that function would serve.
Here's my code in case anyone wants to take a look:
void handler (int sig) {
return;
}
int main(int argc, char* argv[]){
if (argc != 3) {
printf ("Please enter values W and T, where W\n");
printf ("is the number of seconds the child\n");
printf ("should do work for, and T is the number\n");
printf ("of seconds the parent process should wait.\n");
printf ("-------------------------------------------\n");
printf ("./executable <W> <T>\n");
}
pid_t pid;
unsigned int work_seconds = (unsigned int) atoi(argv[1]);
unsigned int wait_seconds = (unsigned int) atoi(argv[2]);
if ((pid = fork()) == 0) {
/* child code */
sleep(work_seconds);
printf("Child done.\n");
exit(0);
}
sleep(wait_seconds);
kill(pid, SIGKILL);
printf("Time out.");
exit(0);
}
Although waitpid would get you the return status of the child, its default usage would force parent to wait until the child terminates.
But your requirement (if i understood correctly) only wants parent to wait for a certain time, alarm() can be used to do that.
Then, you should use waitpid() with a specific option that returns immediately if the child has not exited yet (study the api's parameters). So if the child didn't exit, you could kill it, else you already receive its return status.
You want the timeout program to stop more or less as soon as the command finishes, so if you say timeout -t 1000 sleep 1 the protecting program stops after about 1 second, not after 1000 seconds.
The way to do that is to set an alarm of some sort — classically, with the alarm() system call and a signal handler for SIGALRM — and then have the main process execute wait() or waitpid() so that when the child dies, it wakes up and collects the corpse. If the parent process gets the alarm signal, it can print its message and send death threats of some sort to its child. It might be sensible to try SIGTERM and/or SIGHUP before resorting to SIGKILL; the SIGTERM and SIGHUP signals give the errant child a chance to clean up whereas SIGKILL does not.
If you know how to manage signals, you could catch SIGALRM and SIGCHLD in your parent process. SIGCHLD will be raised when the client terminates, and SIGALRM when the timer expires. If the first raised signal is SIGALRM, the timeout expired, otherwise, if the first SIGNAL that the parent catches is SIGCHLD, the child has stopped before the expiration of the timeout.
wait() or waitpid() would still be necessary to collect the terminated child.
This program is supposed to
The parent simply waits indefinitely for any child to return (hint, waitpid).
b. The child sets up two signal handlers (hint, signal) and goes to sleep for 5 minutes.
i. The first signal handler listens for the USR1 signal, and upon receiving it:
1. Creates a thread (hint, pthread_create).
a. Basically, all that the thread needs to do is “say hello” and sleep for 60
seconds.
ii. The second signal handler listens for the USR2 signal, and upon receiving it:
1. Destroys the thread (hint, pthread_cancel).
When this program receives the first signal to create the thread, it outputs
"[thread] sleeping for 1 m[thread] sleeping for 1 minute"
and then ends, it never waits for the 2nd signal, what am i doing wrong?
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
pthread_t thread;
void* temp()
{
printf("[thread] hello professor\n");
printf("[thread] sleeping for 1 minute\n");
sleep(60);
}
void handle_USR1(int x)
{
int s;
printf("[signal] creating the thread\n");
s = pthread_create(&thread, NULL, &temp, NULL);
}
void handle_USR2(int x)
{
int s;
printf("[signal] destroying the thread\n");
s = pthread_cancel(thread);
}
int main(void)
{
int status = 0;
if(fork() != 0)
{
printf("[parent] waiting.....\n");
waitpid(-1, &status, 0);
}
else
{
printf("[child] to create the thread: kill -USR1 %d\n", getpid());
printf("[child] to end the thread: kill -USR2 %d\n", getpid());
printf("[child] setting up signal handlers\n");
signal(SIGUSR1, handle_USR1);
signal(SIGUSR2, handle_USR2);
printf("[child] waiting for signals\n");
sleep(300);
}
return (0);
}
As Charlie Burns pointed out, both processes eventually exit as a consequence of the signal, but for different reasons.
Child
During its sleep, the child is blocked in a system call (the actual system call is nanosleep, used to implement the sleep() function). When a process receives a signal while in a system call, the corresponding signal handler is executed and the system call returns an error, EINTR, which means it has been interrupted and couldn't fulfill its duty. You can then decide if you want to restart the system call or not. Upon receiving SIGUSR1, the nanosleep system call executed by the child is interrupted, the handler is executed and sleep() returns immediately. Notice what man 3 sleep says about the return value of sleep():
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.
The correct way would be for the child to check for the return value of sleep (number of seconds left to sleep), and sleep again for that duration.
Parent
Unlike what Charlie Burns pointed out, waitpid() in the parent does not return because of the child receiving a signal. It returns because of the child exiting. It would return because of the child IF the child did not handle the signal, and thus was killed by it (an unhandled signal causes the process to die). You can (and should) check that using the WIFEXITED macro and its companions as described in man 2 waitpid. The example at the bottom of this man page is very good:
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
Basically, what this code does is wait on the child until it has exited normally or has exited because of an unhandled signal. In your case, it would be a good idea for the parent to check the status variable to make sure that waitpid returned because of the event it expects (a child exiting) and not something else.
Place a pthread_join after your pthread_create.
Ok, I see what is going on.
When you send a signal, without otherwise directing it to a particular thread by masking, any thread within a process can get it. When SIGUSR1 gets delivered main in the child gets blown out of the sleep and the main thread terminates killing the thread created in the handler.
There are plenty of questions here covering how to direct signals to a single thread and/or using sigaction to restart a system call if that is also a direction you want to go in to resolve it.
I'm writing a program that uses fork to create child processes and count them when they're done.
How can I be sure I'm not losing signals?
what will happen if a child sends the signal while the main program still handles the previous signal? is the signal "lost"? how can I avoid this situation?
void my_prog()
{
for(i = 0; i<numberOfDirectChildrenGlobal; ++i) {
pid = fork();
if(pid > 0)//parent
//do parent thing
else if(0 == pid) //child
//do child thing
else
//exit with error
}
while(numberOfDirectChildrenGlobal > 0) {
pause(); //waiting for signal as many times as number of direct children
}
kill(getppid(),SIGUSR1);
exit(0);
}
void sigUsrHandler(int signum)
{
//re-register to SIGUSR1
signal(SIGUSR1, sigUsrHandler);
//update number of children that finished
--numberOfDirectChildrenGlobal;
}
It's recommended to use sigaction instead of signal, but in both cases it won't provide what you need. If a child sends a signal while the previous signal is still being handled, it will become a pending signal, but if more signals are sent they will be discarded (on systems that are not blocking incoming signals, the signals can be delivered before reestablishment of the handler and again resulting in missing signals). There is no workaround for this.
What one usually does is to assume that some signals are missing, and lets the handler take care of exiting children.
In your case, instead of sending a signal from your children, just let the children terminate. Once they terminate, the parent's SIGCHLD handler should be used to reap them. Using waitpid with WNOHANG option ensures that the parent will catch all the children even if they all terminate at the same time.
For example, a SIGCHLD handler that counts the number of exited children can be :
pid_t pid;
while((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
nrOfChildrenHandled++;
}
To avoid this situation you can use the posix real-time signals.
Use sigaction instead of signal to register your handlers, and the delivery of the signals is assured.