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);
}
Related
The codes is as below, and is the same as the one in book apue3e:
#include "apue.h"
#include "sys/wait.h"
static void sig_int(int);
int
main(int argc, char *argv[]) {
pid_t pid;
char buf[MAXLINE];
int status;
if (signal(SIGINT, sig_int) == SIG_ERR) {
err_sys("signal error");
}
printf("%% ");
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf)-1] == '\n') {
buf[strlen(buf)-1] = '\0';
}
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) {
execlp(buf, buf, (char *)NULL);
err_ret("couldn't execlvp: %s\n", buf);
exit(127);
}
if ((pid = waitpid(pid, &status, 0)) < 0) {
err_sys("waitpid_error");
}
printf("%% ");
}
exit(0);
}
static void
sig_int(int signo/* arguments */) {
/* code */
printf("Interrupted\n%%3 ");
}
So, my question is why this signal handler doesn't handle the SIGINT signal and exit immediately after pressing the Ctrl+c which i was testing on archlinux.
[W]hy this signal handler doesn't handle the SIGINT signal and exit immediately after pressing the Ctrl+c which i was testing on archlinux.
Given
static void
sig_int(int signo/* arguments */) {
/* code */
printf("Interrupted\n%%3 ");
}
and
signal(SIGINT, sig_int)
Your process doesn't exit when you press CTRL-C for the simple reason your signal handler doesn't cause the process to exit.
You replaced the default SIGINT handler with your own, so the default action of exiting the process no longer happens.
Since you're running on Linux, I'll refer to the GNU glibc documentation on termination signals:
24.2.2 Termination Signals
These signals are all used to tell a process to terminate, in one way
or another. They have different names because they’re used for
slightly different purposes, and programs might want to handle them
differently.
The reason for handling these signals is usually so your program can
tidy up as appropriate before actually terminating. For example, you
might want to save state information, delete temporary files, or
restore the previous terminal modes. Such a handler should end by
specifying the default action for the signal that happened and then
reraising it; this will cause the program to terminate with that
signal, as if it had not had a handler. (See Termination in
Handler.)
The (obvious) default action for all of these signals is to cause the
process to terminate.
...
Macro: int SIGINT
The SIGINT (“program interrupt”) signal is sent when the user types
the INTR character (normally C-c).
The Termination in Handler glibc documentation states:
24.4.2 Handlers That Terminate the Process
Handler functions that terminate the program are typically used to
cause orderly cleanup or recovery from program error signals and
interactive interrupts.
The cleanest way for a handler to terminate the process is to raise
the same signal that ran the handler in the first place. Here is how
to do this:
volatile sig_atomic_t fatal_error_in_progress = 0;
void
fatal_error_signal (int sig)
{
/* Since this handler is established for more than one kind of signal,
it might still get invoked recursively by delivery of some other kind
of signal. Use a static variable to keep track of that. */
if (fatal_error_in_progress)
raise (sig);
fatal_error_in_progress = 1;
/* Now do the clean up actions:
- reset terminal modes
- kill child processes
- remove lock files */
…
/* Now reraise the signal. We reactivate the signal’s
default handling, which is to terminate the process.
We could just call exit or abort,
but reraising the signal sets the return status
from the process correctly. */
signal (sig, SIG_DFL);
raise (sig);
}
Also, note that there can be significant differences between signal() and sigaction(). See What is the difference between sigaction and signal?
Finally, calling printf() from with a signal handler is undefined behavior. Only async-signal-safe functions can be safely called from within a signal handler. See POSIX 2.4 Signal Concepts for the gory details.
My intention is to create a time out of 1 sec for fgets. If no input is received in 1 sec, then the program terminates.
The design I come up with is:
the parent registers a signal handler for SIGALRM. Then it forks a child which will trigger SIGALRM and it goes ahead and call fgets. The SIGALRM will trigger the handler which kills the parent process. But when I execute this on a ubuntu 14.04 64-bit, the handler is not triggered and the program just waits for user to input for fgets forever.
Why would this happen and how can I fix this?
#include "csapp.h"
void handler() {
printf("lazy man\n");
kill(SIGKILL, getppid());
exit(0);
}
int main() {
char buf[100];
signal(SIGALRM, handler);
pid_t pid;
if ((pid = fork()) == 0) {
alarm(1);
} else {
fgets(buf, 100, stdin);
printf("%s", buf);
}
return 0;
}
~
This forking and killing seems wrong. Just set the alarm, register an empty signal handler for SIGALRM, and then check the return value from fgets() - if it fails, check whether errno == EINTR; if it does - it was interrupted by signal.
If you will take time to read the manual of kill(), you will see that you miss the order of the arguments.
int kill(pid_t pid, int sig);
Fix:
kill(getppid(), SIGKILL);
Plus, your child terminate his execution before that the signal is raise you must add a sleep() after your call to alarm() to make it wait:
alarm(1);
sleep(2);
Finally, printf() is not safe in a signal handler, list of safe function.
The APUE book says that: If the signal occurs after the test of sig_int_flag but before the call to pause, the process could go to sleep forever.
I don't know why, can somebody tells me?
Thanks a lot.
int sig_int(); /* my signal handling function */
int sig_int_flag; /* set nonzero when signal occurs */
int main() {
signal(SIGINT, sig_int) /* establish handler */
.
.
.
while (sig_int_flag == 0)
pause(); /* go to sleep, waiting for signal */
}
int sig_int() {
signal(SIGINT, sig_int); /* reestablish handler for next time */
sig_int_flag = 1; /* set flag for main loop to examine */
}
If an interrupt signal is issued at the precise time you're describing:
the flag has been checked false: entering loop
signal resets itself, setting the flag to 1, but too late (test has been done)
since loop has already been entered, pause() is called and the program waits
That said, if CTRL+C/SIGINT is triggered another time, you can exit the loop, so it's not that critical, since that signal can be issued manually.
If you want to check that behaviour, I suggest you add a sleep statement:
while (sig_int_flag == 0)
{
printf("Hit CTRL+C in the next 10 seconds to trigger the bug\n");
sleep(10);
pause(); /* go to sleep, waiting for signal */
}
A workaround would be to remove the pause() statement and replace it by a polling loop:
while (sig_int_flag == 0)
{
sleep(1);
}
If a SIGINT occurs anywhere in the loop, including between the while and the sleep, then the worse thing that can happen is that the program waits 1 second before noticing that the flag is set, then it exits the loop, and the other, more plausible case it that the sleep call is interrupted, and the loop is exited immediately, so when the signal is set, there's little visible difference between that and a pause call if we only expect SIGINT.
The question's already answered. However, additional answer can consolidate the idea.
while (sig_int_flag == 0) {
<----- think it signal is caught here before pause btw while and pause()
pause(); /* go to sleep, waiting for signal */
}
Having caught, signal handler runs. After it finishes its task, it returns to a point at which the signal is caught, in main() in this case. So, the point is pause() and pause() is called. It waits again SIGINT to catch. To exemplify it, I add sleep(5) equivalently to catch prior pause().
So, we typically want the second situation. To achieve it always, the aforementioned code block has to be atomic. That's why sigsuspend() is better and should be used.
If you would like to experience the fallible case,
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
volatile sig_atomic_t sig_int_flag = 0; /* set nonzero when signal occurs */
char const * handlerMsg = "in handler\n";
int handlerMsgLen;
void sig_int(int s) {
signal(SIGINT, sig_int); /* reestablish handler for next time */
sig_int_flag = 1; /* set flag for main loop to examine */
write(2, handlerMsg, handlerMsgLen);
}
void mySleep() {
for (int i = 0; i < 5; ++i) {
sleep(1);
fprintf(stderr, "%d ", i + 1);
}
}
int main() {
handlerMsgLen = strlen(handlerMsg);
signal(SIGINT, sig_int); /* establish handler */
while (sig_int_flag == 0) {
mySleep();
pause(); /* go to sleep, waiting for signal */
}
}
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