I am trying to make a program that suspends its execution until a signal arrives. Then, after the signal arrives I just want my code to continue its execution from where it was. I don't want it to execute a function handler or whatsoever. Is there a simple way of doing this? I have been struggling for a week or so, reading here and there, and didn't manage to get a fully operative code.
In particular, I want the main program to create a thread that waits for some particular event to happen (e.g., a user has input some data to stdin). Meanwhile, the main program is doing something but at some point it suspends its execution until it receives a signal.
The signal may come from the thread because it has detected the event or it may be due to a timeout because I don't want it to wait for ever.
I have made some code but it does not work as expected...
/*
* This code SHOULD start a thread that gets messages from stdin.
* If the message is a "quit", the thread exits. Otherwise it raises
* a signal that should be caught by the main program.
* The main program simply waits for the message unless a timer of
* 5.5 seconds expires before receiving the signal from the thread.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include <signal.h>
#define BSIZE 100 /* Buffer size */
sigset_t mask;
pthread_t tid;
//struct itimerval timervalue;
int milisec = 5500; /* Timeout: 5,5 seconds */
int end = 0;
char buffer[BSIZE];
//Function prototypes
void init(void);
void * thread_job(void *);
void message_rcvd(void);
void wait_for_message_or_timeout(void);
int start_timer(struct itimerval, int);
int stop_timer(struct itimerval);
void on_signal(int);
// MAIN: Wait for message or timeout
int main(int argc, char ** argv) {
init();
while(!end){
wait_for_message_or_timeout();
if(!end)
printf("Message received [%s]\n", buffer);
}
return 0;
}
// INIT: Initializes the signals that the program will wait for
// and creates a thread that will eventually generate a signal
void init()
{
/* Init the signals I want to wait for with sigwait() */
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_BLOCK, &mask, NULL);
//signal(SIGUSR1, SIG_IGN);
signal(SIGUSR1, on_signal);
/* Create the thread and put it to work */
pthread_t tid;
pthread_create(&tid, NULL, thread_job, NULL);
}
void on_signal(int signum){
printf("on_signal\n");
}
// THREAD CODE -------------
// THREAD JOB: When the user inputs a message, it passes the message
// to the main thread by invoking message_rcvd()
void * thread_job(){
int end = 0;
while(!end){
printf("Input message:");
if (fgets(buffer, BSIZE, stdin) != NULL)
message_rcvd();
}
}
// MESSAGE RECEIVED: If message is not equal to "quit" raise a signal
void message_rcvd(){
if(strcmp(buffer, "quit") == 0){
exit(0);
}else{
printf("Going to raise SIGUSR1...");
if(raise(SIGUSR1) == 0)
printf("raised!\n");
}
}
// WAIT: Should wait for signal SIGUSR1 for some time
void wait_for_message_or_timeout(){
int sigid;
struct itimerval t;
/* Set a timer to prevent waiting for ever*/
printf("Setting timer...\n");
start_timer(t, milisec);
/* Put the process to wait until signal arrives */
sigwait(&mask, &sigid);
switch(sigid){
case SIGUSR1:
printf("Received SIGUSR1: Message avaible!\n");
break;
case SIGALRM:
printf("Received SIGALRM: Timeout\n");
end = 1;
break;
default:
printf("Unknown signal received\n");
break;
}
printf("Stopping timer...\n");
/* Stop timer */
stop_timer(t);
}
// START TIMER: I don't want the timer to cause the execution
// of a handler function
int start_timer(struct itimerval timervalue, int msec)
//int start_timer(int msec)
{
timervalue.it_interval.tv_sec = msec / 1000;
timervalue.it_interval.tv_usec = (msec % 1000) * 1000;
timervalue.it_value.tv_sec = msec / 1000;
timervalue.it_value.tv_usec = (msec % 1000) * 1000;
if(setitimer(ITIMER_REAL, &timervalue, NULL))
{
printf("\nsetitimer() error\n");
return(-1);
}
return(0);
}
// STOP TIMER:
int stop_timer(struct itimerval timervalue)
//int stop_timer()
{
timervalue.it_interval.tv_sec = 0;
timervalue.it_interval.tv_usec = 0;
timervalue.it_value.tv_sec = 0;
timervalue.it_value.tv_usec = 0;
if(setitimer(ITIMER_REAL, &timervalue, NULL))
{
printf("\nsetitimer() error\n");
return(-1);
}
return(0);
}
Here is a typical execution of this code.
./signaltest
Setting timer...
Input message:hello
Going to raise SIGUSR1...raised!
Input message:friend
Going to raise SIGUSR1...raised!
Input message:Received SIGALRM: Timeout
Stopping timer...
As you can see, the signal SIGUSR1 is being raised and sigwait is being unblocked. However, the code seems does not continue after the signal has been raised. (Note that I don't need a signal handler but I just added for the debugging purposes. I have blocked its execution with sigprocmask)
Why is SIGUSR1 unblocking sigwait but the execution does not continue from there? Is there a way to make it continue after unblocking? This seems to work for SIGALRM but why not for SIGUSR1?
As I said, I have been looking at tons of stackoverflow questions, online howto's, tried with different system calls (e.g., pause, sigsuspend), ... but couldn't find a way to solve this :-(
If you are wondering why I am not doing this code much simpler by not using a thread is because this is not actually the code I am implementing but just a simpler example to make my question more clear. I am actually trying to implement a network protocol API, similar to the sockets API for my own protocol.
Thanks in advance
The SIGUSR1 signal isn't going where you think it is.
In a multithreaded program, the raise function sends a signal to the current thread, which is the thread_job thread in this case. So the main thread never sees the signal.
You need to save off thread ID of the main thread, then use pthread_kill to send a signal to that thread.
Add a new global:
pthread_t main_tid;
Then populate it in your init function before starting the new thread:
void init()
{
main_tid = pthread_self();
...
Then in message_rcvd, use pthread_kill:
if(pthread_kill(main_tid, SIGUSR1) == 0)
printf("raised!\n");
Also, remove the definition of end in thread_job, and remove the definition of tid in init. These definitions mask the global variables of the same name.
Sample output:
Setting timer...
Input message:hello
Going to raise SIGUSR1...raised!
Input message:Received SIGUSR1: Message avaible!
Stopping timer...
Message received [hello
]
Setting timer...
test
Going to raise SIGUSR1...raised!
Input message:Received SIGUSR1: Message avaible!
Stopping timer...
Message received [test
]
Setting timer...
Received SIGALRM: Timeout
Stopping timer...
Related
I have a threadpool of workers. Each worker executes this routine:
void* worker(void* args){
...
pthread_mutex_lock(&mtx);
while (queue == NULL && stop == 0){
pthread_cond_wait(&cond, &mtx);
}
el = pop(queue);
pthread_mutex_unlock(&mtx);
...
}
main thread:
int main(){
...
while (stop == 0){
...
pthread_mutex_lock(&mtx);
insert(queue, el);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx);
...
}
...
}
Then I have a signal handler that executes this code when it receives a signal:
void exit_handler(){
stop = 1;
pthread_mutex_lock(&mtx);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mtx);
}
I have omitted declarations and initialization, but the original code has them.
After a signal is received most of the time it's all ok, but sometimes it seems that some worker threads stay in the wait loop because they don't see that the variable stop is changed and/or they are not waken up by the broadcast.
So the threads never end.
What I am missing?
EDIT: stop=1 moved inside the critical section in exit_handler. The issue remains.
EDIT2: I was executing the program on a VM with Ubuntu. Since the code appears to be totally right I tried to change VM and OS (XUbuntu) and now it seems to work correctly. Still don't know why, anyone has an idea?
Some guessing here, but it's too long for a comment, so if this is wrong, I will delete. I think you may have a misconception about how pthread_cond_broadcast works (at least something I've been burned with in the past). From the man page:
The pthread_cond_broadcast() function shall unblock all threads
currently blocked on the specified condition variable cond.
Ok, that make sense, _broadcast awakens all threads currently blocked on cond. However, only one of the awakened threads will then be able to lock the mutex after they're all awoken. Also from the man page:
The thread(s) that are unblocked shall contend for the mutex according
to the scheduling policy (if applicable), and as if each had called
pthread_mutex_lock().
So this means that if 3 threads are blocked on cond and _broadcast is called, all 3 threads will wake up, but only 1 can grab the mutex. The other 2 will still be stuck in pthread_cond_wait, waiting on a signal. Because of this, they don't see stop set to 1, and exit_handler (I'm assuming a Ctrl+c software signal?) is done signaling, so the remaining threads that lost the _broadcast competition are stuck in limbo, waiting on a signal that will never come, and unable to read that the stop flag has been set.
I think there are 2 options to work-around/fix this:
Use pthread_cond_timedwait. Even without being signaled, this will return from waiting at the specified time interval, see that stop == 1, and then exit.
Add pthread_cond_signal or pthread_cond_broadcast at the end of your worker function. This way, right before a thread exits, it will signal the cond variable allowing any other waiting threads to grab the mutex and finish processing. There is no harm in signaling a conditional variable if no threads are waiting on it, so this should be fine even for the last thread.
EDIT: Here is an MCVE that proves (as far as I can tell) that my answer above is wrong, heh. As soon as I press Ctrl+c, the program exits "immediately", which says to me all the threads are quickly acquiring the mutex after the broadcast, seeing that stop is false, and exiting. Then main joins on the threads and it's process over.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#define NUM_THREADS 3
#define STACK_SIZE 10
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
volatile bool stop = false;
int stack[STACK_SIZE] = { 0 };
int sp = 0; // stack pointer,, also doubles as the current stack size
void SigHandler(int sig)
{
if (sig == SIGINT)
{
stop = true;
}
else
{
printf("Received unexcepted signal %d\n", sig);
}
}
void* worker(void* param)
{
long tid = (long)(param);
while (stop == false)
{
// acquire the lock
pthread_mutex_lock(&m);
while (sp <= 0) // sp should never be < 0
{
// there is no data in the stack to consume, wait to get signaled
// this unlocks the mutex when it is called, and locks the
// mutex before it returns
pthread_cond_wait(&c, &m);
}
// when we get here we should be guaranteed sp >= 1
printf("thread %ld consuming stack[%d] = %d\n", tid, sp-1, stack[sp-1]);
sp--;
pthread_mutex_unlock(&m);
int sleepVal = rand() % 10;
printf("thread %ld sleeping for %d seconds...\n", tid, sleepVal);
sleep(sleepVal);
}
pthread_exit(NULL);
}
int main(void)
{
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
srand(time(NULL));
for (long i=0; i<NUM_THREADS; i++)
{
int rc = pthread_create(&threads[i], &attr, worker, (void*)i);
if (rc != 0)
{
fprintf(stderr, "Failed to create thread %ld\n", i);
}
}
while (stop == false)
{
// produce data in bursts
int numValsToInsert = rand() % (STACK_SIZE - sp);
printf("main producing %d values\n", numValsToInsert);
// acquire the lock
pthread_mutex_lock(&m);
for (int i=0; i<numValsToInsert; i++)
{
// produce values for the stack
int val = rand() % 10000;
// I think this should already be guaranteed..?
if (sp+1 < STACK_SIZE)
{
printf("main pushing stack[%d] = %d\n", sp, val);
stack[sp++] = val;
// signal the workers that data is ready
//printf("main signaling threads...\n");
//pthread_cond_signal(&c);
}
else
{
printf("stack full!\n");
}
}
pthread_mutex_unlock(&m);
// signal the workers that data is ready
printf("main signaling threads...\n");
pthread_cond_broadcast(&c);
int sleepVal = 1;//rand() % 5;
printf("main sleeping for %d seconds...\n", sleepVal);
sleep(sleepVal);
}
for (long i=0; i<NUM_THREADS; i++)
{
pthread_join(threads[i], NULL);
}
return 0;
}
Learning about signals, and I was wondering about the subtle differences between the process signal mask, a blocked signal set, a signal handler, and a blocked signal.
The questions involve (on Debian):
sigprocmask(2)
sigsetops(3) related functions
Each process has it's own signal mask (a long which contains the signals being blocked). And a signal set can be obtained by calling sigprocmask(2) with a NULL argument for the *set variable, will result in the old process mask to be put into *oldset, unchanged:
#include <string.h>
#include <signal.h>
void show_signals(const sigset_t exmask)
{
int exsignals[43];
exsignals[0] = SIGABRT;
exsignals[1] = SIGALRM;
exsignals[2] = SIGBUS;
exsignals[3] = SIGCHLD;
exsignals[4] = SIGCONT;
#ifdef SIGEMT
exsignals[5] = SIGEMT;
#else
exsignals[5] = -1;
#endif
exsignals[6] = SIGFPE;
#ifdef SIGFREEZE
exsignals[7] = SIGFREEZE;
#else
exsignals[7] = -1;
#endif
exsignals[8] = SIGHUP;
exsignals[9] = SIGILL;
#ifdef SIGINFO
exsignals[10] = SIGINFO;
#else
exsignals[10] = -1;
#endif
exsignals[11] = SIGINT;
exsignals[12] = SIGIO;
exsignals[13] = SIGIOT;
#ifdef SIGJVM1
exsignals[14] = SIGJVM1;
#else
exsignals[14] = -1;
#endif
#ifdef SIGJVM2
exsignals[15] = SIGJVM2;
#else
exsignals[15] = -1;
#endif
exsignals[16] = SIGKILL;
#ifdef SIGLOST
exsignals[17] = SIGLOST;
#else
exsignals[17] = -1;
#endif
#ifdef SIGLWP
exsignals[18] = SIGLWP;
#else
exsignals[18] = -1;
#endif
exsignals[19] = SIGPIPE;
exsignals[20] = SIGPOLL;
exsignals[21] = SIGPROF;
exsignals[22] = SIGPWR;
exsignals[23] = SIGQUIT;
exsignals[24] = SIGSEGV;
exsignals[25] = SIGSTKFLT;
exsignals[26] = SIGSTOP;
exsignals[27] = SIGSYS;
exsignals[28] = SIGTERM;
#ifdef SIGTHAW
exsignals[29] = SIGTHAW;
#else
exsignals[29] = -1;
#endif
#ifdef SIGTHR
exsignals[30] = SIGTHR;
#else
exsignals[30] = -1;
#endif
exsignals[31] = SIGTRAP;
exsignals[32] = SIGTSTP;
exsignals[33] = SIGTTIN;
exsignals[34] = SIGTTOU;
exsignals[35] = SIGURG;
exsignals[36] = SIGUSR1;
exsignals[37] = SIGUSR2;
exsignals[38] = SIGVTALRM;
#ifdef SIGWAITING
exsignals[39] = SIGWAITING;
#else
exsignals[39] = -1;
#endif
exsignals[40] = SIGWINCH;
exsignals[41] = SIGXCPU;
exsignals[42] = SIGXFSZ;
#ifdef SIGXRES
exsignals[43] = SIGXRES;
#else
exsignals[43] = -1;
#endif
int exsignals_n = 0;
for (;exsignals_n < 43; exsignals_n++) {
if (exsignals[exsignals_n] == -1) continue;
static char *exsignal_name;
exsignal_name = strsignal(exsignals[exsignals_n]);
switch(sigismember(&exmask, exsignals[exsignals_n]))
{
case 0: break;
case 1: printf("YES %s\n", exsignal_name); break;
case -1: printf("could not obtain signal\n"); break;
default: printf("UNEXPECTED for %s return\n", exsignal_name); break;
}
}
}
const sigset_t getmask(void)
{
static sigset_t retmask;
if ((sigprocmask(SIG_SETMASK, NULL, &retmask)) == -1)
printf("could not obtain process signal mask\n");
return retmask;
}
At the beginning of my program, I realize that the process signal mask, has not blocked any signals. I then place a signal handler into the program.
static void sig_abrt(int signo)
{
printf("Caught SIGABRT\n");
}
int main(void)
{
show_signals(getmask());
signal(SIGABRT, sig_abrt);
show_signals(getmask());
return 0;
}
So now there is a signal handler for SIGABRT, but if I were to call sigprocmask(2) again, as above, SIGABRT will not be in the process signal mask. I tried checking with sigismember(3), but the process signal mask will only be modified once I have called sigaddset(3) or another function which modifies the signal mask.
If I block SIGABRT with sigaddset(3), will the signal handler sig_abrt not receive the call when the SIGABRT is delivered? Does it mean that the signal mask affects which signals are delivered? What is the difference?
Also, is there a way to block a signal in a process without using the sigsetops(3) and sigprocmask(2) functions?
Each process has it's [sic] own signal mask (a long which contains the signals being blocked)
Well, no. The signal mask is actually thread-specific. (In a multithreaded program, you must use pthread_sigmask() to manipulate the signal mask for the current thread; in a single-threaded program, you can use sigprocmask().)
Also, it's not "a long". It is of type sigset_t, which might be an array, structure, or union type. In any case, one should consider it simply as an unordered bit set, one bit per signal.
So now there is a signal handler for SIGABRT, but SIGABRT will not be in the process signal mask.
Correct. Whether or not you have assigned a signal handler or not, does not affect the signal mask at all.
If I block SIGABRT with sigaddset(3), will the signal handler sig_abrt not receive the call when the SIGABRT is delivered? Does it mean that the signal mask affects which signals are delivered? What is the difference?
If all your threads block SIGABRT, it will not be delivered until either the signal is unblocked (removed from the signal mask). If the signal is consumed using sigwait(), sigwaitinfo(), or sigtimedwait(), the signal handler will not be invoked at all.
A short summary:
Signals can be directed to a process group (kill() with pid == 0 or pid == -pgid), a specific process (pid), or a specific thread in a specific process (pthread_kill() within the same process, tgkill system call in Linux in general).
If a signal is directed to a process group, each process in that group receives "a copy" of the signal.
The signal mask defines whether signals are blocked, or delivered immediately.
In each process, each signal
can have a signal handler, or
be ignored (SIG_IGN "handler"), or
have the default disposition (ignored (Ign), terminates the process with (Core) or without (Term) a core dump; or it can stop (Stop) or continue (Cont) the execution of the target thread or process). See man 7 signal for details.
If some, but not all threads, block a signal, and the signal is not targeted to a specific thread, the kernel directs the signal to one of the threads that are not blocking the signal (at random).
There are two ways of catching a signal:
Using a signal handler. The signal gets delivered to a signal handler only when the signal is not blocked. If the signal is blocked, the delivery of the signal is pending until not blocked (or caught by the other option below).
sigwait(), sigwaitinfo(), or sigtimedwait(). These functions check if any signals are pending, and if so, "catch" it. The set of signals they check is defined by a function parameter of sigset_t type.
When the kernel sends/forwards a signal to a process, it first checks if the process has a thread that is not blocking that signal. If there is such a thread, it delivers it via that thread. (If the signal has a signal handler, that signal handler gets invoked in that thread; otherwise, the effect is dictated by the signal disposition.)
If the signal is blocked, the kernel leaves it pending for the process.
If the process calls sigwait(), sigwaitinfo(), or sigtimedwait() with the pending signal in the specified signals set, it receives the information on that signal, and the signal is caught. (It will no longer be pending, and it will not cause a signal handler to be invoked; it is "consumed".)
If the process changes its signal mask, so that the pending signal becomes unblocked, it is delivered by the kernel (just as if it was sent at that point in time).
Also, is there a way to block a signal in a process without using the sigsetops(3) and sigprocmask(2) functions?
No. (You can implement your own sigsetops() and a syscall wrapper for sigprocmask(), but that's about it.)
Here is an example program, example.c, you can use for exploring signal handlers, catching signals, and the signal mask, in a single-threaded process:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
/* Async-signal safe write-to-standard error function.
Keeps errno unchanged. Do not use stderr otherwise!
*/
static int wrerrpp(const char *ptr, const char *end)
{
const int saved_errno = errno;
ssize_t chars;
while (ptr < end) {
chars = write(STDERR_FILENO, ptr, (size_t)(end - ptr));
if (chars > 0)
ptr += chars;
else
if (chars != -1) {
errno = saved_errno;
return EIO;
} else
if (errno != EINTR) {
const int retval = errno;
errno = saved_errno;
return retval;
}
}
errno = saved_errno;
return 0;
}
/* Write the supplied string to standard error.
Async-signal safe. Keeps errno unchanged.
Do not mix with stderr!
*/
static int wrerr(const char *ptr)
{
if (!ptr)
return 0;
else {
const char *end = ptr;
/* strlen() is not async-signal safe, so
find the end of the string the hard way. */
while (*end)
end++;
return wrerrpp(ptr, end);
}
}
/* Write the supplied long to standard error.
Async-signal safe. Keeps errno unchanged.
Do not mix with stderr!
*/
static int wrerrnum(const long value)
{
unsigned long u = (value < 0) ? (unsigned long)-value : (unsigned long)value;
char buf[40];
char *ptr = buf + sizeof buf;
char *const end = buf + sizeof buf;
do {
*(--ptr) = '0' + (u % 10uL);
u /= 10uL;
} while (u > 0uL);
if (value < 0)
*(--ptr) = '-';
return wrerrpp(ptr, end);
}
/* Async-signal safe variant of strsignal().
Only covers a small subset of all signals.
Returns NULL if the signal name is not known. */
static const char *signal_name(const int signum)
{
switch (signum) {
case SIGHUP: return "HUP";
case SIGINT: return "INT";
case SIGQUIT: return "QUIT";
case SIGKILL: return "KILL";
case SIGSEGV: return "SEGV";
case SIGTERM: return "TERM";
case SIGUSR1: return "USR1";
case SIGUSR2: return "USR2";
case SIGCHLD: return "CHLD";
case SIGCONT: return "CONT";
case SIGSTOP: return "STOP";
default: return NULL;
}
}
/* Signal handler that reports its delivery immediately,
but does nothing else.
*/
static void report_signal(int signum, siginfo_t *info, void *ctx)
{
const char *sname = signal_name(signum);
wrerr("report_signal(): Received signal ");
if (sname)
wrerr(sname);
else
wrerrnum(signum);
if (info->si_pid) {
wrerr(" from process ");
wrerrnum(info->si_pid);
wrerr(".\n");
} else
wrerr(" from kernel or terminal.\n");
}
/* Install report_signal() handler.
*/
static int install_report_signal(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_sigaction = report_signal;
act.sa_flags = SA_SIGINFO;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
int main(void)
{
sigset_t mask;
siginfo_t info;
const char *name;
int signum;
if (install_report_signal(SIGINT) ||
install_report_signal(SIGCONT)) {
const char *errmsg = strerror(errno);
wrerr("Cannot install signal handlers: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
sigaddset(&mask, SIGHUP);
sigaddset(&mask, SIGTERM);
sigprocmask(SIG_SETMASK, &mask, NULL);
printf("Process %ld is ready to receive signals! Run\n", (long)getpid());
printf("\tkill -USR1 %ld\n", (long)getpid());
printf("\tkill -USR2 %ld\n", (long)getpid());
printf("\tkill -HUP %ld\n", (long)getpid());
printf("\tkill -TERM %ld\n", (long)getpid());
printf("in another terminal; press Ctrl+C in this terminal; or press Ctrl+Z and run\n");
printf("\tfg\n");
printf("in this terminal.\n");
fflush(stdout);
/* Almost same as blocked mask, just without SIGUSR1 and SIGUSR2. */
sigemptyset(&mask);
sigaddset(&mask, SIGHUP);
sigaddset(&mask, SIGTERM);
do {
do {
signum = sigwaitinfo(&mask, &info);
} while (signum == -1 && errno == EINTR);
if (signum == -1) {
const char *errmsg = strerror(errno);
wrerr("sigwaitinfo(): ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
name = signal_name(signum);
if (name)
printf("main(): Received signal %s from ", name);
else
printf("main(): Received signal %d from ", signum);
if (info.si_pid == 0)
printf("kernel or terminal.\n");
else
printf("process %ld.\n", (long)info.si_pid);
fflush(stdout);
} while (signum != SIGTERM);
return EXIT_SUCCESS;
}
Compile it using for example
gcc -Wall -O2 example.c -o example
I suggest you prepare two terminals. In one terminal, run the compiled program, using
./example
and observe its output. It will be something like
Process 843 is ready to receive signals! Run
kill -USR1 843
kill -USR2 843
kill -HUP 843
kill -TERM 843
in another terminal; press Ctrl+C in this terminal; or press Ctrl+Z and run
fg
in this terminal.
The KILL and STOP signals cannot be caught. KILL will always kill the process, and STOP will always stop ("pause") the process.
If you press Ctrl+C in that terminal, the kernel will send an INT signal to the process. (This will be delivered via the report_signal() signal handler.)
If you press Ctrl+Z in that terminal, the kernel will send a STOP signal to the process. The shell detects this, pushing ./example under job control, and lets you input new shell commands. The fg command brings ./example back to foreground, with the shell sending it the CONT signal, so that ./example will continue execution.
USR1 and USR2 signals are blocked, so they are never delivered to the report_signal() signal handler.
HUP and TERM signals are also blocked, but they are received by the main thread via sigwaitinfo().
The program exits, when it receives a TERM signal.
In the context of an existing multi-threaded application I want to suspend a list of threads for a specific duration then resume their normal execution. I know some of you wil say that I should not do that but I know that and I don't have a choice.
I came up with the following code that sort of work but randomly failed. For each thread I want to suspend, I send a signal and wait for an ack via a semaphore. The signal handler when invoked, post the semaphore and sleep for the specified duration.
The problem is when the system is fully loaded, the call to sem_timedwait sometimes fails with ETIMEDOUT and I am left with an inconsistent logic with semaphore used for the ack: I don't know if the signal has been dropped or is just late.
// compiled with: gcc main.c -o test -pthread
#include <pthread.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/syscall.h>
#define NUMTHREADS 40
#define SUSPEND_SIG (SIGRTMIN+1)
#define SUSPEND_DURATION 80 // in ms
static sem_t sem;
void checkResults(const char *msg, int rc) {
if (rc == 0) {
//printf("%s success\n", msg);
} else if (rc == ESRCH) {
printf("%s failed with ESRCH\n", msg);
} else if (rc == EINVAL) {
printf("%s failed with EINVAL\n", msg);
} else {
printf("%s failed with unknown error: %d\n", msg, rc);
}
}
static void suspend_handler(int signo) {
sem_post(&sem);
usleep(SUSPEND_DURATION*1000);
}
void installSuspendHandler() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = suspend_handler;
int rc = sigaction(SUSPEND_SIG, &sa, NULL);
checkResults("sigaction SUSPEND", rc);
}
void *threadfunc(void *param) {
int tid = *((int *) param);
free(param);
printf("Thread %d entered\n", tid);
// this is an example workload, the real app is doing many things
while (1) {
int rc = sleep(30);
if (rc != 0 && errno == EINTR) {
//printf("Thread %d got a signal delivered to it\n", tid);
} else {
//printf("Thread %d did not get expected results! rc=%d, errno=%d\n", tid, rc, errno);
}
}
return NULL;
}
int main(int argc, char **argv) {
pthread_t threads[NUMTHREADS];
int i;
sem_init(&sem, 0, 0);
installSuspendHandler();
for(i=0; i<NUMTHREADS; ++i) {
int *arg = malloc(sizeof(*arg));
if ( arg == NULL ) {
fprintf(stderr, "Couldn't allocate memory for thread arg.\n");
exit(EXIT_FAILURE);
}
*arg = i;
int rc = pthread_create(&threads[i], NULL, threadfunc, arg);
checkResults("pthread_create()", rc);
}
sleep(3);
printf("Will start to send signals...\n");
while (1) {
printf("***********************************************\n");
for(i=0; i<NUMTHREADS; ++i) {
int rc = pthread_kill(threads[i], SUSPEND_SIG);
checkResults("pthread_kill()", rc);
printf("Waiting for Semaphore for thread %d ...\n", i);
// compute timeout abs timestamp for ack
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
const int TIMEOUT = SUSPEND_DURATION*1000*1000; // in nano-seconds
ts.tv_nsec += TIMEOUT; // timeout to receive ack from signal handler
// normalize timespec
ts.tv_sec += ts.tv_nsec / 1000000000;
ts.tv_nsec %= 1000000000;
rc = sem_timedwait(&sem, &ts); // try decrement semaphore
if (rc == -1 && errno == ETIMEDOUT) {
// timeout
// semaphore is out of sync
printf("Did not received signal handler sem_post before timeout of %d ms for thread %d", TIMEOUT/1000000, i);
abort();
}
checkResults("sem_timedwait", rc);
printf("Received Semaphore for thread %d.\n", i);
}
sleep(1);
}
for(i=0; i<NUMTHREADS; ++i) {
int rc = pthread_join(threads[i], NULL);
checkResults("pthread_join()\n", rc);
}
printf("Main completed\n");
return 0;
}
Questions?
Is it possible for a signal to be dropped and never delivered?
What causes the timeout on the semaphore at random time when the system is loaded?
usleep() is not among the async-signal-safe functions (though sleep() is, and there are other async-signal-safe functions by which you can produce a timed delay). A program that calls usleep() from a signal handler is therefore non-conforming. The specifications do not describe what may happen -- neither with such a call itself nor with the larger program execution in which it occurs. Your questions can be answered only for a conforming program; I do that below.
Is it possible for a signal to be dropped and never delivered?
It depends on what exactly you mean:
If a normal (not real-time) signal is delivered to a thread that already has that signal queued then no additional instance is queued.
A thread can die with signals still queued for it; those signals will not be handled.
A thread can change a given signal's disposition (to SIG_IGN, for example), though this is a per-process attribute, not a per-thread one.
A thread can block a signal indefinitely. A blocked signal is not dropped -- it remains queued for the thread and will eventually be received some time after it is unblocked, if that ever happens.
But no, having successfully queued a signal via the kill() or raise() function, that signal will not be randomly dropped.
What causes the timeout on the semaphore at random time when the system is loaded?
A thread can receive a signal only when it is actually running on a core. On a system with more runnable processes than cores, some runnable processes must be suspended, without a timeslice on any core, at any given time. On a heavily-loaded system, that's the norm. Signals are asynchronous, so you can send one to a thread that is currently waiting for a timeslice without the sender blocking. It is entirely possible, then, that the thread you have signaled does not get scheduled to run before the timeout expires. If it does run, it may have the signal blocked for one reason or another, and not get around to unblocking it before it uses up its timeslice.
Ultimately, you can use your semaphore-based approach to check whether the target thread handled the signal within any timeout of your choice, but you cannot predict in advance how long it will take for the thread to handle the signal, nor even whether it will do so in any finite amount of time (for example, it could die for one reason or another before doing so).
I am trying to set up a counter for my programme to count how many times a signal was sent. I am trying to achieve the program to exit after ctrl +c was pressed twice. I have most of the code but just don't know how to link the counter to the if section. Here is my code.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
// user-defined signal handler for alarm.
int cnt=0;
void my_handler(int signo)
{
while ( cnt < 2){
if (signo == SIGINT)
{
printf("Press ctrl c to stop\n");
exit(0);
}
}
}
int main(void)
{
signal(SIGINT,my_handler);
while(1){
printf(" I am running into infinite loop.., stop me if you dear..\n");
sleep(1); /* wait until alarm goes off */
}
} /* main */
I tried out the above code and it seems that the counter will stay at 0 forever and the programme exit immediately as soon as ctrl+c was pressed.
You can't do much safely in a signal handler, and definitely no I/O. For maximum portability, there are really only a handful of things a signal handler can do to affect global state:
Assign to a volatile sig_atomic_t variable
Make calls to signal
abort, exit, etc. on error
You can't do I/O safely. The safe thing to do is set a flag that the main thread can check and do your printing for you. If printing isn't necessary, the first call to your handler could just unregister itself, restoring the default behavior with SIG_DFL (or registering a new "second Ctrl-C" handler if you need to do something special) so the second Ctrl-C kills as normal.
Replace the while statement with an if one. If cnt is lower than 2, then print your message and count by using cnt++; else do something else
Signals are a little more involved to get right.
You should either use sigaction or a custom sigaction wrapper as signal doesn't have clearly defined semantics. Registering the handler may fail.
If you want to set a flag, it should be volatile sigatomic_t, you shouldn't do buffered IO in the handler.
With the wrapper and flag approach, you could do something like:
typedef void (Sigfunc)(int);
Sigfunc* reliableSignal(int signo, Sigfunc *func);
// user-defined signal handler for alarm.
volatile sig_atomic_t cnt=0;
void my_handler(int signo){
if(cnt++ == 1)
exit(0);
}
int main(void) {
if(reliableSignal(SIGINT,my_handler)<0){ perror("Signal"); exit(1); }
while(1){
printf(" I am running into infinite loop.., stop me if you dear..\n");
sleep(1); /* wait until alarm goes off */
}
} /* main */
Sigfunc* reliableSignal(int signo, Sigfunc *func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
} else {
act.sa_flags |= SA_RESTART;
}
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}
In this example you must press twice Ctrl-C within 300ms.
So if you keep Ctrl-C pressed the program will stop otherwise not.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
int ctrlcs=0;
void cchandler(int signum){
printf("Press again to quit.\n");
ctrlcs+=1;
if (ctrlcs==2) {
signal(SIGINT, SIG_DFL);
}
usleep(300000); // delay for the second Ctrl-C
}
int main(){
signal(SIGINT, cchandler);
while(1) {
printf(" I am running into infinite loop.., stop me if you dare..\n");
sleep (5);
ctrlcs=0;
}
}
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.