justincormack / ljsyscall

LuaJIT Unix syscall FFI
http://www.myriabit.com/ljsyscall/
Other
440 stars 53 forks source link

Signal masked with custom handler ignored #187

Closed dpino closed 8 years ago

dpino commented 8 years ago

I'm try to mask a signal with my own handler. Here is my code:

local S = require("syscall")

local SIGINT = 1

local function handler(signo)
   if signo == SIGINT then
      print("Catched SIGINT")
   end
end

S.signal(SIGINT, handler)
while 1 do S.sleep(1) end

I run it and press Ctrl+C to emit a SIGINT signal. Here's the result:

 $ luajit test-signal.lua
^Cluajit: ./syscall/linux/c.lua:71: interrupted!
stack traceback:
    ./syscall/linux/c.lua:71: in function 'nanosleep'
    ./syscall/syscalls.lua:849: in function 'nanosleep'
    ./syscall/compat.lua:139: in function 'sleep'
    test-signal.lua:12: in main chunk
    [C]: at 0x004042a0

The handler is not triggered. I coded a similar test in C. It looks like this:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void handler(int signo)
{
    if (signo == SIGINT) {
        printf("Catched SIGINT\n");
    }
}

int main(void)
{
    if (signal(SIGINT, handler) == SIG_ERR) {
        printf("Couldn't initialize signal");
    }
    while (1) sleep(1);
    return 0;
}

This is the result:

$ ./test-signal 
^CCatched SIGINT

I expected the Lua test case to work similarly to the C test case. I'm doing anything wrong? Maybe I'm not using the signal function correctly. My system is Ubuntu 15.04 x86_64 LuaJIT 2.0.4.

justincormack commented 8 years ago

I don't recommend doing that, as it is unclear if it is safe to write handler functions in Lua, and I had a lot of problems when writing the tests, the code may actually be disabled, I need to check (travelling at the minute).

I recommend you use signalfd to process signals (kqueue on BSD platforms) as this avoids all the issues with signal handlers and is a nicer interface. This just means you mask the signal without making a handler.

dpino commented 8 years ago

Thanks, I followed your advice. I coded the example above using signalfd. I leave it here for reference:

local S = require("syscall")
local util = S.util

local function empty(sig)
   return type(sig) == "table" and #sig == 0
end

local ss = "int"
local fd = assert(S.signalfd(ss, "nonblock"))
assert(S.sigprocmask("block", ss))

while 1 do
   local sig = assert(util.signalfd_read(fd))
   if not empty(sig) then
      if sig[1].int then
         print("Cought SIGINT")
      end
   end
end
lukego commented 8 years ago

I also followed this advice from Justin when implementing SnabbCo/snabbswitch#629.