justincormack / ljsyscall

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

epoll_wait SIGSTOP/SIGCONT - attempt to call nil value #166

Closed houseofkodai closed 10 years ago

houseofkodai commented 10 years ago

when SIGSTOP CTRL+Z is given to a running program and SIGCONT (bg/fg) is given - epoll_wait goes for a toss - groks with "attempt to call a nil value"

replicable by running the following code - hitting CTRL+Z and then bg/fg from shell

local S = require 'syscall'

local ep = S.epoll_create()
ep:epoll_ctl('add', 0, 'in') --stdin
local epevents = S.t.epoll_events(2)
local epwait = function(timeout) return ep:epoll_wait(epevents, timeout) end 
while true do
  for i,evnt in epwait() do
    if evnt.IN then io.read() end
  end
end
justincormack commented 10 years ago

The issue is the slightly non intuitive iterator interface of epoll_wait (and some other similar functions). Maybe I should change this, but I am not sure how best to. The following works:

local S = require 'syscall'

local ep = S.epoll_create()
ep:epoll_ctl('add', 0, 'in') --stdin
local epevents = S.t.epoll_events(2)
local epwait = function(timeout) return ep:epoll_wait(epevents, timeout) end 
while true do
  local f, a, r = epwait()
  if f then
    for i,evnt in f, a, r do
      if evnt.IN then io.read() end
    end
  else print(a) end
end

The issue is if epoll_wait gets an error it returns nil, error (like all other syscalls do), but this is not a valid iterator (which must start with a function, hence the calling nil). You could wrap it to return an iterator that just terminates if you dont really care about errors, like this:

local S = require 'syscall'

local ep = S.epoll_create()
ep:epoll_ctl('add', 0, 'in') --stdin
local epevents = S.t.epoll_events(2)
local epwait = function(timeout)
  local function nilf() return nil end
  local f, a, r = ep:epoll_wait(epevents, timeout)
  if f then return f, a, r else return nilf end
end 
while true do
  for i,evnt in epwait() do
    if evnt.IN then io.read() end
  end
end
houseofkodai commented 10 years ago

Thanks for the prompt response - this works.

Yes the iterator logic is a bit confusing; but the lack of sample code made discovering its' proper usage more difficult.

May I suggest that this logic be used in the sample/testing code (epoll.lua) - which is what I referred to first, and I'm guessing that others would too. of course, the next thing I did was search the issues and posted this, since I did not find something similar.