void main ( )
{ int x;
signal (SIGUSR1, f);
x= fork ( );
if (x == -1) exit (1);
if (x != 0)
{ kill (x, SIGUSR1) ;
sleep (2);
exit (0);
}
}
void f ( )
{
printf ("signal received");
exit (0);
}
I think that the program above asks the system to launch the f function ( which displays "signal received" ) when the SIGUSR1 signal is received by the parent process. but I'm not sure about that, please feel free to correct or to give more details. Thank for the help !
There are some mistakes in your code:
Avoid calling printf( ) function in signal handler. SIGNAL(7) manual provides a list of authorized functions calling them is safe inside signal-handlers. Read:
Async-signal-safe functions
A signal handler function must be very careful, since processing
elsewhere may be interrupted at some arbitrary point in the execution
of the program. POSIX has the concept of "safe function". If a
signal interrupts the execution of an unsafe function, and handler
calls an unsafe function, then the behavior of the program is
undefined.
Use return type of main() int; read "What should main() return in C?"
x should be pid_t. (Process Identification).
Now lets suppose your program compile and run (not interrupted by any other signal while handler executing):
I am just indenting your code and shifting f() function definition before main because function declaration is missing, also adding some comments that you should read:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
void f( )
{
printf ("signal received\n");
exit (0);//if child receives signal then child exits from here
} // ******* mostly happens
int main ( )
{ int x;
signal (SIGUSR1, f);// First: handler registered
x = fork ( ); // Second: Child created, now child will execute in
if (x == -1) // parallel with parent
exit (1);
if (x != 0) {// parent
kill(x, SIGUSR1) ; // Third: sends signal to child
sleep(2); // Forth: parent sleep
}
return 0; // parent always exits
// Child can exits from here ****
// if signal sent from parent delayed
}
In main() function, you registers f() function for SIGUSR1 signal and after that calls fork() to create a new process. In runtime as fork() function returns a child-process starts executing in parallel with parent process.
As I can see your code, I think that you understands that child-process is copy of parent-process except values of variables can be different from the point fork() returns and hence x is different in child and parent process. We can use the return value from fork to tell whether the program is running in the parent-process or in child. But note that it is not parent but actually the child-process that receives signal SIGUSR1. Value of self process id is always 0 for any process. You checks the return value x = fork() that is pid of newly created child-process, in child-process value of x is 0 and in parent x != 0. Hence signal is sent from parent process to child process.
Your comments:
I think that the program above asks the system to launch the f( ) function ( which displays "signal received") when the SIGUSR1 signal is received by the parent process.
I have impression that you don't consider that both processes execute concurrently and "it can be happen that soon after fork() create a child-process, child-process start executing and immediately terminate before parent-process can send a signal to child (or child-process can receive the signal)". In that case, function f() will never get a chance to execute and printf in signal handler never prints.
But the possibility of what I have described just above is very low because fork takes time to create a new process. And even if you execute the code again and again most of the times signal sent from the parent process will execute signal-handler.
What is correct way of writing this code?
Code is x.c: Correct way is set a flag that indicates that signal handler executed and then call printf function on the bases of flag value outside signal-handler as I have described in my answer: How to avoid using printf in a signal handler? And reason behind it explained by Jonathan Leffler in his answer.
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
volatile sig_atomic_t flag = 0; //initially flag == 0
void f(){
flag = 1; // flag is one if handler executes
}
int main(void){
pid_t x;
(void) signal (SIGUSR1, f);
x = fork();
if(x == -1)
exit(EXIT_FAILURE);
if (x != 0){// parent
kill(x, SIGUSR1);
sleep(1);
}
if(flag)//print only if signal caught and flag == 1
printf("%s signal received \n", x == 0 ? "Child:" : "Parent:");
return EXIT_SUCCESS;
}
Now compile it and execute:
#:~$ gcc -Wall -pedantic -std=c99 x.c -o x
#:~$ ./x
Child: signal received
#:~$
Notice child-process prints because parent sends signal to child(but parent process doesn't prints as no signal catch in parent). So behavior of above code still similar as you was getting in your code. Below I have added one more example in which I am trying to demonstrate that 'concurrent execution of processes results different at different instance of execution'(read comments).
// include header files...
volatile sig_atomic_t flag = 0;
void f(){
flag = 1;
}
int main(void){
pid_t x;
(void) signal (SIGUSR1, f);
(void) signal (SIGUSR2, f); // added one more signal
x= fork ( );
if(x == -1)
exit(EXIT_FAILURE);
if (x != 0){// parent
kill(x, SIGUSR1);
while(!flag); // in loop until flag == 0
}
if (x == 0){//child
kill(getppid(), SIGUSR2); // send signal to parent
while(!flag); // in loop until flag == 0
}// ^^^^ loop terminates just after signal-handler sets `flag`
if(flag)
printf("%s signal received \n", x == 0 ? "Child:" : "Parent:");
return EXIT_SUCCESS;
}
In above code, two signals are registered in both parent and child process. Parent process doesn't sleeps but busy in a while loop until a signal sets flag. Similarly child-process has a loop that breaks as flag becomes 1 in signal-handler. Now compile this code and run repeatedly. I frequently tried an got following output in my system.
#:~$ gcc -Wall -pedantic -std=c99 x.c -o x
#:~$ ./x
Child: signal received
Parent: signal received
#:~$ ./x
Child: signal received
Parent: signal received
#:~$ ./x
Child: signal received
Parent: signal received
#:~$ ./x
Parent: signal received // <------
#:~$ Child: signal received
./x
Child: signal received
Parent: signal received
#:~$ ./x
Parent: signal received // <------
#:~$ Child: signal received
#:~$
Notice output, one case is: "till child process created parent sent signal and enter in while-loop and when child-process get chance to execute(depends on CPU scheduling) it send back a signal to parents and before parent process get chance to execute child receives signal and prints message". But it also happens sometimes that before child printf print; parent receives and print message (that is I marked using arrow).
In last example I am trying to show child-process executes in parallel with parent- process and output can be differs if you don't applies concurrency control mechanism.
Some good resource To learn signals (1) The GNU C Library: Signal Handling
(2) CERT C Coding Standard 11. Signals (SIG).
One problem is that the child process doesn't do anything, but will return immediately from the main function, maybe before the parent process can send the signal.
You might want to call e.g. pause in the child.
For the sake of the exercise, here is a corrected version of the original code which will compile and run.
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <bits/signum.h>
void f ( );
int main ( )
{ int x;
signal (SIGUSR1, f);
x= fork ( );
if (x == -1) exit (1);
if (x != 0)
{ kill (x, SIGUSR1) ;
sleep (2);
exit (0);
}
}
void f ( )
{
printf ("signal received\n");
exit (0);
}
This does exactly what the original question suggested the program should do. Try it out and see what happens if you don't believe me.
BTW: I'm not very experienced at C. There are a number of comments asserting that using printf() in the child process is unsafe. Why?? The child process is a duplicate of the parent including virtual address space. So why is printf() unsafe?
Related
I tried to answer this question:
Write a program C that creates two children. The second child process
is blocked until the reception of the signal SIGUSR1 sent from the
parent process. While the first child process is blocked until the
reception of the signal SIGUSR2 (that will kill him) sent from the
second child process. The parent is terminated after the termination
of his children.
However the execution is not working as intended with my code below, and only the parent printfs are displayed. Can you tell me what's wrong with my code?
My code:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
void this(int sig) {
printf("this is this");
}
int main() {
int pid = fork();
int pid2;
if (pid < 0) {
exit(-1);
} else if (pid == 0) {
printf("FIrst child is paused");
pause();
printf("ERror");
} else {
pid2 = fork();
if (pid2 < 0) {
exit(-2);
} else if (pid2 == 0) {
signal(SIGUSR1, &this);
printf("Second child is paused");
pause();
kill(pid,SIGUSR2);
printf("signal sent to first child");
} else {
printf("this is the parent");
kill(pid2, SIGUSR1);
printf("signal sent to second child");
wait(NULL);
exit(-3);
}
}
}
You make no provision to ensure that the parent's signal is delivered to the second child only when that child is ready for it. Because process startup takes some time, chances are good that the signal is indeed delivered sooner. In that case, the second child will be terminated (default disposition of SIGUSR1) or it will block indefinitely in pause() (if the signal is received after the handler is installed but before pauseing). In neither case will the second child signal the first.
Signal masks and signal dispositions are inherited across a fork, so you can address that by blocking SIGUSR1 in the parent before forking, and then using sigsuspend() in the child instead of pause(), which will enable you to atomically unblock the signal and start waiting for it.
The same is not an issue for the first child because you're looking for it to exercise the default disposition for SIGUSR2 (termination), and it does not matter for the specified behavior whether that happens before that child reaches or blocks in pause().
Additionally,
the parent waits only for one child, but the prompt seems to say that it must wait for both. Perhaps you dropped the second wait() because the parent was not terminating, but if so, that was a missed clue that one of the children was not terminating.
printf is not async-signal-safe, so calling it from a signal handler invokes undefined behavior.
you should put a newline at the end of your printf formats. This will make your output much more readable, and it will also ensure that the output is delivered to the screen promptly. That could end up being useful as you debug. Alternatively, use puts() instead of printf() since you are outputting only fixed strings. puts() will add a newline automatically.
The absence of newlines probably explains why the first child's output from before it pauses is never printed. If the second child were reaching the indefinite pause state then it would also explain why that child's pre-pause output was not being printed.
Recently, when reading a book about linux programming, I got a message that:
The status argument given to _exit() defines the termination status of the process, which is available to the parent of this process when it calls wait(). Although defined as an int, only the bottom 8 bits of status are actually made available to the parent. And only 0 ~ 127 is recommanded to use, because 128 ~ 255 could be confusing in shell due to some reason. Due to that -1 will become 255 in 2's complement.
The above is about the exit status of a child process.
My question is:
Why the parent process only get the 8 bits of the child process's exit status?
What about return value of normal functions? Does it reasonable or befinit to use only 0 ~ 127 ? Because I do use -1 as return value to indicate error sometimes, should I correct that in future.
Update - status get by wait() / waitpid():
I read more chps in the book (TLPI), and found there are more trick in the return status & wait()/waitpid() that worth mention, I should have read more chps before ask the question. Anyhow, I have add an answer by myself to describe about it, in case it might help someone in future.
Why the parent process only get the 8 bits of the child process's exit status?
Because POSIX says so. And POSIX says so because that's how original Unix worked, and many operating system derived from it and modeled after it continue to work.
What about return value of normal functions?
They are unrelated. Return whatever is reasonable. -1 is as good as any other value, and is in fact a standard way to indicate an error in a huge lot of standard C and POSIX APIs.
The answer from #n.m. is good.
But later on, I read more chps in the book (TLPI), and found there are more trick in the return status & wait()/waitpid() that worth mention, and that might be another important or root reason why child process can't use full bits of int when exit.
Wait status
basicly:
child process should exit with value within range of 1 byte, which is set as part of the status parameter of wait() / waitpid(),
and only 2 LSB bytes of the status is used,
byte usage of status:
event byte 1 byte 0
============================================================
* normal termination exit status (0 ~ 255) 0
* killed by signal 0 termination signal (!=0)
* stopped by signal stop signal 0x7F
* continued by signal 0xFFFF
*
dissect returned status:
header 'sys/wait.h', defines a set of macros that help to dissect a wait status,
macros:
* WIFEXITED(status)
return true if child process exit normally,
*
* WIFSIGNALED(status)
return true if child process killed by signal,
* WTERMSIG(status)
return signal number that terminate the process,
* WCOREDUMP(status)
returns ture if child process produced a core dump file,
tip:
this macro is not in SUSv3, might absent on some system,
thus better check whether it exists first, via:
#ifdef WCOREDUMP
// ...
#endif
*
* WIFSTOPPED(status)
return true if child process stopped by signal,
* WSTOPSIG(status)
return signal number that stopp the process,
*
* WIFCONTINUED(status)
return true if child process resumed by signal SIGCONT,
tip:
this macro is part of SUSv3, but some old linux or some unix might didn't impl it,
thus better check whether it exists first, via:
#ifdef WIFCONTINUED
// ...
#endif
*
Sample code
wait_status_test.c
// dissect status returned by wait()/waitpid()
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#define SLEEP_SEC 10 // sleep seconds of child process,
int wait_status_test() {
pid_t cpid;
// create child process,
switch(cpid=fork()) {
case -1: // failed
printf("error while fork()\n");
exit(errno);
case 0: // success, child process goes here
sleep(SLEEP_SEC);
printf("child [%d], going to exit\n",(int)getpid());
_exit(EXIT_SUCCESS);
break;
default: // success, parent process goes here
printf("parent [%d], child created [%d]\n", (int)getpid(), (int)cpid);
break;
}
// wait child to terminate
int status;
int wait_flag = WUNTRACED | WCONTINUED;
while(1) {
if((cpid = waitpid(-1, &status, wait_flag)) == -1) {
if(errno == ECHILD) {
printf("no more child\n");
exit(EXIT_SUCCESS);
} else {
printf("error while wait()\n");
exit(-1);
}
}
// disset status
printf("parent [%d], child [%d] ", (int)getpid(), (int)cpid);
if(WIFEXITED(status)) { // exit normal
printf("exit normally with [%d]\n", status);
} else if(WIFSIGNALED(status)) { // killed by signal
char *dumpinfo = "unknow";
#ifdef WCOREDUMP
dumpinfo = WCOREDUMP(status)?"true":"false";
#endif
printf("killed by signal [%d], has dump [%s]\n", WTERMSIG(status), dumpinfo);
} else if(WIFSTOPPED(status)) { // stopped by signal
printf("stopped by signal [%d]\n", WSTOPSIG(status));
#ifdef WIFCONTINUED
} else if(WIFCONTINUED(status)) { // continued by signal
printf("continued by signal SIGCONT\n", WSTOPSIG(status));
#endif
} else { // this should never happen
printf("unknow event\n");
}
}
return 0;
}
int main(int argc, char *argv[]) {
wait_status_test();
return 0;
}
Compile:
gcc -Wall wait_status_test.c
Execute:
./a.out and wait it to terminate normally, child process id is printed after fork(),
./a.out, then kill -9 <child_process_id> before it finish sleep,
./a.out, then kill -STOP <child_process_id> before it finish sleep, then kill -CONT <child_process_id> to resume it,
I got a problem in C when I try to pause an execution of a system() call.
A thread calls some application (e.g. some benchmark) repeatedly. Whenever it gets a signal SIGUSR1, the execution shall be paused and resumed on receiving SIGUSR2.
The source looks like this:
#include <signal.h>
#include <pthread.h>
void* run_app(sigset_t* signalsBetweenControllerandLoad)
{
/* assign handler */
signal(SIGUSR1, pausesignal_handler)
signal(SIGUSR2, pausesignal_handler)
pthread_sigmask(SIG_UNBLOCK, signalsBetweenControllerandLoad, NULL))
/* call application repeatedly */
while(1) {
system(SOMECOMMAND);
}
return(0);
}
static void pausesignal_handler(int signo)
{
int caughtSignal;
caughtSignal = 0;
/* when SIGUSR1 is received, wait until SIGUSR2 to continue execution */
if (signo == SIGUSR1) {
signal(signo, pausesignal_handler);
while (caughtSignal != SIGUSR2) {
sigwait (signalsBetweenControllerandLoad, &caughtSignal);
}
}
}
When I use some commands (e.g. a for loop as below that makes some computations) instead of system(SOMECOMMAND) this code works. But a program called by system() is not paused when the handler is active.
int i;
for(i=0;i<10;i++) {
sleep(1);
printf("Just a text");
}
Is there a way to pause the execution of the system() command by using thread signals? And is there even a way to stop the application called by system without needing to wait until the program is finished?
Thank you very much in advance!
system runs the command in a separate process, which doesn't even share address space with the invoking program, never mind signal handlers. The process which called system is sitting in a waitpid (or equivalent), so pausing and unpausing it will have little effect (except that if it is paused, it won't return to the loop to call system again.)
In short, there is no way to use signals sent to the parent process to pause an executable being run in a child, for example with the system() call or with fork()/exec().
If the executable itself implements the feature (which is unlikely, unless you wrote it yourself), you could deliver the signal to that process, not the one which called system.
Alternatively, you could send the SIGSTOP signal to the executable's process, which will unconditionally suspend execution. To do that, you'll need to know its pid, which suggests the use of the fork()/exec()/waitpid() sequence -- a little more work than system(), but cleaner, safer, and generally more efficient -- and you'll need to deal with a couple of issues:
A process cannot block or trap SIGSTOP, but it can trap SIGCONT so the sequence is not necessarily 100% transparent.
Particular care needs to be taken if the stopped process is the terminal's controlling process, since when it is resumed with SIGCONT it will need to reacquire the terminal. Furthermore, if the application has placed the terminal in a non-standard state -- for example, by using the readline or curses libraries which typically put the terminal into raw mode and disable echoing -- then the terminal may be rendered unusable.
Your process will receive a SIGCHLD signal as a result of the child processed being stopped. So you need to handle that correctly.
I want to present you my (shortened) resulting code after the help of #rici. Again, thank you very much.
Shortly described, the code forks a new process (calling fork) and executes there a command with exec. The parent then catches user defined signals SIGNAL_PAUSE and SIGNAL_RESUME and forwards signals to the forked child accordingly. Whenever the command finishes - catched by waitpid - the parent forks again and restarts the load.
This gets repeated until SIGNAL_STOP is sent where the child gets a SIGINT and gets cancelled.
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#define SIGNAL_PAUSE (SIGUSR1)
#define SIGNAL_RESUME (SIGUSR2)
#define SIGNAL_STOP (SIGSYS)
/* File scoped functions */
static void pausesignal_handler(int signo);
static void stopsignal_handler(int signo);
void send_signal_to_load_child(int signo);
/*Set file scope variables as handlers can only have signal-number as argument */
sigset_t* signalsBetweenControllerandLoad;
int restart_benchmark;
pid_t child_pid;
void* Load(char* load_arguments[MAX_NR_LOAD_ARGS], sigset_t* signalsToCatch) {
int load_ID;
pid_t p;
signalsBetweenControllerandLoad = signalsToCatch;
/* set signal handlers to catch signals from controller */
signal(SIGNAL_PAUSE, pausesignal_handler)
signal(SIGNAL_RESUME, pausesignal_handler)
signal(SIGNAL_STOP, stopsignal_handler)
pthread_sigmask(SIG_UNBLOCK, signalsBetweenControllerandLoad[load_ID], NULL)
/* Keep restarting benchmark until Stop signal was received */
restart_benchmark[load_ID] = 1;
/* execute benchmark, repeat until stop signal received */
while(restart_benchmark[load_ID])
{
if (child_pid == 0) {
if ((p = fork()) == 0) {
execv(load_arguments[0],load_arguments);
exit(0);
}
}
/* Parent process: Wait until child with benchmark finished and restart it */
if (p>0) {
child_pid = p; /* Make PID available for helper functions */
wait(child_pid); /* Wait until child finished */
child_pid = 0; /* Reset PID when benchmark finished */
}
}
return(0);
}
static void pausesignal_handler(int signo) {
static double elapsedTime;
int caughtSignal;
caughtSignal = 0;
if (signo == SIGNAL_PAUSE) {
send_signal_to_load_child(SIGSTOP);
printf("Load Paused, waiting for resume signal\n");
while (restart_benchmark == 1 && caughtSignal != SIGNAL_RESUME) {
sigwait (signalsBetweenControllerandLoad, &caughtSignal);
if (caughtSignal == SIGNAL_STOP) {
printf("Load caught stop signal when waiting for resume\n");
stopsignal_handler(caughtSignal);
} else if (caughtSignal != SIGNAL_RESUME) {
printf("Load caught signal %d which is not Resume (%d), keep waiting...\n",caughtSignal,SIGNAL_RESUME);
}
}
if (restart_benchmark[load_ID]) {
send_signal_to_load_child(SIGCONT, load_ID);
printf("Load resumed\n");
}
} else {
printf("Load caught unexpected signal %d.\n",signo);
}
/* reassign signals for compatibility reasons */
signal(SIGNAL_PAUSE, pausesignal_handler);
signal(SIGNAL_RESUME, pausesignal_handler);
}
static void stopsignal_handler(int signo) {
double elapsedTime;
signal(SIGNAL_STOP, stopsignal_handler);
if (signo == SIGNAL_STOP) {
restart_benchmark = 0;
send_signal_to_load_child(SIGINT);
printf("Load stopped.\n");
} else {
printf("catched unexpected stop-signal %d\n",signo);
}
}
void send_signal_to_load_child(int signo) {
int dest_pid;
dest_pid = child_pid;
printf("Error sending %d to Child: PID not set.\n",signo);
kill(dest_pid, signo);
}
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 playing with waitpid() and signal() and I'm looking for reliable test cases for returning WIFSIGNALED(status) = WIFSTOPPED(status) = WIFCONTINUED (status) = true but can't find any...
Care to tell me how can I make sure those return true so I can debug my code?
Also, a few hints about what signals should I catch with signal() to test those macros would be helpful...
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define NELEMS(x) (sizeof (x) / sizeof (x)[0])
static void testsignaled(void) {
kill(getpid(), SIGINT);
}
static void teststopped(void) {
kill(getpid(), SIGSTOP);
}
static void testcontinued(void) {
kill(getpid(), SIGSTOP);
/* Busy-work to keep us from exiting before the parent waits.
* This is a race.
*/
alarm(1);
while(1) {}
}
int main(void) {
void (*test[])(void) = {testsignaled, teststopped, testcontinued};
pid_t pid[NELEMS(test)];
int i, status;
for(i = 0; i < sizeof test / sizeof test[0]; ++i) {
pid[i] = fork();
if(0 == pid[i]) {
test[i]();
return 0;
}
}
/* Pause to let the child processes to do their thing.
* This is a race.
*/
sleep(1);
/* Observe the stoppage of the third process and continue it. */
wait4(pid[2], &status, WUNTRACED, 0);
kill(pid[2], SIGCONT);
/* Wait for the child processes. */
for(i = 0; i < NELEMS(test); ++i) {
wait4(pid[i], &status, WCONTINUED | WUNTRACED, 0);
printf("%d%s%s%s\n", i, WIFCONTINUED(status) ? " CONTINUED" : "", WIFSIGNALED(status) ? " SIGNALED" : "", WIFSTOPPED(status) ? " STOPPED" : "");
}
return 0;
}
Handling WIFSIGNALED is easy. The child process can commit suicide with the kill() system call. You can also check for core dumps - some signals create them (SIGQUIT, IIRC); some signals do not (SIGINT).
Handling WIFSTOPPED may be harder. The simple step to try is for the child to send itself SIGSTOP with the kill() system call again. Actually, I think that should work. Note that you may want to check on SIGTTIN and SIGTTOU and SIGTSTOP - I believe they count for WIFSTOPPED. (There's also a chance that SIGSTOP only works sanely when sent by a debugger to a process it is running via the non-POSIX system call, ptrace().)
Handling WIFCONTINUED is something that I think the parent has to do; after you detect a process has been stopped, your calling code should make it continue by sending it a SIGCONT signal (kill() again). The child can't deliver this itself; it has been stopped. Again, I'm not sure whether there are extra wrinkles to worry about - probably.
A framework something like the below will allow you check the results of the wait() and waitpid() calls.
pid_t pid = fork();
if (pid == 0) {
/* child */
sleep(200);
}
else {
/* parent */
kill(pid, SIGSTOP);
/* do wait(), waitpid() stuff */
}
You do not actually have to catch the signals (using signal() or related function) that are sent. signal() installs a handler that overrides the default behavior for the specific signal - so if you want to check for a signal terminating your process, pick one that has that default behavior - "man -s7 signal" will give you details a signal's default behavior.
For the macros you have mentioned use SIGSTOP for WIFSTOPPED(status), SIGCONT for WIFCONTINUED (status) and SIGINT for WIFSIGNALED(status)
If you want more flexibility for testing, you could use kill (see "man kill") to send signals to your process. kill -l will list all the signals that can be sent.
in your tests you can fork() and send specific signal to your child processes? In this scenario your child processes are test cases?
EDIT
my answer is about coding a C test. you fork, get the pid of your child process (the process
with signal handlers installed), then you can send signal to it by using kill(2).
In this way you can test the exit status