5

Can anyone give me the steps or even the code for the following situation:

A process which contains multiple thread, and of these threads is responsible of catching a user defined signal SIGUSR1. Only this thread should be capable of receiving this signal, and upon the reception of this signal I do some stuff.

In my situation the signal is being sent by a Kernel Module to my Process ID. Then it is the responsibility of my process to deliver it to the correct listening thread, which has also established the Signal Handler i.e. the signal handler is not in the main thread.

I already did some code which runs for a single-thread process, but I have a problem in running it in multiple thread environment.

I am running my code on Linux Ubuntu 12.04.3 with Kernel Version 3.8.0-29. And for the creation of the process I am mixing between Boost Threads and POSIX threads API.

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <string.h>

/* Value of the last signal caught */
volatile sig_atomic_t sig_value;

static void sig_handler(const int sig_number, siginfo_t *sig_info, void *context)
{
if (sig_number == SIGSEGV)
{
    error_sys("Error at address 0x%lx", (long)sig_info->si_addr);
    exit(-1);
}
sig_value = sig_number;
}


int init_signal_catcher()
{
struct sigaction sig_action; /* Structure describing the action to be taken when asignal arrives.  */

sigset_t oldmask;  /* Signal mask before signal disposition change.      */
sigset_t newmask;  /* Signal mask after signal disposition change.       */
sigset_t zeromask; /* Signal mask to unblock all signal while suspended. */

/* Define signal mask and install signal handlers */
memset(&sig_action, 0, sizeof(struct sigaction));

sig_action.sa_flags = SA_SIGINFO;
sig_action.sa_sigaction = sig_handler;

/* Examine and change a signal action. */
sigaction(SIGHUP, &sig_action, NULL);
sigaction(SIGINT, &sig_action, NULL);
sigaction(SIGTERM, &sig_action, NULL);
sigaction(SIGSEGV, &sig_action, NULL);
sigaction(SIGUSR1, &sig_action, NULL);

    /* Block SIGHUP, SIGINT, SIGTERM, SIGSEGV and SIGUSR1 signals. */
sigemptyset(&newmask);
sigaddset(&newmask, SIGHUP);
sigaddset(&newmask, SIGINT);
sigaddset(&newmask, SIGTERM);
sigaddset(&newmask, SIGSEGV);
sigaddset(&newmask, SIGUSR1);

/* Examine and change blocked signals. */
pthread_sigmask(SIG_BLOCK, &newmask, &oldmask);

/* Initialize the empty signal set. */
sigemptyset(&zeromask);
sig_value = 0;

while ((sig_value != SIGINT) && (sig_value != SIGTERM))
{
    sig_value = 0;

    /*
     * Go to sleep (unblocking all signals) until a signal is catched.
     * On return from sleep, the signals SIGHUP, SIGINT, SIGTERM and
         * SIGUSR1 are again blocked.
     */
        printf("Suspending on %lu mask.", zeromask);

        // Wait for a signal.
    sigsuspend(&zeromask);

    switch(sig_value)
    {
                printf("Caught Signal %d", sig_value);
        case SIGUSR1:
                    printf("Caught SIGUSR1");
                    break;
    }
}

return 0;
}
IoT
  • 607
  • 1
  • 11
  • 23
  • possible duplicate of [POSIX threads and signals](http://stackoverflow.com/questions/2575106/posix-threads-and-signals) – pilcrow Apr 22 '14 at 17:02
  • I checked your link and it doesn't explain enough about signals with multi-thread. – IoT Apr 22 '14 at 19:12
  • 2
    I usually use Boost Asio to handle signals see e.g. this answer: http://stackoverflow.com/a/22545891/85371 – sehe Apr 22 '14 at 21:47
  • You know, you have about 70% of this done already. What have you tried in the last two days? – Duck Apr 22 '14 at 22:04
  • I have tried exactly like what you gave me before, to Block the interesting signals in the main thread and suspend waiting for a signal in the signal handler thread. But it does not work with me at all, the program does not catch any signal from the Kernel Module. – IoT Apr 22 '14 at 22:09
  • 1
    @sehe I want to thank you a lot for your answer, your solution worked perfectly with me :). Thanks for your continuous support – IoT Apr 22 '14 at 22:35
  • @HA-AS Cheers. I appreciate the feedback. On SO it's customary to **[vote (see help)](http://stackoverflow.com/help/why-vote)**, and "thank-you" comments are **[generally avoided](http://stackoverflow.com/help/someone-answers)** – sehe Apr 22 '14 at 22:49
  • Well don't leave us hanging, what solution worked? Sehe's answer below or the Boost link? – Duck Apr 22 '14 at 22:54
  • @Duck sehe answer which is the Boost link. The Boost libraries were more easy to deal with [Boost ASIO Signal](http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/overview/signals.html) – IoT Apr 22 '14 at 22:56

3 Answers3

2

The signals need to be blocked in every thread. The safest way to do this is to block them in the first thread before any others are created. Then a single, specially chosen thread can call sigsuspend() and only that thread will execute the signal handlers.

void *signal_handling_thread(void *whatever) {
  sig_value := 0
  while (sig_value not in (SIGTERM, SIGINT)) {
    sigsuspend(empty_mask)
    ...
  }
  ...
}

int main(int argc, char **argv) {
  block_relevant_signals();               // SIG_BLOCK HUP, TERM, USR1, etc.
  catch_relevant_signals();               // SA_SIGINFO ...

  spawn_signal_handling_thread();         // spawned with relevant signals blocked

  for (int i = 0; i < NUM_WORKERS; i++) {
    spawn_worker_thread();                // spawned with relevant signals blocked
  }
  ...
}

It's time to refactor your code to break apart concerns — do global process attribute manipulation in one place, signal-specific reaction in another, etc.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
1

In your signal handler, you are calling exit(-1). exit(-1) is not asynchronous signal-handler safe. Use _exit(-1) instead.

The difference between the two functions is that exit() calls all of the registered atexit() routines (including C++ static destructors). Before exit() does that shutdown step, it uses pthread_mutex_lock() to ensure a thread-safe shutdown. If the lock happens to be held by another thread, your program will deadlock.

_exit() skips those atexit routines and terminates the process.

I'm not familiar with error_sys(), but it looks like it ends up using printf()/fprintf(). Those routines also tend to be protected by mutexes.

0

Here is an example to organize which thread gets which signal using pthread_sigmask: http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html

JayS
  • 2,057
  • 24
  • 16