Reputation: 231
I am working with the following example (which is based on the example in the manpage for pthread_sigmask in linux):
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
/* Simple error handling functions */
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void * silly_worker(void *arg)
{
for(int index=0,max=5; index<max; ++index) {
printf("waiting %d of %d\n",index,max);
sleep(1);
}
puts("Finished waiting. Here comes the SIGSEGV");
strcpy(NULL,"this will crash");
}
static void *
sig_thread(void *arg)
{
sigset_t *set = (sigset_t *) 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;
pthread_t thread2;
sigset_t set;
int s;
/* Block SIGINT; other threads created by main() will inherit
a copy of the signal mask. */
sigemptyset(&set);
sigaddset(&set, SIGQUIT);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGSEGV);
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 */
s = pthread_create(&thread2, NULL, &silly_worker, (void *) &set);
if (s != 0)
handle_error_en(s, "pthread_create");
pause(); /* Dummy pause so we can test program */
}
According to the man page, this should catch the SIGSEGV generated by the silly_worker thread. But it doesn't. In fact I'm not sure what agency is getting the signal at all. When the program runs, I get the following output:
waiting 0 of 5
waiting 1 of 5
waiting 2 of 5
waiting 3 of 5
waiting 4 of 5
Finished waiting. Here comes the SIGSEGV
Segmentation fault
You can see that the signal handler doesn't output a "Segmentation fault" string, so it must be coming from the default handler. If default, then it kind of spoils the purpose of the example - to set a signal handler and capture signals and do something with them.
I can find a lot of examples of handlers, but none of them work for this situation: none of them demonstrate a thread which causes a really obvious SIGSEGV, and catches and reports the error in its custom handler.
The question remains: how does one get a custom signal handler to get the signal from this SIGSEGV'ing thread?
Upvotes: 2
Views: 2910
Reputation: 215259
The SIGSEGV
from invalid memory accesses (as opposed to a "fake" one sent by kill
or sigqueue
) is sent to the thread that performed the invalid memory access, not to the whole process. Thus you cannot have a dedicated segfault-handler thread. If you want to handle it, you must handle it in the thread where it happened. (The reason you're seeing the shell print Segmentation fault
is because, when SIGSEGV
is blocked in the thread and a segfault occurs, the kernel performs the default action of killing the process. Actually it's UB per POSIX, but this is how Linux handles the UB.)
Note, however, that you could have the signal handler for SIGSEGV
trigger an action by a dedicated thread. An ugly way to do this would be with another signal, which you could send (along with an argument) via sigqueue
. The cleaner way (in my opinion, at least) to do it would be to have the SIGSEGV
handler use sem_post
, which is async-signal-safe and can be used to wake another thread waiting on a semaphore.
Upvotes: 1