I'm studying C signals and I'm having trouble with an exercise that requires to write a program which sends back any signal it receives from a process back to the sender process.
I thought about using the function signal() or the function sigaction(), but they ask you to specify the signum, and I would need them to handle EVERY signal my program receives.
Is there any way to do so without calling the sigaction() for every signal number?
Thank you in advance for your answers
You don't specify what OS you are using but this is simple on POSIX systems. I can't speak to Windows.
The call you want is sigwaitinfo.
You need to block all signals and then use sigwaitinfo to process any received signals synchronously. Sigwaitinfo's return code is the signal received and when you pass a non-null siginfo_t struct as the second parameter you get the same information you would get from a signal handler returning a siginfo_t structure, including the pid of the sending process. Take the received signal and pid and use kill to send the signal back to the originating process. Make sure you aren't sending the signal to yourself before calling kill lest you end up in a loop of sending and receiving a signal to yourself.
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#define errExit(msg) do {perror(msg); exit(EXIT_FAILURE);} while (0)
int main(int argc, char *argv[])
{
siginfo_t signalInfo;
sigset_t allSignals;
printf("echo pid = %d\n", getpid());
// block every signal but SIGKILL & SIGSTOP which can't be blocked
sigfillset(&allSignals);
if (sigprocmask(SIG_SETMASK, &allSignals, NULL) == -1)
errExit("sigprocmask");
while(1)
{
// accept signals until SIGTERM delivered
int sig = sigwaitinfo(&allSignals, &signalInfo);
if (sig == -1)
errExit("sigwaitinfo");
if (sig == SIGTERM)
{
printf("buh-bye\n");
exit(EXIT_SUCCESS);
}
printf("echo received signal %s (%d) from pid = %d\n", strsignal(sig), sig, signalInfo.si_pid);
/*** NOT doing this for testing because it will kill the sending shell
// echo signal back to sender but not to yourself
// which would be stupid and lead to an endless loop
if (signalInfo.si_pid != getpid())
kill(signalInfo.si_pid, sig);
***/
}
}
TEST
--- terminal 1 ---
//current shell's pid
> echo $$
7646
//send signals after starting echo pgm in another terminal
> kill -SIGUSR1 7754
> kill -SIGUSR2 7754
> kill -SIGTERM 7754
--- terminal 2 ---
> echosig
echo pid = 7754
echo received signal User defined signal 1 (10) from pid = 7646
echo received signal User defined signal 2 (12) from pid = 7646
buh-bye
Related
When sending a signal to a process that both blocks and ignores it, the kernel still keeps this signal in the pending list (my terminology here). In this case the kernel behaves like the signal is only blocked, although it should also be ignored. I can't understand this behavior. Here is a C code for example with SIGUSR1 (which has the index 10):
#define _GNU_SOURCE
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void handler(int sig)
{
printf("Received signal %d\n", sig);
}
int main(int argc, char *argv[])
{
printf("PID is %ld\n", (long) getpid());
int sig = SIGUSR1;
//creating the sigaction struct and setting the handler
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
if(sigaction(sig, &act, NULL) == -1)
{
printf("Error: sigaction\n");
exit(1);
}
//Blocking the signal
sigset_t blockedSignals;
sigemptyset(&blockedSignals);
sigaddset(&blockedSignals, sig);
printf("Blocking signal %d\n", sig);
if(sigprocmask(SIG_SETMASK, &blockedSignals, NULL) == -1)
{
printf("Error: sigprocmask\n");
exit(1);
}
//Ignoring the signal
act.sa_handler = SIG_IGN;
printf("Ignoring signal %d\n", sig);
if(sigaction(sig, &act, NULL) == -1)
{
printf("Error: sigaction\n");
exit(1);
}
//Sleeping for a while in order to give the user a chance to send the signal to this process
printf("Sleeping for 20 sec. Please send the signal.\n");
sleep(20);
//Unblocking the signal
/*sigemptyset(&blockedSignals);
printf("Unblocking signal %d\n", sig);
if(sigprocmask(SIG_SETMASK, &blockedSignals, NULL) == -1)
{
printf("Error: sigprocmask\n");
exit(1);
}*/
//Let's check the pending list
sigset_t pendingSignals;
sigemptyset(&pendingSignals);
if(sigpending(&pendingSignals) == -1)
{
printf("Error: sigpending\n");
exit(1);
}
if(sigismember(&pendingSignals, sig) == 1)
{
printf("Signal %d is pending.\n", sig);
}
else
{
printf("Signal %d isn't pending.\n", sig);
}
exit(0);
}
SIGUSR1 is both blocked and ignored. While this process sleeps, if I send a SIGUSR1 to it (from shell: kill -s SIGUSR1 PID), and then checks the pending list, I get this printing:
Signal 10 is pending.
If I uncomment the commented block of code, which unblocks the signal:
sigemptyset(&blockedSignals);
printf("Unblocking signal %d\n", sig);
if(sigprocmask(SIG_SETMASK, &blockedSignals, NULL) == -1)
{
printf("Error: sigprocmask\n");
exit(1);
}
and repeat the experiment, I see the following printing:
Signal 10 isn't pending.
It's like the kernel gives priority to the 'blocking' over the 'ignoring'.
Is it really the case?
Update: As far as I understand, when the process ignores a signal, it means that the kernel won't send it to the process. This also means that it won't keep it in the pending list. For example, if a signal is only blocked by the process, and exists in the pending list, and then we call 'sigaction' in order to ignore it, the kernel will remove this signal from the pending list. So the question is, why if we block+ignore in ahead, the kernel inserts the signal to its pending list?
Blocking a signal and ignoring it are two separate and independent things.
Ignoring a signal by setting its disposition to SIG_IGN instructs that when the signal is delivered the resulting action should be to do nothing.
Blocking a signal (by setting a signal mask that includes that signal) has the effect of preventing that signal from being delivered at all. If it is received, then it will remain pending until unblocked or the process terminates. Signal disposition does not matter until the signal is actually delivered. So,
It's like the kernel gives priority to the 'blocking' over the 'ignoring'. Is it really the case?
Yes. The effect of ignoring a signal cannot be realized while that signal is blocked.
With regard to the update to the question:
As far as I understand, when the process ignores a signal, it means
that the kernel won't send it to the process.
No, that's incorrect. SIG_IGN is a signal disposition. That's what the process does in response to a signal. It can't respond if the kernel doesn't send the signal in the first place.
Note that another option for signal disposition is for the process to run a custom signal handler function. It should be clearer that this is something that the process must do, not something that the kernel does for it.
This also means that it
won't keep it in the pending list.
It would mean that ignored signals never became pending, but your understanding of the semantics is incorrect.
So the question is, why if we
block+ignore from ahead, the kernel inserts the signal to its pending
list?
Because that's what the kernel does with signals. You can characterize it as what the kernel does with all signals, but those that aren't blocked don't stay pending very long.
In the main process I listen to SIGCHLD:
signal(SIGCHLD, &my_handler);
Then I fork(), execv() and let it run in background (/bin/cat for example).
When I try from terminal to send SIGSTOP to the child process, my_handler() gets called. But when I try to send SIGCONT to it, the the handler isn't called on macOS but it's executed on my Ubuntu.
Man:
SIGCHLD: child status has changed.
Am I missing something? Is it an expected behaviour? I wrote my app on Ubuntu and expected it to work on mac as well.
I tried with sigaction() as well, but with the same results.
Here's a sample code to demonstrate:
#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void my_handler(int signum)
{
printf("\t SIGCHLD received\n");
fflush(stdout);
}
void my_kill(pid_t pid, int signum)
{
printf("Sending %d\n", signum);
fflush(stdout);
kill(pid, signum);
printf("Sent %d\n\n", signum);
fflush(stdout);
}
int main()
{
pid_t pid;
char *cat_args[2] = {"/bin/cat", NULL};
signal(SIGCHLD, &my_handler);
pid = fork();
if (pid == 0)
{
execv("/bin/cat", cat_args);
}
else
{
my_kill(pid, SIGSTOP);
my_kill(pid, SIGCONT);
wait(NULL);
}
return 0;
}
With the output on macOS:
Sending 17
SIGCHLD received
Sent 17
Sending 19
Sent 19
That behavior is optional. An implementation need not generate a SIGCHLD upon continuation. The language used in POSIX.1-2008 (2016 edition) is "may" rather than "shall":
When a stopped process is continued, a SIGCHLD signal may be generated for its parent process, unless the parent process has set the SA_NOCLDSTOP flag.
- System Interfaces, 2.4.3 Signal Actions
...a SIGCHLD signal may be generated for the calling process whenever any of its stopped child processes are continued.
-
System Interfaces sigaction "Description"
Emphases added.
Am I missing something?
Probably not.
Is it an expected behaviour?
Probably yes.
OSX is based on 4.4 BSD, and this BSD simply does not support sending a SIGCHLD to the parent when the child continues. Earlier versions of Linux lacked this support as well.
I have 2 threads(thread1 and thread2). And I have signal disposition for SIGINT. Whenever SIGINT occurs thread 2 should handle the signal. For that I wrote below program
void sig_hand(int no) //signal handler
{
printf("handler executing...\n");
getchar();
}
void* thread1(void *arg1) //thread1
{
while(1) {
printf("thread1 active\n");
sleep(1);
}
}
void * thread2(void * arg2) //thread2
{
signal(2, sig_hand);
while(1) {
printf("thread2 active\n");
sleep(3);
}
}
int main()
{
pthread_t t1;
pthread_t t1;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
while(1);
}
I compiled and and run the program. for every 1 second "thread1 active" is printing and for every 3 seconds "thread2 active" is printing.
Now I generated SIGINT. But its printing "thread1 active" and "thread2 active" messages like above. Again I generated SIGINT, now for every 3 seconds only "thread2 active" message is printing. Again I generated SIGINT, now all threads are blocked.
So I understood, for first time main thread executing signal handler. For second time thread1 executing handler and lastly thread2 executing signal handler.
How I can write the code like whenever signal occurs, only thread2 have to execute my signal handler?
If you send a signal to a process, which thread in the process will handle this signal is undetermined.
According to pthread(7):
POSIX.1 also requires that threads share a range of other attributes (i.e., these attributes are process-wide rather than per-thread):
...
- signal dispositions
...
POSIX.1 distinguishes the notions of signals that are directed to the process as a whole and signals that are directed to individual threads. According to POSIX.1, a process-directed signal (sent using kill(2), for example) should be handled by a single, arbitrarily selected thread within the process.
If you want a dedicated thread in your process to handle some signals, here is an example from pthread_sigmask(3) shows you how to do it:
The program below blocks some signals in the main thread, and then creates a dedicated thread to fetch those signals via sigwait(3). The following shell session demonstrates its use:
$ ./a.out &
[1] 5423
$ kill -QUIT %1
Signal handling thread got signal 3
$ kill -USR1 %1
Signal handling thread got signal 10
$ kill -TERM %1
[1]+ Terminated ./a.out
Program source
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
/* Simple error handling functions */
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void *
sig_thread(void *arg)
{
sigset_t *set = arg;
int s, sig;
for (;;) {
s = sigwait(set, &sig);
if (s != 0)
handle_error_en(s, "sigwait");
printf("Signal handling thread got signal %d\n", sig);
}
}
int
main(int argc, char *argv[])
{
pthread_t thread;
sigset_t set;
int s;
/* Block SIGQUIT and SIGUSR1; other threads created by main()
will inherit a copy of the signal mask. */
sigemptyset(&set);
sigaddset(&set, SIGQUIT);
sigaddset(&set, SIGUSR1);
s = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (s != 0)
handle_error_en(s, "pthread_sigmask");
s = pthread_create(&thread, NULL, &sig_thread, (void *) &set);
if (s != 0)
handle_error_en(s, "pthread_create");
/* Main thread carries on to create other threads and/or do
other work */
pause(); /* Dummy pause so we can test program */
}
Read carefully signal(7) & pthread(7) & pthread_kill(3) & sigprocmask(2) & pthread_sigmask(3) -which you could use (to block SIGINT in unwanted threads). Read also a pthread tutorial.
Avoid using signals to communicate or synchronize between threads. Consider e.g. mutexes (pthread_mutex_lock etc...) and condition variables (pthread_cond_wait etc...).
If one of the threads runs an event loop (e.g. around poll(2)...) consider using signalfd(2).
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