Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is execution of signal handler un-preemptible in linux?

I have a process p registered with a signal handler for SIGALRM. A timer is setup to periodically send signal SIGALRM to process p. There are also multiple threads running in process p. Is the signal handler, when being triggered and executed, un-preemptible? Or to say, is it that the execution of signal handler will not be interrupted by any thread in process p?

PS: I thought signal handler is executed in kernel (is it?) and kernel is unpreemptive to user-mode threads? Correct me if it's wrong...

like image 388
Richard Avatar asked May 25 '11 17:05

Richard


People also ask

Are signal handlers executed in kernel mode?

The kernel process then uses the signal number to determine which action should be taken. The kernel does not automatically call signal handlers for a kernel process as it does for user processes.

Where are signal handlers executed?

Signal handlers usually execute on the current stack of the process. This lets the signal handler return to the point that execution was interrupted in the process. This can be changed on a per-signal basis so that a signal handler executes on a special stack.

What are signal handlers in Linux?

Signal Handlers. A signal handler is special function (defined in the software program code and registered with the kernel) that gets executed when a particular signal arrives. This causes the interruption of current executing process and all the current registers are also saved.

Can signal handler be interrupted?

Signal handlers can be interrupted by signals, including their own. If a signal is not reset before its handler is called, the handler can interrupt its own execution. A handler that always successfully executes its code despite interrupting itself or being interrupted is async-signal-safe.


1 Answers

Pretty much - don't - dealing with shared data in a signal handler almost always leads to a world of pain, dealing with threads as well and you got yourself a mess.

By default a signal is blocked while the signal handler is running (at least on linux, that might not be universally true), so at least the signal handler will not be preempted by itself. Though, if you have multiple threads, and the signal is not blocked in the other threads, a signal handler might very well be run concurrently within several threads.

One thread will receive the signal and execute the handler, it's more or less random which thread that'll be, although you could control it by blocking the signal in all threads you don't want to handle the signal.

However, any of the other threads bar the one handling the signal might run in parallell. The thread handling a signal could run the signal handler at pretty much any point in the program (as long as the signal isn't blocked.) So, you'd need some sort of locking to protect that data. The problem is you can't use any of the normal thread locking primitives, they are not signal async safe. Meaning if you e.g. try to grab a pthread_mutex_t in a signal handler, you easily deadlock your program.

The only functions you can safely call in a signal handler are the ones listed here . With regards to protecting the shared data, you could use sigblock()/sigunblock() as a sort of protection, ensuring the signal handler doesn't run while you're accessing that shared data - and the signal have to blocked in all the threads, otherwise it'll just run within one of the threads that doesn't have it blocked - going down that road is madness.

Pretty much the only shared data you can safely access in a signal handler is a sig_atomic_t type, in practice other kinds of primitive types usually safe too.

What you really should do in a signal handler is just

  • set a global flag
  • check that flag elsewhere in code when suitable, and take action

Or

  • have some sort of main loop that monitors file descriptors for events using select()/poll() or similar.
  • create a pipe and monitor that in your main loop
  • write() a byte to a pipe in your signal handler
  • run your code to deal with the signal, including protecting any shared data when the mainloop detects an event on that pipe

Or

  • Keep a spare thread around
  • block the given signal in all your threads
  • have that spare thread loop on calling sigsuspend() with a signal mask ensuring delivery of that signal.
  • run your code, including protecting any shared data to deal with the signal when sigsuspend() returns
like image 91
Lyke Avatar answered Oct 20 '22 14:10

Lyke