简体   繁体   中英

Signal handling in secondary thread

I am writing a program to demonstrate signal handling in a secondary thread. In my program, main thread spawns 10 thread and each thread calls sigwait to wait for signal. But in my case, it is main thread which is handling signa. Code is given below:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <errno.h>

volatile sig_atomic_t cont = 1;

volatile sig_atomic_t wsig = 0;
volatile sig_atomic_t wtid = 0;

int GetCurrentThreadId()
{
    return syscall(__NR_gettid);
}

void Segv1(int, siginfo_t *, void *)
{
    //printf("SIGSEGV signal on illegal memory access handled by thread: %d\n", GetCurrentThreadId());
    wtid = GetCurrentThreadId();
    wsig = SIGSEGV;
    _exit(SIGSEGV);
}

void Fpe1(int , siginfo_t *, void *)
{
    wtid = GetCurrentThreadId();
    wsig = SIGFPE;
    _exit(SIGFPE);
}

void User1(int, siginfo_t *, void *)
{
    wtid = GetCurrentThreadId();
    wsig = SIGUSR1;
}


void* ThreadFunc (void*)
{
    sigset_t sigs;
    sigemptyset(&sigs);
    sigaddset(&sigs, SIGUSR1);
    sigaddset(&sigs, SIGSEGV);
    sigaddset(&sigs, SIGFPE);
    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
    //printf("Thread: %d starts\n", GetCurrentThreadId());
    while(cont) {
        //printf("Thread: %d enters into loop\n", GetCurrentThreadId());
        //int s = sigwaitinfo(&sigs, NULL);
        //int sig;
        //int s = sigwait(&sigs, &sig);
        //printf("A signal\n");
        /*if(s==0) {
            sigaddset(&sigs, sig);
            printf("Signal %d handled from thread: %d\n", sig, GetCurrentThreadId());
            if(sig==SIGFPE||sig==SIGSEGV)
                return NULL;
        } else {
            printf("sigwaitinfo failed with %d\n", s);
            break;
        }*/
        int s = sigsuspend(&sigs);
        switch(wsig) {
            case SIGSEGV:
                printf("Segmenation fault in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
                exit(1);
                break;
            case SIGFPE:
                printf("Floating point exception in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
                exit(1);
                break;
            case SIGUSR1:
                printf("User 1 signal in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
                break;
            default:
                printf("Unhandled signal: %d in thread: %d Current thread id: %d\n", wsig, wtid, GetCurrentThreadId());
                break;
        }
    }

    printf("Thread: %d ends\n", GetCurrentThreadId());

    return NULL;
}

int main()
{
    printf("My PID: %d\n", getpid());
    printf("SIGSEGV: %d\nSIGFPE: %d\nSIGUSR1: %d\n", SIGSEGV, SIGFPE, SIGUSR1);
    //Create a thread for signal
    struct sigaction act;
    memset(&act, 0, sizeof act);
    act.sa_sigaction = User1;
    act.sa_flags    = SA_SIGINFO;

    //Set Handler for SIGUSR1 signal.
    if(sigaction(SIGUSR1, &act, NULL)<0) {
        fprintf(stderr, "sigaction failed\n");
        return 1;
    }

    //Set handler for SIGSEGV signal.
    act.sa_sigaction    = Segv1;
    sigaction(SIGSEGV, &act, NULL);

    //Set handler for SIGFPE (floating point exception) signal.
    act.sa_sigaction    = Fpe1;
    sigaction(SIGFPE, &act, NULL);

    sigset_t sset;
    sigemptyset(&sset);
    sigaddset(&sset, SIGUSR1);
    sigaddset(&sset, SIGSEGV);
    sigaddset(&sset, SIGFPE);
    //pthread_sigmask(SIG_BLOCK, &sset, NULL);
    const int numthreads = 10;
    pthread_t tid[numthreads];
    for(int i=0;i<numthreads;++i)
        pthread_create(&tid[i], NULL, ThreadFunc, NULL);

    sleep(numthreads/2);

    int sleepval = 15;
    int pid = fork();
    if(pid) {
        while(sleepval) {
            sleepval = sleep(sleepval);
            //It might get interrupted with signal.
            switch(wsig) {
                case SIGSEGV:
                    printf("Segmenation fault in thread: %d\n", wtid);
                    exit(1);
                    break;
                case SIGFPE:
                    printf("Floating point exception in thread: %d\n", wtid);
                    exit(1);
                    break;
                case SIGUSR1:
                    printf("User 1 signal in thread: %d\n", wtid);
                    break;
                default:
                    printf("Unhandled signal: %d in thread: %d\n", wsig, wtid);
                    break;
            }
        }

    } else {
        for(int i=0;i<10;++i) {
            kill(getppid(), SIGUSR1);
            //If sleep is not used, signal SIGUSR1 will be handled one time in parent
            //as other signals will be ignored while SIGUSR1 is being handled.
            sleep(1);
        }
        return 0;
    }

    int * a = 0;
    //*a = 1;
    int c=0;
    //c = 0;
    int b = 1/c; //send SIGFPE signal.
    return 0;
}

Is there any rule of picking up the thread for signal handling on Linux and Mac OS X? What should I do so that signal got handled in secondary thread?

In the above program, I am not able to handle the signal in secondary thread. What is wrong with it?

I suggest you should SIG_BLOCK needed signals in main thread (commented out now) and SIG_UNBLOCK them in other threads (SIG_BLOCK now). Or you can spawn you threads and after it SIG_BLOCK in main thread, as spawned threads got their sigmask from parent. And sigsuspend's parameter is not the signals you want to wake up on, but vice versa.

Is there any rule of picking up the thread for signal handling on Linux and Mac OS X?

There is, see Signal Generation and Delivery :

During the time between the generation of a signal and its delivery or acceptance, the signal is said to be pending . Ordinarily, this interval cannot be detected by an application. However, a signal can be blocked from delivery to a thread. If the action associated with a blocked signal is anything other than to ignore the signal, and if that signal is generated for the thread, the signal shall remain pending until it is unblocked, it is accepted when it is selected and returned by a call to the sigwait() function, or the action associated with it is set to ignore the signal. Signals generated for the process shall be delivered to exactly one of those threads within the process which is in a call to a sigwait() function selecting that signal or has not blocked delivery of the signal. If there are no threads in a call to a sigwait() function selecting that signal, and if all threads within the process block delivery of the signal, the signal shall remain pending on the process until a thread calls a sigwait() function selecting that signal, a thread unblocks delivery of the signal, or the action associated with the signal is set to ignore the signal. If the action associated with a blocked signal is to ignore the signal and if that signal is generated for the process, it is unspecified whether the signal is discarded immediately upon generation or remains pending.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM