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