Reading shared data inside a signal handler
Asked Answered
C

4

9

I am in a situation where I need to read a binary search tree (BST) inside a signal handler (SIGSEGV signal handler, which according to my knowledge is per thread base). The BST can be modified by the other threads in the application.

Now since a signal handler can't use semaphores, mutexes etc. and therefore can't access shared data, How do I solve this problem? Note that my application is multithreaded and running on a multicore system.

Campanology answered 13/12, 2011 at 16:0 Comment(8)
I would try really, really hard, to think of a way to not read shared data in that signal handler.Lordosis
To emphasize the point of @dbeer, in a signal handler you should generally not do anything that will block or raise other signals, or any lengthy operations. A signal handler should be small, quick and short.Belldas
Maybe I'm missing something, but if only the threads of your program access the shared memory (no other interrupts and exceptions), why could you not use a semaphore (whether it's good style is a different question)? If a thread accesses the critical region, blocks it, is put to sleep by another thread, the semaphore is still locked for the other thread, and eventually your initial thread will be scheduled to access it again. Performance reasons aside, I see neither a danger of data corruption nor stalling the system.Archery
@gnometorule: You mean I can use the semaphore in both the signal handler and threads?Campanology
On theoretical grounds, it seems to me that's ok. The kernel itself, say, protects critical regions accessed by only exceptions using sometimes only semaphores - in UP and MP architectures. However, I'm not terribly practically experienced with these issues in user space, and might overlook something. As I outlined above, I just don't see how in your case it could lead to issues.Archery
The danger of accessing shared data in a signal handler is easy to show: thread A locks shared data X, and while it holds the lock it handles a signal, calling the signal handler, which tries to lock data X. Deadlock!Lordosis
@Lordosis How about a recursive mutex then? :)Wenoa
@mlvjr switch the example to thread B locks data X, thread A is interrupted for the signal handler, and then it blocks because the lock is being held by B, while B never advances due to the signal handler being active.Lordosis
D
4

You shouldn't access shared data from signal handler. You can find out more information about signals in following articles:

Linux Signals for the Application Programmer

The Linux Signals Handling Model

All about Linux signals

Looks like the safest way to deal with signals in linux so far is signalfd.

Deipnosophist answered 13/12, 2011 at 16:15 Comment(0)
M
4

I can see two quite clean solutions:

  1. Linux-specific: Create a dedicated thread handling signals. Catch signals using signalfd(). This way you will handle signals in a regular thread, not any limited handler.
  2. Portable: Also use a dedicated thread that sleeps until signal is received. You may use a pipe to create a pair of file descriptors. The thread may read(2) from the first descriptor and in a signal handler you may write(2) to the second descriptor. Using write() in a signal handler is legal according to POSIX. When the thread reads something from the pipe it knows it must perform some action.
Mana answered 2/12, 2012 at 16:58 Comment(0)
A
3

Assuming the SH can't access the shared data directly, then maybe you could do it indirectly:

  1. Have some global variable that only signal handlers can write to, but can be read from elsewhere (even if only within the same thread).
  2. SH sets the flag when it is invoked
  3. Threads poll this flag when they are not in the middle of modifying the BST; when the find it set, they do the processing that is required by the original signal (using whatever synchronizations are necessary), and then raise a different signal (like SIGUSR1) to indicate that the processing is done
  4. The SH for THAT signal resets the flag

If you're worried about overlapping SIGSEGVs, add a counter to the mix to keep track. (Hey! You just built your own semaphore!)

The weak link here is obviously the polling, but its a start.

Ammamaria answered 13/12, 2011 at 16:18 Comment(2)
I was thinking exactly the same thing :-p! But what will happen when a thread is modifying the BST when the signal occurs. That point is a little worrisome.Campanology
I think that wouldn't be a problem: the signal will get caught, set the flag & return; the thread will continue modifying the BST, and won't try to "handle" the signal until it is done w/ its modification. Assuming that such modifications are to be atomic, that seems like a reasonable outcome.Ammamaria
R
1

You might consider mmap-ing a fuse file system (in user space).

Actually, you'll be more happy on Gnu Hurd which has support for external pagers

And perhaps your hack of reading a binary search tree in your signal handler could often work in practice, non-portably and in a kernel version dependent way. Perhaps serializing access with low-level non portable tricks (e.g. futexes and atomic gcc builtins) might work. Reading the (machine specific) source code of NPTL i.e. current Linux pthread routines should help.

It could probably be the case that pthread_mutex_lock etc are in fact usable from inside a Linux signal handler... (because it probably does only futex and atomic instructions).

Randi answered 13/12, 2011 at 17:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.