boost::asio::signal_set does not restore previous signal handlers - c++

So I have a daemon who can be gracefully shut down using SIGQUIT.
This daemon is running boost::asio::io_service. I use boost::asio::signal_set to catch this signal.
I have encountered a behaviour that I believe to be completely wrong. When I destroy boost::asio::signal_set object it does not restore previous handler of that signal. Previous handler for SIGQUIT was a no-op. So upon receiving this signal after boost::asio::signal_set was destroyed my daemon terminates. My guess is this is because boost::asio::signal_set upon destruction sets default handler, that is to terminate the program, but not the previous handler.
I see this as very inappropriate. What I am asking is am I wrong? Maybe I am missing something?

Boost.Asio does not specify the resulting handler state for a signal that had been added to boost::asio::signal_set and then removed via either signal_set::remove(), signal_set::clear(), or destruction of the signal_set. In particular, the post-condition is not specified for any of the associated operations in the Signal Set Service requirements.
A quick glance a the signal_set_service::add() implementation:
::sigaction(signal_number, &sa, 0)
and the signal_set_service::clear() implementation:
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
::sigaction(reg->signal_number_, &sa, 0)
shows that the calls to sigaction() are not handling previously installed handlers, and results in the default handler action being registered when a signal is removed via signal_set_service.
As a signal may be delivered after Boost.Asio sets the signal action to default, but before the application code has been able to assign its own handler, consider using pthread_sigmask() to block all signals within the io_service. Once the signals have been removed from the signal_set, assign the desired handler via sigaction(), then unblock the signals.
Here is a complete example demonstrating this approach:
#include <iostream>
#include <boost/asio.hpp>
void signal_handler(int signal_number)
{
std::cout << "signal_handler(): " << signal_number << std::endl;
}
int main()
{
// Force scope to control io_service lifetime.
{
boost::asio::io_service io_service;
// Boost.Asio will register an internal handler for SIGQUIT.
boost::asio::signal_set signal_set(io_service, SIGQUIT);
signal_set.async_wait(
[](const boost::system::error_code& error,
int signal_number)
{
std::cout << "siganl_set.async_wait handler: "
<< signal_number << std::endl;
// Block SIGQUIT.
sigset_t signal_mask;
sigemptyset(&signal_mask);
sigaddset(&signal_mask, SIGQUIT);
assert(pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) == 0);
});
// Send SIGQUIT to this process.
raise(SIGQUIT);
// By the time raise() returns, Boost.Asio has handled SIGQUIT with its
// own internal handler, queuing it internally. At this point, Boost.Asio
// is ready to dispatch this notification to a user signal handler
// (i.e. those provided to signal_set.async_wait()) within the
// io_service event loop.
// Prior to calling the io_service, SIGQUIT is not blocked.
io_service.run();
// The user provided handler was invoked and has blocked SIGQUIT.
}
// Send SIGQUIT to this process.
raise(SIGQUIT);
// Even though Boost.Asio has set the default handler for SIGQUIT, the
// signal is blocked, so the signal has been placed into a pending state.
// Register a custom handler for SIGQUIT.
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = &signal_handler;
assert(sigaction(SIGQUIT, &sa, 0) == 0);
// Unblock SIGQUIT.
sigset_t signal_mask;
sigemptyset(&signal_mask);
sigaddset(&signal_mask, SIGQUIT);
assert(pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL) == 0);
// Upon unblocking, the pending SIGQUIT signal is delivered and handled
// by the handler registered via sigaction.
std::cout << "Fin" << std::endl;
}
And its output:
$ ./a.out
siganl_set.async_wait handler: 3
signal_handler(): 3
Fin

Related

sigwait() does not work in multithreaded program

I'm trying to write a multithreaded program which one thread (variable thread in below) is responsible to any asynchronous signals that might be set to this process.
I am facing thread that uses sigwait() but does not react to any signals have been sent to process. (like SIGUSR1 in below).
static void * signal_thread(void *arg = nullptr)
{
int sig = -1;
sigset_t sigset;
sigfillset(&sigset);
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
while(1)
{
int s = sigwait(&sigset, &sig);
if(s == 0)
printf("SIG %d recieved!...\n", sig);
usleep(20);
}
}
int main()
{
sigset_t signalset;
pthread_t thread;
pthread_create(&thread, NULL, &signal_thread, nullptr);
sigfillset(&signalset);
pthread_sigmask(SIG_BLOCK, &signalset, NULL);
while(1)
{
raise(SIGUSR1);
usleep(20);
}
}
The problem is concerned to two issues:
First, call of raise in main sent signal only to main thread not whole process.
Secondly, std::cout should be used instead of printf in signal_thread.
raise(sig) is the equivalent of calling pthread_kill(pthread_self(), sig).
Since the main thread raise()s the signal, the SIGUSR1 will be generated for that thread and not for any other. Thus, your signal_thread will be unable to sigwait() for the USR1, which will be held pending for the thread that generated it.

Terminating a program with calling atexit functions (Linux)

Is there any way to send a signal to a process (in Linux), that results in a termination of the process after going through the "atexit-functions" (in this case: void shutdownEngines())? Using "pkill name" does not work.
#include <cstdlib>
void shutdownEngines() {/*is not executed by "pkill name"*/}
int main() {
atexit(shutdownEngines);
while(true)
doStuff();
}
Usage: I'm currently programming a robot. Every time I want to test it, I'll start the program and terminate it with "pkill name", but "shutdownEngines" isn't called and the robot keeps moving, falling off the table etc.
I know I could do "pkill name; ./shutdownEngines.sh", but this would be very bad style in my case (the numbers of the gpio pins connected to the engines are defined in a header file of the main program (the source code of the main program is not on the robot but on my computer). Making sure that there's always a "shutdownEngines.sh" program/script with the right pins on every robot would be very complicated.
Update
The following code works perfectly:
#include <iostream>
#include <csignal>
#include <cstdlib>
void signalHandler(__attribute__((unused)) const int signum) {
exit(EXIT_FAILURE);
}
void driverEpilog() {
std::cout << "shutting down engines...";
//drv255(0,0);
}
int main() {
signal(SIGTERM, signalHandler);
atexit(driverEpilog);
while(true)
system("sleep 1");
}
from the man page of atexit:
Functions registered using atexit() (and on_exit(3)) are not called
if a process terminates abnormally because of the delivery of a
signal.
atexit is called when your main routine returns or when you call exit, not on a signal.
When you call pkill you're sending a SIGTERM signal. Handle this signal with signal or sigaction instead (define handlers on SIGTERM, SIGINT, SIGFPE, ...) to stop the engines before exiting your program.
Example lifted from GNU C library documentation:
void
termination_handler (int signum)
{
struct temp_file *p;
for (p = temp_file_list; p; p = p->next)
unlink (p->name); // don't delete files, stop your engines instead :)
}
int
main (void)
{
…
struct sigaction new_action, old_action;
/* Set up the structure to specify the new action. */
new_action.sa_handler = termination_handler;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction (SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction (SIGINT, &new_action, NULL);
sigaction (SIGHUP, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction (SIGHUP, &new_action, NULL);
sigaction (SIGTERM, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction (SIGTERM, &new_action, NULL);
…
}
(of course, no handler can handle the SIGKILL "signal", which tells the OS to remove your process from the active process list, without further notice!)

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;
}
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.
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.
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

I want to know which a signal is arrived when system call() is interrupted

My application has two threads. Each threads recevive some data from the server via each sockets. Threads wait to return epoll_wait(). Sometimes epoll_wait() returns -1 and errno is EINTR. EINTR means that system call() is interrupted by a signal. I added to process EINTR.
However I do not know what a signal is arrived and why a signal is arrived. I wonder it.
Method 1.
I created a thread.
sigset_t sMaskOfSignal;
sigset_t sOldMaskOfSignal;
sigfillset(&sMaskOfSignal);
sigprocmask(SIG_UNBLOCK, &sMaskOfSignal, &sOldMaskOfSignal)
while(1)
{
sigwait(&sMaskOfSignal, &sArrivedSignal);
fprintf(stdout, "%d(%s) signal caught\n", sArrivedSignal, strsignal(sArrivedSignal));
}
I could not catch a signal when epoll_wait() is interrupted.
Method 2
When I execute my application in strace tool, epoll_wait() never be interrupted.
My problem is reproduced very well in GDB tool. I need helps....
You can try to implement your own signal handler. If you application gets interrupted by a signal again, your own signal-handler will be called and you can see, what kind of signal has been raised.
void
signal_callback_handler(int signum)
{
printf("Caught signal %d\n",signum);
exit(signum); // terminate application
}
int main()
{
// Register signal handler for all signals you want to handle
signal(SIGINT, signal_callback_handler);
signal(SIGABRT, signal_callback_handler);
signal(SIGSEGV, signal_callback_handler);
// .. and even more, if you want to
}
Not a very handy-method, but this should (hopefully) enable you to find out, what signal has been raised. Take a look here to see the different signals, that can be handled (note: not all signals can be handled in your own signal-handler(!)).
May be you should try setting signal handler for catching all signals and set your signal flags to SA_SIGINFO
something like this
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = <handler>;
sigaction(SIGFPE, &act, 0);
sigaction(SIGHUP, &act, 0);
sigaction(SIGABRT, &act, 0);
sigaction(SIGILL, &act, 0);
sigaction(SIGALRM, &act, 0);
sigaction(SIGALRM, &act, 0);
.
.
.
//and your handler looks like
void handle_sig (int sig, siginfo_t *info, void *ptr)
{
printf ("Signal is %d\n",sig);
}
Resgister the handler in your main program and ignore EINTR in epoll.

Unable to handle signal, causing interruped system calls

I am having trouble trying to handle a signal...
I have a multithreaded application, which receives a signal that interrupts system calls in a library that I am using. After some research, I found that if a signal is not handled, it gets sent to a random thread in the application. I have confirmed from the library I am using that they are not using any signals in their application. Neither am I. Here is my main driver class:
void sig_handler(int signum)
{
cout << "Signal Handle: " << signum << endl;
signal(signum, SIG_IGN);
}
class Driver
{
public:
Driver();
void LaunchLog();
void logonListen();
};
Driver::Driver()
{
pthread_t logThread;
pthread_create(&logThread, NULL, LaunchLogThread, (void*) this);
pthread_detach(logThread);
pthread_t listenThread;
pthread_create(&listenThread, NULL, LaunchListenThread, (void*)this);
pthread_detach(listenThread);
bool running = true;
while(running)
{
//Simple loop to resemble a menu for the console
}
}
void Driver::logonListen()
{
char buffer[256];
int logonPort = BASEPORT;
int sockfd;
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen;
//initialize socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0){
perror("Error opening socket");
exit(1);
}
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(logonPort);
//bind socket to our address
if(bind(sockfd,(struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
{
perror("Error on bind");
exit(1);
}
clilen = sizeof(struct sockaddr_in);
int n;
int nextUser = 2;
char reply[32];
while(1)
{
//Wait for incoming connection on a socket
}
}
void Driver::LaunchLog()
{
Logger::Instance()->WriteToFile();
}
void* LaunchListenThread(void* ptr)
{
Driver* driver = (Driver*) ptr;
driver->logonListen();
}
int main()
{
signal (SIGHUP, sig_handler);
signal (SIGINT, sig_handler);
signal (SIGQUIT, sig_handler);
signal (SIGILL, sig_handler);
signal (SIGTRAP, sig_handler);
signal (SIGFPE, sig_handler);
signal (SIGKILL, sig_handler);
signal (SIGUSR1, sig_handler);
signal (SIGSEGV, sig_handler);
signal (SIGUSR2, sig_handler);
signal (SIGPIPE, sig_handler);
signal (SIGALRM, sig_handler);
signal (SIGTERM, sig_handler);
signal (SIGCHLD, sig_handler);
signal (SIGCONT, sig_handler);
signal (SIGSTOP, sig_handler);
signal (SIGTSTP, sig_handler);
signal (SIGTTIN, sig_handler);
signal (SIGTTOU, sig_handler);
signal (SIGABRT, sig_handler);
Driver driver;
return 0;
}
I am unable to handle the signals. Interrupted System Calls keep creeping up, and my signal handler never gets used. Even when I press CTRL+C in the console, the program ends with interruption rather than SIGINT being handled. Am I installing the handler incorrectly?
Is there a way to handle all signals and to ignore them if they arise?
Thanks
You want to use sigaction(2) with the SA_RESTART flag to ignore the signals and insure that system calls get restarted instead of interrupted:
struct sigaction sa;
sa.sa_hanlder = SIG_IGN;
sa.sa_flags = SA_RESTART;
sigaction(SIGALRM, &sa);
sigaction(SIGPIPE, &sa);
/* repeat for all the signals you want to ignore */
Note that you might not want to ignore things like SIGINT as you then won't be able to stop you program with ctrl-C. Likewise, ignoring SIGSEGV may cause your program to hang if it contains a bug, rather than exiting.
edit
Your description that neither you nor the library is using any signals doesn't quite ring true -- the signals are coming from SOMEWHERE, and it may just be a case that you don't realize something you are doing is using signals under the hood. If you're using any alarms or itimers anywhere, those involve signals. If your sig_handler is truly not being called, that implies that someone else (your library?) is installing a signal handler to replace it.
If you still can't figure out where the signals are coming from, you can run under a debugger, and enable the debugger's signal debugging ability (if needed). That should at least tell you which signals are occurring, and where they are occurring.
In general, with any system call, you should ALWAYS check for errors, and if you see the error EINTR unexpectedly, you should probably just loop and redo the system call.
A couple things. First, you should be checking the return value of signal(). It can return SIG_ERR if there are problems installing your signal handler (which there probably are in some of those cases at least, because some of those signals are not trappable). Second, using stdio/iostream functions in a signal handler can be problematic due to their asynchronous (with respect to something else in the program that might be using the same facilities) nature. And third, in your signal handler, even if it's called the first time, you are then setting that signal to be ignored, so any subsequent instances of that signal (assuming it's one that's catchable) will simply be ignored. If you want to ignore them to begin with, you don't need to write a handler, just signal(SIG<whatever>, SIG_IGN) in your main().