I'm trying to figure out how to use signal handlers in C via sigaction and it's desperately confusing. signal() is extremely straightforward, and works, but apparently Linux dictates it can't handle asynchronous processes, so I have to use sigaction. The confusing bit for me is how in signal(), one can very easily refer to various signal handler functions and it will automatically do the handling. I'm extremely confused on how this works with sigaction(). Do I simply add a secong sigaction struct?
Thanks in advance
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.
The following is from the man page of signal
The behavior of signal() varies across UNIX versions, and has also varied
historically across different versions of Linux. Avoid its use: use sigacā
tion(2) instead. See Portability below.
Does that mean that we should always use the sigaction call instead of using signal ?
Yes. You've already identified the Linux reference, and POSIX says the same thing:
The sigaction() function supersedes the signal() function, and should be used in preference.
sigaction addresses the historical inconsistencies in signal by forcing the user to make decisions about syscall interruption (SA_RESTART), handler interruption (sa_mask, SA_NODEFER), child handling (SA_NOCLD[WAIT|STOP]), disposition permanence (SA_RESETHAND), and more.
I have a test program for part of a C library where I handle signals. There is a lot of code in this test program - so much that I feel that posting it here would only make it more difficult to answer my question.
Basically what's happening is that I am forcing the system to send me a SIGSEGV inside a background thread. I handle that signal, and then the test is over. The main thread will be waiting for this and part of the signal handler is to restart the main thread. When the main thread restarts I restore the default signal handler by signal(SIGSEGV, SIG_DFL) and then I get another SIGSEGV.
I understand that I have a lot of code and this could very well be my fault, but is there a common explanation of why a SIGSEGV would fire twice? It is not happening when I cause other signals (though I haven't tried all of them).
To clarify I am on OS X, writing in C, compiling with gcc.
If you have any problem inside the signal handler, for example, memory overwrite, trying to access beyond the allocated area, then a new signal will be raised. Check the following page for details.
http://www.gnu.org/software/libc/manual/html_node/Signals-in-Handler.html
You should also use reentrant functions inside the signal handlers, For example localtime_r instead of localtime.
Moreover it is recommended to use sigaction() instead of signal().
More details here: What is the difference between sigaction and signal?
This is somewhat of a followup to related question I found
here.
In the linked question there is a mention of using signalfd() and using that fd with libevent. In that question the OP does not list why he is using signalfd() as opposed to the libevent signal handling facilities.
In both methods you would be processing the callback outside of the signal-handler.
This documentation seems to warn about scheduling timer in the signal event callback. Which doesn't seem right (as we would be outside of a signal handler context). Aside for said warning I cant see a benefit to doing this with signalfd().
Any input about the difference between the two methods or about the warning
Thanks!
from libevent's source code (v2.0.19-stable)
/* signal.c
This is the signal-handling implementation we use for backends that
don't have a better way to do signal handling. It uses sigaction()
or signal() to set a signal handler, and a socket pair to tell the
event base when
Note that I said "the event base" : only one event base can be set
up to use this at a time. For historical reasons and backward
compatibility, if you add an event for a signal to event_base A,
then add an event for a signal (any signal!) to event_base B,
event_base B will get informed about the signal, but event_base A
won't.
It would be neat to change this behavior in some future version of
Libevent. kqueue already does something far more sensible. We can
make all backends on Linux do a reasonable thing using signalfd.
*/
so right now libevent uses sigaction() if it's available, and, failing that, signal().
if you use signalfd() you usually block the signal using sigprocmask so that the signals won't cause the default handlers to execute. then, you can monitor the returned file handle using libevent and handle the signal from normal synchronous code safely, without having to worry about memory safety or blocking or interrupting other syscalls.
there are restrictions on what you can safely do inside classic asynchronous signal handlers (i.e. those registered using sigaction). See the "Async-signal-safe functions" in man signal. Using the signalfd approach, these restrictions are greatly lessened.
the warning about registering a timer callback was likely put there as a concern because libevent supports so many platforms, and at least one person reported problems. note that if you are selecting/polling a file handle registered by signalfd then you don't have to worry about this restriction anyways.
EDIT: i re-read your question and realized I hadn't really answered it properly. the benefit of registering a signalfd and then using that in libevent is because it's faster at the expense of portability. there were plans (http://archives.seul.org/libevent/users/Mar-2010/msg00046.html) to include signalfd into libevent but AFAIK it hasn't happened yet.
also, once you've been notified of the SIGCHLD you should always call waitpid in a loop until you get ENOCHLD because both methods will collapse multiple occurences of the signal.
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.