1#!/usr/local/bin/lua52 2-- 3-- Solaris has no analog to *BSD EVFILT_SIGNAL or Linux signalfd. Rather 4-- than using tricks (signal handlers + pipes, or thread + sigwait + pipe) 5-- which create troublesome global state, especially on fork, the default 6-- signal listener implementation just uses a short timeout for Solaris. 7-- 8-- Most of the time signals are used for simple process management. The most 9-- portable solution for immediate signal response I can come up with is to 10-- use two signals. One signal will be used to interrupt the process, and 11-- another for queueing and retrieval. (Note that you can't do both. Neither 12-- blocked nor ignored signals guarantee a syscall interrupt.) We install a 13-- dummy handler for the interrupt signal, and block both signals. Then we 14-- use pselect (cqueue:pause()) to wait around for either I/O or our 15-- interrupt. When we wake up, we check for any queued signals and process 16-- any I/O. 17-- 18-- There's one more caveat, however. pselect is broken on OS X. Therefore, 19-- for the most portable solution we use both methods: polling a signal 20-- listener descriptor, and a loop using pselect(). 21-- 22-- If all is working well, then the following script should print "sent 23-- SIGTERM" and "rcvd SIGTERM" in rapid succession on all supported 24-- platforms. 25-- 26local cqueues = require("cqueues") 27local signal = require("cqueues.signal") 28 29local cq = cqueues.new() 30 31local sl = signal.listen(signal.SIGTERM, signal.SIGINT) 32 33signal.discard(signal.SIGINT) 34signal.block(signal.SIGTERM, signal.SIGINT) 35 36 37cq:wrap(function() 38 -- Change the default Solaris timeout so we can confirm we're waking 39 -- up from an interrupt, and not just timing out. 40 sl:settimeout(30) 41 42 while true do 43 sl:wait() 44 end 45end) 46 47 48cq:wrap(function() 49 local i = 0 50 51 while true do 52 cqueues.sleep(2) 53 54 i = i + 1 55 56 if i > 2 then 57 os.exit() 58 end 59 60 signal.raise(signal.SIGTERM) 61 print("sent", signal.SIGTERM, signal[signal.SIGTERM]) 62 signal.raise(signal.SIGINT) 63 end 64end) 65 66 67while not cq:empty() do 68 local signo = sl:wait(0.0) 69 70 if signo then print("rcvd", signo, signal[signo]) end 71 72 local ok, err = cq:step(0.0) 73 if not ok then error(err) end 74 cq:pause(signal.SIGINT) 75end 76 77