multiple timers delivering signal to separate threads - c

I am developing an application wherein I have created a timer using timer_create function which upon expiration delivers a signal to a thread. As of now I am able to implement delivering a timer signal to a particular thread. The problem that I am facing now is if there is an other timer, how to deliver the signal to another separate thread(basically 1st timer signal to thread A and second timer signal to thread B). This is what I have written so far
static void *
sig_threadproc(void *thrarg)
{
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
/* endless loop to wait for and handle a signal repeatedly */
for (;;) {
int sig;
int error;
error = sigwait(&sigset, &sig);
if (error == 0) {
assert(sig == SIGALRM);
printf("got SIGALRM\n");
} else {
perror("sigwait");
}
}
return NULL;
}
static void
sig_alrm_handler(int signo)
{
/**
* dummy signal handler,
* the signal is actually handled in sig_threadproc()
**/
}
int
main(int argc, char *argv[])
{
sigset_t sigset;
struct sigaction sa;
pthread_t sig_thread;
struct itimerspec tspec;
timer_t timer_id;
/* mask SIGALRM in all threads by default */
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
sigprocmask(SIG_BLOCK, &sigset, NULL);
/* we need a signal handler.
* The default is to call abort() and
* setting SIG_IGN might cause the signal
* to not be delivered at all.
**/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_alrm_handler;
sigaction(SIGALRM, &sa, NULL);
/* create SIGALRM looper thread */
pthread_create(&sig_thread, NULL, sig_threadproc, NULL);
/* setup timer */
tspec.it_interval.tv_sec = 1;
tspec.it_interval.tv_nsec = 0;
tspec.it_value.tv_sec = 1;
tspec.it_value.tv_nsec = 0;
timer_create(CLOCK_REALTIME, NULL, &timer_id);
timer_settime(timer_id, 0, &tspec, NULL);
/**
* this might return early if usleep() is interrupted (by a signal)
* It should not happen, since SIGALRM is blocked on the
* main thread
**/
usleep(10000000);
return 0;
}

Do not use SIGALRM for real time timer, instead use SIGRTMIN. So you will create two timer, for the 1st one, set sigev_signo member of sevp argument to SIGRTMIN + 0, and set the the 2nd one's segev_signo to SIGRTMIN + 1. This means the when the 1st timer fires, your process will receive SIGRTMIN signal, when 2nd fires, you will receive SIGRTMIN + 1.
Then call pthread_sigmask in the 2 threads of your program, mask signal SIGRTMIN in your thread B, and mask SIGRTMIN + 1 in your thread A.
As a result, your thread A will only be notified when 1st timer fires, and thread B will get notification from 2nd timer.

Related

Signal Handler in a separate pthread using timer_create

I am developing a small application where in I want to call a function every 1 second. This is how I implemented
Timerspec.it_interval.tv_sec=1;
Timerspec.it_interval.tv_nsec=0;
Timerspec.it_value.tv_sec=1;
Timerspec.it_value.tv_nsec=0;
timer_t timerId;
struct sigaction sa;
sa.sa_handler=&TimerFn;
sa.sa_flags=0;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM,&sa,NULL);
timer_create(CLOCK_REALTIME,NULL,&timerId);
timer_settime(timerId,0,(const itimerspec*)Timerspec,NULL);
But I want to run the TimerFn function in a separate pthread(basically a timer for pthread function). Can somebody please tell how to do this?
If you can accept the creation of a new thread for every timer tick, you can use SIGEV_THREAD:
struct sigevent evp;
memset((void *)&evp, 0, sizeof(evp));
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = &sig_alrm_handler;
evp.sigev_signo = SIGALRM;
evp.sigev_value.sigval_ptr = (void *)this;
int ret = timer_create(CLOCK_REALTIME, &evp, &_timerId);
This will create a new thread for every tick.
If you need to handle the signal in a specific thread, a little more work is required:
static void *
sig_threadproc(void *thrarg)
{
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
/* endless loop to wait for and handle a signal repeatedly */
for (;;) {
int sig;
int error;
error = sigwait(&sigset, &sig);
if (error == 0) {
assert(sig == SIGALRM);
printf("got SIGALRM\n");
} else {
perror("sigwait");
}
}
return NULL;
}
static void
sig_alrm_handler(int signo)
{
/**
* dummy signal handler,
* the signal is actually handled in sig_threadproc()
**/
}
int
main(int argc, char *argv[])
{
sigset_t sigset;
struct sigaction sa;
pthread_t sig_thread;
struct itimerspec tspec;
timer_t timer_id;
/* mask SIGALRM in all threads by default */
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
sigprocmask(SIG_BLOCK, &sigset, NULL);
/* we need a signal handler.
* The default is to call abort() and
* setting SIG_IGN might cause the signal
* to not be delivered at all.
**/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_alrm_handler;
sigaction(SIGALRM, &sa, NULL);
/* create SIGALRM looper thread */
pthread_create(&sig_thread, NULL, sig_threadproc, NULL);
/* setup timer */
tspec.it_interval.tv_sec = 1;
tspec.it_interval.tv_nsec = 0;
tspec.it_value.tv_sec = 1;
tspec.it_value.tv_nsec = 0;
timer_create(CLOCK_REALTIME, NULL, &timer_id);
timer_settime(timer_id, 0, &tspec, NULL);
/**
* this might return early if usleep() is interrupted (by a signal)
* It should not happen, since SIGALRM is blocked on the
* main thread
**/
usleep(10000000);
return 0;
}
You might get away with selectively unblocking SIGARLM only in the signal handler thread, causing it the only thread to be eligible to handle that signal, but that may not be portable across systems.
Other versions (including use of pthread_cond_signal()) are already discussed in this answer.
If you just want to call a function every second, here's a simple solution:
#include <pthread.h>
#include <unistd.h>
void TimerFn(void)
{
...
}
void* timer(void* arg)
{
for (;;) {
TimerFn();
sleep(1);
}
return NULL;
}
...
pthread_t timerThread;
pthread_create(&timerThread, NULL, timer, NULL);
Is there some reason this wouldn't suffice?

Thread blocked waiting for a signal

sIn my application, I try to catch a specific signal which is SIGUSR1, I wrote the below code to do this issue, in which the application will create a thread for "init_signal_catcher".
The problem is when I run the code ,the program goes to sleep forever and does not respond to any signal even if it is SIGUSR1.
So could you please tell me what is the problem in my below code?
Note: The below can be run directly without having to create a thread, just replace the function name init_signal_catcher with main.
#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. */
sigprocmask(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;
}

sigwait() and signal handler

If I setup and signal handler for SIGABRT and meanwhile I have a thread that waits on sigwait() for SIGABRT to come (I have a blocked SIGABRT in other threads by pthread_sigmask).
So which one will be processed first ? Signal handler or sigwait() ?
[I am facing some issues that sigwait() is get blocked for ever. I am debugging it currently]
main()
{
sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT);
sigprocmask(SIG_BLOCK, &signal_set, NULL);
// Dont deliver SIGABORT while running this thread and it's kids.
pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
pthread_create(&tAbortWaitThread, NULL, WaitForAbortThread, NULL);
..
Create all other threads
...
}
static void* WaitForAbortThread(void* v)
{
sigset_t signal_set;
int stat;
int sig;
sigfillset( &signal_set);
pthread_sigmask( SIG_BLOCK, &signal_set, NULL ); // Dont want any signals
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT); // Add only SIGABRT
// This thread while executing , will handle the SIGABORT signal via signal handler.
pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
stat= sigwait( &signal_set, &sig ); // lets wait for signal handled in CatchAbort().
while (stat == -1)
{
stat= sigwait( &signal_set, &sig );
}
TellAllThreadsWeAreGoingDown();
sleep(10);
return null;
}
// Abort signal handler executed via sigaction().
static void CatchAbort(int i, siginfo_t* info, void* v)
{
sleep(20); // Dont return , hold on till the other threads are down.
}
Here at sigwait(), i will come to know that SIGABRT is received. I will tell other threads about it. Then will hold abort signal handler so that process is not terminated.
I wanted to know the interaction of sigwait() and the signal handler.
From sigwait() documentation :
The sigwait() function suspends execution of the calling thread until
one of the signals specified in the signal set becomes pending.
A pending signal means a blocked signal waiting to be delivered to one of the thread/process. Therefore, you need not to unblock the signal like you did with your pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL) call.
This should work :
static void* WaitForAbortThread(void* v){
sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT);
sigwait( &signal_set, &sig );
TellAllThreadsWeAreGoingDown();
sleep(10);
return null;
}
I got some information from this <link>
It says :
To allow a thread to wait for asynchronously generated signals, the threads library provides the sigwait subroutine. The sigwait subroutine blocks the calling thread until one of the awaited signals is sent to the process or to the thread. There must not be a signal handler installed on the awaited signal using the sigwait subroutine.
I will remove the sigaction() handler and try only sigwait().
From the code snippet you've posted, it seems you got the use of sigwait() wrong. AFAIU, you need WaitForAbortThread like below:
sigemptyset( &signal_set); // change it from sigfillset()
for (;;) {
stat = sigwait(&signal_set, &sig);
if (sig == SIGABRT) {
printf("here's sigbart.. do whatever you want.\n");
pthread_kill(tid, signal); // thread id and signal
}
}
I don't think pthread_sigmask() is really needed. Since you only want to handle SIGABRT, first init signal_set as empty then simply add SIGABRT, then jump into the infinite loop, sigwait will wait for the particular signal that you're looking for, you check the signal if it's SIGABRT, if yes - do whatever you want. NOTE the uses of pthread_kill(), use it to sent any signal to other threads specified via tid and the signal you want to sent, make sure you know the tid of other threads you want to sent signal. Hope this will help!
I know this question is about a year old, but I often use a pattern, which solves exactly this issue using pthreads and signals. It is a little length but takes care of any issues I am aware of.
I recently used in combination with a library wrapped with SWIG and called from within Python. An annoying issue was that my IRQ thread waiting for SIGINT using sigwait never received the SIGINT signal. The same library worked perfectly when called from Matlab, which didn't capture the SIGINT signal.
The solution was to install a signal handler
#define _NTHREADS 8
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#include <linux/unistd.h>
#include <sys/signal.h>
#include <sys/syscall.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h> // strerror
#define CallErr(fun, arg) { if ((fun arg)<0) \
FailErr(#fun) }
#define CallErrExit(fun, arg, ret) { if ((fun arg)<0) \
FailErrExit(#fun,ret) }
#define FailErrExit(msg,ret) { \
(void)fprintf(stderr, "FAILED: %s(errno=%d strerror=%s)\n", \
msg, errno, strerror(errno)); \
(void)fflush(stderr); \
return ret; }
#define FailErr(msg) { \
(void)fprintf(stderr, "FAILED: %s(errno=%d strerror=%s)\n", \
msg, errno, strerror(errno)); \
(void)fflush(stderr);}
typedef struct thread_arg {
int cpu_id;
int thread_id;
} thread_arg_t;
static jmp_buf jmp_env;
static struct sigaction act;
static struct sigaction oact;
size_t exitnow = 0;
pthread_mutex_t exit_mutex;
pthread_attr_t attr;
pthread_t pids[_NTHREADS];
pid_t tids[_NTHREADS+1];
static volatile int status[_NTHREADS]; // 0: suspended, 1: interrupted, 2: success
sigset_t mask;
static pid_t gettid( void );
static void *thread_function(void *arg);
static void signalHandler(int);
int main() {
cpu_set_t cpuset;
int nproc;
int i;
thread_arg_t thread_args[_NTHREADS];
int id;
CPU_ZERO( &cpuset );
CallErr(sched_getaffinity,
(gettid(), sizeof( cpu_set_t ), &cpuset));
nproc = CPU_COUNT(&cpuset);
for (i=0 ; i < _NTHREADS ; i++) {
thread_args[i].cpu_id = i % nproc;
thread_args[i].thread_id = i;
status[i] = 0;
}
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_mutex_init(&exit_mutex, NULL);
// We pray for no locks on buffers and setbuf will work, if not we
// need to use filelock() on on FILE* access, tricky
setbuf(stdout, NULL);
setbuf(stderr, NULL);
act.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT;
act.sa_handler = signalHandler;
sigemptyset(&act.sa_mask);
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
if (setjmp(jmp_env)) {
if (gettid()==tids[0]) {
// Main Thread
printf("main thread: waiting for clients to terminate\n");
for (i = 0; i < _NTHREADS; i++) {
CallErr(pthread_join, (pids[i], NULL));
if (status[i] == 1)
printf("thread %d: terminated\n",i+1);
}
// On linux this can be done immediate after creation
CallErr(pthread_attr_destroy, (&attr));
CallErr(pthread_mutex_destroy, (&exit_mutex));
return 0;
}
else {
// Should never happen
printf("worker thread received signal");
}
return -1;
}
// Install handler
CallErr(sigaction, (SIGINT, &act, &oact));
// Block SIGINT
CallErr(pthread_sigmask, (SIG_BLOCK, &mask, NULL));
tids[0] = gettid();
srand ( time(NULL) );
for (i = 0; i < _NTHREADS; i++) {
// Inherits main threads signal handler, they are blocking
CallErr(pthread_create,
(&pids[i], &attr, thread_function,
(void *)&thread_args[i]));
}
if (pthread_sigmask(SIG_UNBLOCK, &mask, NULL)) {
fprintf(stderr, "main thread: can't block SIGINT");
}
printf("Infinite loop started - CTRL-C to exit\n");
for (i = 0; i < _NTHREADS; i++) {
CallErr(pthread_join, (pids[i], NULL));
//printf("%d\n",status[i]);
if (status[i] == 2)
printf("thread %d: finished succesfully\n",i+1);
}
// Clean up and exit
CallErr(pthread_attr_destroy, (&attr));
CallErr(pthread_mutex_destroy, (&exit_mutex));
return 0;
}
static void signalHandler(int sig) {
int i;
pthread_t id;
id = pthread_self();
for (i = 0; i < _NTHREADS; i++)
if (pids[i] == id) {
// Exits if worker thread
printf("Worker thread caught signal");
break;
}
if (sig==2) {
sigaction(SIGINT, &oact, &act);
}
pthread_mutex_lock(&exit_mutex);
if (!exitnow)
exitnow = 1;
pthread_mutex_unlock(&exit_mutex);
longjmp(jmp_env, 1);
}
void *thread_function(void *arg) {
cpu_set_t set;
thread_arg_t* threadarg;
int thread_id;
threadarg = (thread_arg_t*) arg;
thread_id = threadarg->thread_id+1;
tids[thread_id] = gettid();
CPU_ZERO( &set );
CPU_SET( threadarg->cpu_id, &set );
CallErrExit(sched_setaffinity, (gettid(), sizeof(cpu_set_t), &set ),
NULL);
int k = 8;
// While loop waiting for exit condition
while (k>0) {
sleep(rand() % 3);
pthread_mutex_lock(&exit_mutex);
if (exitnow) {
status[threadarg->thread_id] = 1;
pthread_mutex_unlock(&exit_mutex);
pthread_exit(NULL);
}
pthread_mutex_unlock(&exit_mutex);
k--;
}
status[threadarg->thread_id] = 2;
pthread_exit(NULL);
}
static pid_t gettid( void ) {
pid_t pid;
CallErr(pid = syscall, (__NR_gettid));
return pid;
}
I run serveral tests and the conbinations and results are:
For all test cases, I register a signal handler by calling sigaction in the main thread.
main thread block target signal, thread A unblock target signal by calling pthread_sigmask, thread A sleep, send target signal.
result: signal handler is executed in thread A.
main thread block target signal, thread A unblock target signal by calling pthread_sigmask, thread A calls sigwait, send target signal.
result: sigwait is executed.
main thread does not block target signal, thread A does not block target signal, thread A calls sigwait, send target signal.
result: main thread is chosen and the registered signal handler is executed in the main thread.
As you can see, conbination 1 and 2 are easy to understand and conclude.
It is:
If a signal is blocked by a thread, then the process-wide signal handler registered by sigaction just can't catch or even know it.
If a signal is not blocked, and it's sent before calling sigwait, the process-wide signal handler wins. And that's why APUE the books require us to block the target signal before calling sigwait. Here I use sleep in thread A to simulate a long "window time".
If a signal is not blocked, and it's sent when sigwait has already been waiting, sigwait wins.
But you should notice that for test case 1 and 2, main thread is designed to block the target signal.
At last for test case 3, when main thread is not blocked the target signal, and sigwait in thread A is also waiting, the signal handler is executed in the main thread.
I believe the behaviour of test case 3 is what APUE talks about:
From APUE ยง12.8:
If a signal is being caught (the process has established a signal
handler by using sigaction, for example) and a thread is waiting for
the same signal in a call to sigwait, it is left up to the
implementation to decide which way to deliver the signal. The
implementation could either allow sigwait to return or invoke the
signal handler, but not both.
Above all, if you want to accomplish one thread <-> one signal model, you should:
block all signals in the main thread with pthread_sigmask (subsequent thread created in main thread inheris the signal mask)
create threads and call sigwait(target_signal) with target signal.
test code
#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
FILE* file;
void* threadA(void* argv){
fprintf(file, "%ld\n", pthread_self());
sigset_t m;
sigemptyset(&m);
sigaddset(&m, SIGUSR1);
int signo;
int err;
// sigset_t q;
// sigemptyset(&q);
// pthread_sigmask(SIG_SETMASK, &q, NULL);
// sleep(50);
fprintf(file, "1\n");
err = sigwait(&m, &signo);
if (err != 0){
fprintf(file, "sigwait error\n");
exit(1);
}
switch (signo)
{
case SIGUSR1:
fprintf(file, "SIGUSR1 received\n");
break;
default:
fprintf(file, "?\n");
break;
}
fprintf(file, "2\n");
}
void hello(int signo){
fprintf(file, "%ld\n", pthread_self());
fprintf(file, "hello\n");
}
int main(){
file = fopen("daemon", "wb");
setbuf(file, NULL);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = hello;
sigaction(SIGUSR1, &sa, NULL);
sigset_t n;
sigemptyset(&n);
sigaddset(&n, SIGUSR1);
// pthread_sigmask(SIG_BLOCK, &n, NULL);
pthread_t pid;
int err;
err = pthread_create(&pid, NULL, threadA, NULL);
if(err != 0){
fprintf(file, "create thread error\n");
exit(1);
}
pause();
fprintf(file, "after pause\n");
fclose(file);
return 0;
}
run with ./a.out & (run in the background), and use kill -SIGUSR1 pid to test. Do not use raise. raise, sleep, pause are thread-wide.

Is it valid to have multiple signal handlers for same signal?

I have two shared libraries linked to my test application. Both of the libraries have signal handlers for SIGINT.
Is it valid to have multiple signal handlers for same signal? Which order the handlers will execute when I generate a SIGINT signal?
As said by others, only one signal handler can be set, which is the last one. You would then have to manage calling two functions yourself. The sigaction function can return the previously installed signal handler which you can call yourself.
Something like this (untested code):
/* other signal handlers */
static void (*lib1_sighandler)(int) = NULL;
static void (*lib2_sighandler)(int) = NULL;
static void aggregate_handler(int signum)
{
/* your own cleanup */
if (lib1_sighandler)
lib1_sighandler(signum);
if (lib2_sighandler)
lib2_sighandler(signum);
}
... (later in main)
struct sigaction sa;
struct sigaction old;
lib1_init(...);
/* retrieve lib1's sig handler */
sigaction(SIGINT, NULL, &old);
lib1_sighandler = old.sa_handler;
lib2_init(...);
/* retrieve lib2's sig handler */
sigaction(SIGINT, NULL, &old);
lib2_sighandler = old.sa_handler;
/* set our own sig handler */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = aggregate_handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
Only one signal handler can be installed per signal. Only the latest installed handler will be active.
we can handle multiple signal with single signal handler but
but its is not possible to have multiple signal handler for same signal.
void sig_handler(int signo)
{
if (signo == SIGINT)
printf("received SIGINT 1\n");
}
void sig(int signo)
{
if (signo == SIGINT)
printf("received SIGINT 2\n");
}
int main(void)
{
if(signal(SIGINT, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
if (signal(SIGINT, sig) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
// A long long wait so that we can easily issue a signal to this process
while(1)
sleep(1);
return 0;
}
if u try to run this code u will find that the last assigned signal handler is set for that signal.
i think it is not possible to have a multiple signal handler for same signal.
As you could see in the man page for sigaction, the new signal handler replaces the old one and the old one is returned.
If you have two unused signals (say SIGUSR1 and SIGUSR2), assign those signals the two signal handlers for SIGINT. Then you may write your own Signal Handler for SIGINT and from that, you may raise the needed unused signal as per you want.
Shabaz hit the nail on the head. However, if you're looking for something all your libraries could use (provided you have access to the source code), you could do something along the following lines:
linked_list* sigint_handlers = NULL;
void sighand_init(sighand_config_t* config) {
struct sigaction action;
memset(&signalaction, 0, sizeof(signalaction));
action.sa_handler = &sighand_main;
// Order is important, in case we get a signal during start-up
sigint_handlers = linked_list_new();
sigaction(SIGINT, &action);
}
void sighand_main(int signum) {
if (signum == SIGINT) {
linked_list_node* node = linked_list_head(sigint_handlers);
while ((node = node->next) != NULL) {
node->object(signum);
}
if (sighand_config.exitonint) {
app_exit(0);
}
}
}
void sighand_add_int_handler(void (*handler)(int)) {
if (handler == NULL) return;
linked_list_add(sigint_handlers, handler);
}
void sighand_destroy() {
...
linked_list_destroy(signint_handlers);
...
}
Or, you could use this yourself, and after loading each library, get the handler and later call add_handler. Something along the lines of:
loadlibrary(lib1.so);
sigaction1 = signalget(SIGINT);
loadlibrary(lib2.so);
sigaction2 = signalget(SIGINT);
sighand_init(...);
sighand_add_int_handler(sigaction1.sa_handler);
sighand_add_int_handler(sigaction2.sa_handler);
Just some thoughts,
Anthony

Using SIGUSR1 and SIGUSR2 as signals in pthread_kill()

I would like to use SIGUSR1 and SIGUSR2 as arguments to pthread_kill() to suspend the execution of the running thread(i.e thread sends signal to itself) and resuming a suspended thread by a peer thread when a condition is met.
Would be gratefull for any pointers like example code or views about it.
Thanks
Signalling is used as the following example. However, in your case though, you need Condition variables
https://computing.llnl.gov/tutorials/pthreads/#ConVarSignal has an example
pthread_cond_wait (condition,mutex)
pthread_cond_signal (condition)
pthread_cond_broadcast (condition)
Example with the correct usage of the signals with pthread_kill() is demonstrated below
/* ptsig.c
This program illustrates the use of signals in threads.
Three threads including the main thread.
main thread
a. Set up a signal mask to block all signals.
b. Set up signal handlers for SIGINT and SIGUSR1.
c. Create thread_1, detached.
d. Create thread_2, nondetached.
e. Send SIGINT & SIGUSR1 to thread_1.
f. Quit.
thread_1
a. Unblock all to embrace all signals.
b. Wait for signals.
c. Send SIGINT and SIGUSR1 to thread_2
d. Wait for thread_2 to terminate
e. Print thread_2 return status.
f. Quit
thread_2
a. Unblock SIGUSR1 -- all others blocked due to inheritance.
b. Wait for signals.
c. Quit
Note: There is hardly any error checking in this example -- not a good
idea, but to make the program a bit more easier to explain.
To compile: gcc ptsig.c -lpthread
Sam Hsu (11/19/10)
*/
#define _POSIX_C_SOURCE 199506L
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
pthread_t tid2;
static void int_handler(int signo), usr1_handler(int signo);
void millisleep(int milliseconds)
{
usleep(milliseconds * 1000);
}
main()
{
pthread_t tid1;
pthread_attr_t attr_obj; /* a thread attribute variable */
void *thread_1(void *), *thread_2(void *);
sigset_t sigmask;
struct sigaction action;
/* set up signal mask to block all in main thread */
sigfillset(&sigmask); /* to turn on all bits */
pthread_sigmask(SIG_BLOCK, &sigmask, (sigset_t *)0);
/* set up signal handlers for SIGINT & SIGUSR1 */
action.sa_flags = 0;
action.sa_handler = int_handler;
sigaction(SIGINT, &action, (struct sigaction *)0);
action.sa_handler = usr1_handler;
sigaction(SIGUSR1, &action, (struct sigaction *)0);
pthread_attr_init(&attr_obj); /* init it to default */
pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_DETACHED);
pthread_create(&tid1, &attr_obj, thread_1, (void *)NULL);
printf("TID(%u) created\n", (unsigned int)tid1);
pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_JOINABLE);
pthread_create(&tid2, &attr_obj, thread_2, (void *)NULL);
printf("TID(%u) created\n", (unsigned int)tid2);
millisleep(1000); /* for some reason a sleep is needed here */
printf("main(%u) sending SIGINT to TID(%u)\n", (unsigned int)pthread_self(), (unsigned int)tid1);
pthread_kill(tid1, SIGINT); /* not blocked by tid1 */
printf("main(%u) sending SIGUSR1 to TID(%u)\n", (unsigned int)pthread_self(), (unsigned int)tid1);
pthread_kill(tid1, SIGUSR1); /* not blocked by tid1 */
printf("main(%u) is terminating\n", (unsigned int)pthread_self());
pthread_exit((void *)NULL); /* will not terminate process */
} /* main */
void *thread_1(void *dummy)
{
int sig, status, *status_ptr = &status;
sigset_t sigmask;
sigfillset(&sigmask); /* will unblock all signals */
pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0);
sigwait(&sigmask, &sig);
switch(sig) {
case SIGINT:
int_handler(sig);
break;
default:
break;
}
printf("TID(%u) sending SIGINT to %u\n", (unsigned int)pthread_self(), (unsigned int)tid2);
pthread_kill(tid2, SIGINT); /* blocked by tid2 */
printf("TID(%u) sending SIGUSR1 to %u\n", (unsigned int)pthread_self(), (unsigned int)tid2);
pthread_kill(tid2, SIGUSR1); /* not blocked by tid2 */
pthread_join(tid2, (void **)status_ptr);
printf("TID(%u) exit status = %d\n", (unsigned int)tid2, status);
printf("TID(%u) is terminating\n", (unsigned int)pthread_self());
pthread_exit((void *)NULL); /* calling thread will terminate */
} /* thread_1 */
void *thread_2(void *dummy)
{
int sig;
sigset_t sigmask;
sigemptyset(&sigmask); /* to zero out all bits */
sigaddset(&sigmask, SIGUSR1); /* to unblock SIGUSR1 */
pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0);
sigwait(&sigmask, &sig);
switch(sig) {
case SIGUSR1:
usr1_handler(sig);
break;
default:
break;
}
printf("TID(%u) is terminating\n", (unsigned int)pthread_self());
pthread_exit((void *)NULL); /* calling thread will terminate */
} /* thread_2 */
static void int_handler(int dummy)
{
printf("SIGINT received by TID(%u)\n", (unsigned int)pthread_self());
} /* int_handler */
static void usr1_handler(int dummy)
{
printf("SIGUSR1 received by TID(%u)\n", (unsigned int)pthread_self());
} /* usr1_handler */
pthread_cancel() is safer relative to pthread_kill()
An example of pthread_cancel() below
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void *
thread_func(void *ignored_argument)
{
int s;
s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (s != 0)
handle_error_en(s, "pthread_setcancelstate");
while (1) {
printf("sleeping\n");
sleep(1); /* Should get canceled while we sleep */
}
/* sleep() is a cancellation point */
/* Should never get here */
printf("thread_func(): not canceled!\n");
return NULL;
}
int
main(void)
{
pthread_t thr;
void *res;
int s;
/* Start a thread and then send it a cancellation request */
s = pthread_create(&thr, NULL, &thread_func, NULL);
if (s != 0)
handle_error_en(s, "pthread_create");
sleep(10); /* Give thread a chance to get started */
printf("main(): sending cancellation request\n");
s = pthread_cancel(thr);
if (s != 0)
handle_error_en(s, "pthread_cancel");
/* Join with thread to see what its exit status was */
s = pthread_join(thr, &res);
if (s != 0)
handle_error_en(s, "pthread_join");
if (res == PTHREAD_CANCELED)
printf("main(): thread was canceled\n");
else
printf("main(): thread wasn't canceled (shouldn't happen!)\n");
exit(EXIT_SUCCESS);
}
While I agree with Nemo, there are some valid use cases for suspending threads via signals. The susp.c code in PWPT is certainly a good base but you can also find it used in GLIBC. You might also wish to break the thread out of a blocking-IO system call (see this question) or interrupt a semaphore wait (see this question).

Resources