From: rcswebb on
Hello,

I'm writing some threaded shared library code that will be used by
programs that execute a main event loop and exit via a signal handler
i.e.

static void handle_signal(int)
{
exit_flag = true;
}

int main()
{
while(!exit_flag)
{
//stuff
}
return 0;
}

I wish to preserve this behaviour by, in theory at least, blocking
SIGTERM and SIGINT in each of the threads my library code creates thus
allowing only the main thread to receive the signal.

So far I've tried:

sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_SETMASK, &set, 0);

in the function my thread executes, the theory being, I mask every
signal in my threads the library creates. The problem is, my signal
handler in the main thread doesn't seem to be firing.

I'd appreciate any advice or insights on how to solve this?

The only restriction I have is that the code that uses my library
(i.e. the main thread) has to remain agnostic to the presence of
threads in the library and the associated signal handling issues.

Regards,

Richard.
From: Ersek, Laszlo on
On Sat, 19 Jun 2010, rcswebb wrote:

> I'm writing some threaded shared library code that will be used by
> programs that execute a main event loop and exit via a signal handler
> i.e.
>
> static void handle_signal(int)
> {
> exit_flag = true;
> }
>
> int main()
> {
> while(!exit_flag)
> {
> //stuff
> }
> return 0;
> }
>
> I wish to preserve this behaviour by, in theory at least, blocking
> SIGTERM and SIGINT in each of the threads my library code creates thus
> allowing only the main thread to receive the signal.

This approach is sort of mandatory. Even with "exit_flag" being of type
"volatile sig_atomic_t", you can only rely on thread T noticing a change
in "exit_flag" if the thread interrupted by the signal and executing the
handler modifying "exit_flag" is the same thread T. That is, if the main
thread is the one checking "exit_flag", then the main thread must be the
one modifying it in the handler, too. I'm too lazy to look up references,
google >>Boehm volatile sigatomic_t<< [sic].


> So far I've tried:
>
> sigset_t set;
> sigfillset(&set);
> pthread_sigmask(SIG_SETMASK, &set, 0);
>
> in the function my thread executes, the theory being, I mask every
> signal in my threads the library creates.

There's a race condition in that. An async signal could be delivered to
your thread before it executes pthread_sigmask().

I'd recommend blocking SIGTERM and SIGINT in the main thread before
starting any other threads. The subsequently created threads would inherit
the signal mask. Finally, you could unblock those signals in the main
thread if necessary. If the sub-threads, created directly by the main
thread, create their own descendant threads, the latter again will inherit
a signal mask that has those two signals blocked.

For blocking SIGINT and SIGTERM in the main thread, I'd recommend emptying
a signal set and adding only these two. Blocking all possible signals
seems too heavy-handed. For example, you don't need to block asynchronous
signals that the original (single threaded) program doesn't care about at
all. Looking at the list of default signal actions in SUSv4 (<signal.h>):

----v----
The default actions are as follows:

T
Abnormal termination of the process.
A
Abnormal termination of the process [XSI] [Option Start] with
additional actions. [Option End]
I
Ignore the signal.
S
Stop the process.
C
Continue the process, if it is stopped; otherwise, ignore the signal.
----^----

The default action is either to ignore the signal, or the delivery of the
signal affects the entire process. It doesn't matter which thread is the
victim.

Synchronous signals are delivered to the offending thread anyway.


> The problem is, my signal handler in the main thread doesn't seem to be
> firing.

After blocking the signals, have you set up the handler with sigaction()
and unblocked the signals?


> I'd appreciate any advice or insights on how to solve this?
>
> The only restriction I have is that the code that uses my library (i.e.
> the main thread) has to remain agnostic to the presence of threads in
> the library and the associated signal handling issues.

That is impossible. For example, the main thread can't call sigprocmask()
anymore; at least after your library created sub-threads. There are issues
with fork(); see earlier threads in this group. If you don't recompile (or
rather, relink) the original client application, just switch the
pre-existent shared lib below it from single-threaded to multi-threaded,
there might be issues with errno.

In my opinion, it is risky if a "main thread" is oblivious to the presence
of other threads in the same process. Why do you want to do this? Couldn't
you achieve whatever you're trying to with child processes?

lacos