So it seems trylock
is not officially supported in signal handlers because "nothing in C is safe to call from signal handlers" as Andrew put it in the comments to the question. I suppose this is due to the interruptible nature of a signal handler. The ideal signal handler would return ASAP, not performing long running operations. So, I decided on using a pipe to another thread as write
is signal safe. Here is an example of that implementation which could replace the use of trylock
:
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <pthread.h>
#include <csignal>
#define READ_BUF_SET_BYTES(fd, buffer, numb, bytesRead){ \
ssize_t rb = 0; \
ssize_t nb; \
while (rb < numb) { \
nb = read(fd,(char*)&buffer + rb,numb - rb); \
if(nb<=0) \
break; \
rb += nb; \
} \
bytesRead = rb; \
}
#define READ_BUF(fd, buffer, numb) { \
ssize_t bytesRead = 0; \
READ_BUF_SET_BYTES(fd, buffer, numb, bytesRead)\
}
#define WRITE_BUF(fd,buf,sz){ \
size_t nb = 0; \
size_t wb = 0; \
while (nb < sz){ \
wb = write(fd, &buf + nb, sz-nb); \
if(wb == EOF) break; \
nb += wb; \
} \
}
#define UNEXPECTED_ERROR (-1)
static int signalPipe[2];
static pthread_mutex_t signal_mutex;
static void sig_ignore(int) {} //SIGHUP
static void sig_quit(int sig) //SIGQUIT, SIGTERM, SIGINT
{
WRITE_BUF(signalPipe[1],sig,sizeof(int))
}
static void *signalQueueThread(void*){
pthread_detach(pthread_self());
//only accepts one signal, which should be a SIGQUIT, SIGINT, or SIGTERM
int sig = 0;
while(sig == 0) {
READ_BUF(signalPipe[0], sig, sizeof(int))
}
bool locked = !pthread_mutex_trylock(&signal_mutex);
if (locked) {
//...
}
return nullptr;
}
int main(int argc, char *argv[]) {
if (pipe(signalPipe) == UNEXPECTED_ERROR) {
exit(UNEXPECTED_ERROR);
}
pthread_t signalQueueThreadID;
if (pthread_create(&signalQueueThreadID, nullptr,
&signalQueueThread, nullptr) != 0) {
exit(UNEXPECTED_ERROR);
}
signal(SIGQUIT, sig_quit);
signal(SIGTERM, sig_quit);
signal(SIGINT, sig_quit);
signal(SIGHUP, sig_ignore);
//...
return 0;
}