If I have a program like this (in pseudocode):
mutex_lock;
func() {
lock(mutex_lock);
// Some code (long enough to make a
// race condition if no pro
You may use the test mutex functions (trylock) in this kind of undefined situations, to be safe. And with this, you don't necessarily need to block too.
You want pthread_sigmask
, the multithread version of sigprocmask
Here's some sample pseudo code:
int
main(void)
{
sigset_t omask;
sigset_t nmask;
// add as many signals as you want to the mask ...
sigemptyset(&nmask);
sigaddset(&nmask,SIGINT);
// [temporarily] block signals
pthread_sigmask(SIG_BLOCK,&nmask,&omask);
// call function safely
func();
// restore signal mask
pthread_sigmask(SIG_SETMASK,&omask,NULL);
// pending signals should occur now ...
}
I'm not totally sure, but, you may need to use pthread_sigmask
to block signals in all but one thread and do the above from that thread only.
Also, I'd be remiss if I didn't say that I'd refactor your code. The number of things you can do in a signal handler [aside from this] is limited (e.g. no malloc
, no printf
, etc.)
Dedicating one thread for signal handling and having it do sigsetjmp
and the signal handler does siglongjmp
.
Or have the signal handler set a volatile global (e.g. signal_occurred
) that is monitored at base level.
Thus, all the "heavy lifting" that you'd be doing in the signal handler can be done from base task level where you can do anything.
You need two locks. The one used inside your func()
, and one to protect the process's signal mask.
You have to make masking and unmasking the signal atomic also:
static pthread_mutex_t mask_mutex = PTHREAD_MUTEX_INITIALIZER;
sigset_t old_set;
sigset_t new_set;
sigemptyset( &new_set );
sigaddset( &new_set, SIGINT );
pthread_mutex_lock( &mask_mutex );
pthread_sigmask( SIG_BLOCK, &new_mask, &old_mask );
func();
pthread_sigmask( SIG_SETMASK, &old_mask, NULL );
pthread_mutex_unlock( &mask_mutex );
With no lock around the pthread_sigmask()
, threads are likely to corrupt the process sigmask as execution overlaps.