views:

90

answers:

3

I'm implementing user threads in Linux kernel 2.4, and I'm using ualarm to invoke context switches between the threads.

We have a requirement that our thread library's functions should be uninterruptable by the context switching mechanism for threads, so I looked into blocking signals and learned that using sigprocmask is the standard way to do this.

However, it looks like I need to do quite a lot to implement this:

sigset_t new_set, old_set;

sigemptyset(&new_set);
sigaddset(&new_set, SIGALRM);
sigprocmask(SIG_BLOCK, &new_set, &old_set);

This blocks SIGALARM but it does this with 3 function invocations! A lot can happen in the time it takes for these functions to run, including the signal being sent. The best idea I had to mitigate this was temporarily disabling ualarm, like this:

sigset_t new_set, old_set;

time=ualarm(0,0);
sigemptyset(&new_set);
sigaddset(&new_set, SIGALRM);
sigprocmask(SIG_BLOCK, &new_set, &old_set);
ualarm(time, 0);

Which is fine except that this feels verbose. Isn't there a better way to do this?

+1  A: 

You'll find that sigemptyset() and sigaddset() in signals.h are just macros or inline functions, so they execute inline in your code. Just use a stack variable when you call them.

However, why don't you do this in a single-threaded startup section of your code? I also doubt the function call to sigprocmask will be atomic. Blocking signals does not mean your code will be uninterruptible.

By the way, I'm not sure how you're using ualarm, but if you're not catching or ignoring SIGALARM when you call it the first time, you'll probably kill your process.

WhirlWind
"Blocking signals does not mean your code will be uninterruptible." Yes, I meant uninterruptible by the context switching mechanism I'm implementing (updated question). ualarm goes off every THREAD_TIME_SLICE and the handler switches execution to another thread.
EpsilonVector
+1  A: 

As WhirlWind points out, the signal set functions are quite lightweight and may even be implemented as macros; and you can also just keep around a signal set that contains only SIGALRM and re-use that.

Regardless, it doesn't actually matter if the signal happens during the sigaddset() or sigemptyset() calls - the new_set and old_set variable are (presumably) thread-local, and the critical section isn't entered until after sigprocmask() returns.

caf
A: 

sigprocmask() is the only function that goes to kernel level and actually changes the signal masking status. The other functions are just manipulation functions for setting up the mask before calling sigprocmask or passing the set to another signal related function.

stsquad