/ Shayon Mukherjee / blog

Fetch current signal handlers without overriding in Ruby

December 29, 2017
~3 mins

Lately I have been very interested about Signal handling. So, this holiday season I embarked on a journey of writing a small project.

One thing I noticed when inspecting signals is that there isn’t really an easy way of doing so. Or, especially, getting the “current” action handler for a given Signal. For instance, whether a signal (TERM, INT, etc) has an action of SIG_DFL or SIG_IGN or a pointer reference.

Maybe its not a very common use case. Either way, while working on a few ruby projects, I went super deep into signal handling and would have loved to have a tool that would give me the action handlers for signals. There are some ways suggested in ruby, like:

old_handler = Signal.trap("TERM", "DEFAULT")

# do something with old_handler

Signal.trap("TERM", old_handler) # restore it back

Signal.trap returns the old handler for the given signal. So, here you can trap a signal with a different action and upon retrieval, restore it back and this way you can know what the “current” action is.

I found this solution a little too aggressive. Because of the non-atomicity, a lot of things can happen between overriding a signal’s action and restoring back, depending on the application.

To see how things worked internally, I went down digging ruby’s signal.c.

I loved learning more about ruby internals. I can’t wait to dive deeper and learn more about ruby and behind the scenes.

That said, basically, it boils down to how the class is using C library function signal (source code: here) and a few other implementations. A little about signal:

signal() sets the disposition of the signal signum to handler, which  is either SIG_IGN, SIG_DFL, or the address of a programmer-defined  function (a “signal handler”).

source: http://man7.org/linux/man-pages/man2/signal.2.html

Given this, I decided to explore other avenues where I can retrieve a signal’s action handler much more gracefully.

Meet SignalActionHandler

SignalActionHandler, a ruby gem, which uses C library function sigaction (man page), to return the active/current action handlers on a given signal.

Example:

SignalActionHandler.info
=> {
 "EXIT" => "DEFAULT",
 "HUP" => "DEFAULT",
 "INT" => "DEFAULT",
 "QUIT" => "DEFAULT",
 "ILL" => "DEFAULT",
 "TRAP" => "SYSTEM_DEFAULT",
 "ABRT" => "SYSTEM_DEFAULT",
 "IOT" => "SYSTEM_DEFAULT",
 "EMT" => "SYSTEM_DEFAULT",
 "FPE" => "SYSTEM_DEFAULT",
...
 }

Now, you can easily tell the action handlers of any signal, without having to override or restore it.

Note: The gem has a minor limitation of not being able to parse any pointer references as action handler. So, it displays them as a handler set by ruby (which is originally the case).

Writing a Ruby gem with C extension

I feel, the best part about this little holiday project was being able to write a Ruby C extension. Building a C extension in ruby is absolutely painless. The ruby C api is not very hard to understand (requires some basic C understanding but thats all) and can easily be exposed to any extension.

If you are interested in building C extensions, here are some places that I found helpful.

Lastly, if you have run into this scenario or have built similar tools around inspecting Signals, or if you have any feedback on the new gem, I’d love to hear from you.

last modified March 3, 2019