Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Example of handling signals in multi-threaded process

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;
}
like image 664
IoT Avatar asked Oct 20 '22 09:10

IoT


1 Answers

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.

like image 90
pilcrow Avatar answered Oct 23 '22 11:10

pilcrow