I need to know how to avoid a race condition when handling signals in C. Each time my program receives a signal, I want it to alter a (global) linked list. It is vitally important that I not miss a signal, and equally important that the global linked list I'm modifying not be changed while the handler is executing.
The problem is, if I receive a signal, and start the handler, but am then interrupted by another signal. This (as I understand it) triggers a new execution of the signal handler, which will operate on the same global dataset - not permissible!
I can't use a lock, because if the first handler call is interrupted, it will naturally never free the lock for the interrupting handler to pick up. So, how do I do it? Any idea?
If you have the luck to be working in a multi-threaded environment, one of the best ways is to have the global linked list controlled exclusively by a separate thread. Interrupts would enqueue requests to this thread (something that would be executed very quickly, say, by simply passing a pointer), and then the thread would procedurally go through each request and modify the linked list. This allows lockless execution.
Of course, you have to rely on your OS's message passing junk, so that may not be an option.
You can mask signals while executing signal handler - check sa_mask field of struct sigaction you pass to sigaction() syscall.
From http://users.evtek.fi/~tk/rtp/signals-programming.html:
The way to guarantee no races at all, is to let the system set the signal masking for us before it calls the signal handler. This can be done if we use the sigaction() system call to define both the signal handler function AND the signal mask to be used when the handler is executed. You would probably be able to read the manual page for sigaction() on your own, now that you're familiar with the various concepts of signal handling. On old systems, however, you won't find this system call, but you still might find the sigvec() call, that enables a similar functionality.
I think you should seriate the signal.just like the work queue
E.g. all the signal should put into a work queue(FIFO), and then the executing thread poll the queue all the time. if the queue is not empty,this thread will pick the top signal and start it`s handler. keep doing like that, until the queue is empty.
Related
How can i run asynchrounous-unsafe code in a signal handler. I cant use a flag in my case. Could i use longjmp to jump to a different context?
In a signal handler you can only use a set of safe functions which in many cases is sufficient for complicated functionality started within a handler. You can check man pages for your system for 'signal-safety' or similar. Here is a pointer on the web: https://man7.org/linux/man-pages/man7/signal-safety.7.html
pthread synchronization functions are not on the list.
However, One of the function listed there is sem_post: https://man7.org/linux/man-pages/man3/sem_post.3.html
sem_post() is async-signal-safe: it may be safely called within a
signal handler.
So, you can implement mutex-like synchronization using semaphores within the signal handler.
In my program I need to perform some action upon timer (timer_create()) expiration. I want to perform this action by spawning a new thread. So I want to know if it is safe to create a thread in signal handlers?
Signal handlers may not call non re-entrant functions. You should look at your o/s documentation but creating a thread is unlikely to be re-entrant. On linux, man -s7 signal gives you a list of safe to call functions, which doesn't include anything from pthread.
Really all a signal handler should do is to set a flag for the main code or a signal handling thread to read. More than that gets risky.
With alarm function, I want to implement UDP retransmission. Is this function thread safe? Will it work under multi-threaded environment.
Calling alarm() in a thread will not reset pending signals, so you probably don't want to call it in a thread. You'd only want to call it within the parent no matter what language you are using if the underlying functionality is pthreads.
You'd probably be better off making provisions in a structure shared with the threads to re-send data as needed, or poke all (or some) running threads to resend upon servicing the signal in the parent.
I can't think of an implementation where calling it within a thread would be a good idea, so no - I wouldn't use it that way.
alarm() function is not thread safe.
Because it is process level. You can't control which thread should receive the signal once timer triggers. So at the time of signal arrival, another thread may be running. Sometimes it may crash you program with SIG_SEGV.
According to the docs alarm is "process-level" and only the last call is active... it uses the SIGNAL model and sends an async SIGALARAM to the process... whether the called signal handler is threadsafe depends on your implementation...
I am aware that i can mask a signal from being raised when handler is executing (by using sa_mask). However, i would like to know how to mask a signal when i am updating some global variables.
Also, i would like to know how to mask a signal when a particular user defined function is executing.
Is it possible to do these 2 things?
Any help will be appreciated
Thanks
You can call "signal()" any time you want; either to a) set the signal handler to some custom code, or b) clear it by setting the handler argument to NULL.
sigaction(), of course, gives you even finer-grained control. You can call sigaction whenever you wish (for example, before updating your global variables), too.
This link might help:
http://www.linuxjournal.com/article/6483
It's possible to block signals with sigblock(). Signals blocked will be queued and released when the signal is unblocked.
HOWEVER - this is super expensive. You have to do a syscall to block and a syscall to unblock. This can be quite slow if you do it often. So there are some alternative approaches:
If you're on linux, use signalfd. You can block all signals once and redirect them to a file descriptor, then handle them whenever it's safe to do so.
Otherwise (or if async signal handling is important), you can defer signals in userspace. Before entering your critical section, set a volatile flag. In your signal handler, check for this flag; if you see it, write() to a pipe the signal number and immediately return. In your signal handler, check back for a signal on this pipe, and re-raise the signal at that point.
I am writing a multithreaded program and i have this question:
Suppose that, while executing in the main thread, i want to terminate all
child-threads. I can't just send them a termination signal cause i want them
to free dynamically allocated memory first. Can i define a specific signal handler
function in each thread function that is executed, which in turn is going to call
a cleanup function that i will write to do so? If not how can i accomplish my goal??
Thanks,
Nikos
Look at the man page for pthread_cancel:
When a cancellation requested is acted on, the following steps occur for
thread (in this order):
1. Cancellation clean-up handlers are popped (in the reverse of the order in
which they were pushed) and called. (See pthread_cleanup_push(3).)
2. Thread-specific data destructors are called, in an unspecified order. (See
pthread_key_create(3).)
3. The thread is terminated. (See pthread_exit(3).)
So you can use pthread_cancel from your main, provided you have registered you cleanup handlers correctly using the above functions.
(Do read that man page completely though, it has a lot of important information.)
Edit: (from comments) If you plan on using PTHREAD_CANCEL_DEFERRED and need to insert a cancellation point somewhere in your code, then use pthread_testcancel. This function checks if a cancellation was requested. If that is the case, the cancellation is serviced (i.e. that call never returns). Otherwise it has no effect.
The most robust strategy requires cooperation from the child threads: you set a flag that the threads periodically check and, when the flag is set, free whatever resources they're using and then terminate.
Cancellation (Mat's answer) is the correct and canonical one, but if you want a different approach, you can install a no-op signal handler using sigaction without the SA_RESTART flag and use pthread_kill with whatever signal number you chose in order to interrupt (EINTR) whatever the thread might have been blocked on. Combined with this, aix's answer works.