2 * signal.c -- Signal Handler Library for Lua
4 * Version: 1.000+changes
6 * Copyright (C) 2007 Patrick J. Donnelly (batrick@batbytes.com)
8 * This software is distributed under the same license as Lua 5.0:
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
39 #if (LUA_VERSION_NUM == 501)
40 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
48 char *name
; /* name of the signal */
49 int sig
; /* the signal */
54 #define MAX_PENDING_SIGNALS 32
56 #define LUA_SIGNAL "lua_signal"
58 static const struct lua_signal lua_signals
[] = {
101 {"SIGALRM", SIGALRM
},
104 {"SIGCHLD", SIGCHLD
},
107 {"SIGCONT", SIGCONT
},
110 {"SIGSTOP", SIGSTOP
},
113 {"SIGTTIN", SIGTTIN
},
116 {"SIGTTOU", SIGTTOU
},
118 /* some BSD signals */
132 {"SIGXCPU", SIGXCPU
},
135 {"SIGXFSZ", SIGXFSZ
},
138 {"SIGVTALRM", SIGVTALRM
},
141 {"SIGPROF", SIGPROF
},
144 {"SIGWINCH", SIGWINCH
},
147 {"SIGPOLL", SIGPOLL
},
152 /* add odd signals */
154 {"SIGSTKFLT", SIGSTKFLT
}, /* stack fault */
162 static lua_State
*Lsig
= NULL
;
163 static lua_Hook Hsig
= NULL
;
164 static int Hmask
= 0;
165 static int Hcount
= 0;
167 int signals
[MAX_PENDING_SIGNALS
];
170 static void sighook(lua_State
*L
, lua_Debug
*ar
) {
172 /* restore the old hook */
173 lua_sethook(L
, Hsig
, Hmask
, Hcount
);
175 lua_pushstring(L
, LUA_SIGNAL
);
176 lua_gettable(L
, LUA_REGISTRYINDEX
);
178 for(int i
= 0; i
< nsig
; i
++) {
179 lua_pushnumber(L
, signals
[i
]);
186 lua_pop(L
, 1); /* pop lua_signal table */
190 static void handle(int sig
) {
192 /* Store the existing debug hook (if any) and its parameters */
193 Hsig
= lua_gethook(Lsig
);
194 Hmask
= lua_gethookmask(Lsig
);
195 Hcount
= lua_gethookcount(Lsig
);
197 /* Set our new debug hook */
198 lua_sethook(Lsig
, sighook
, LUA_MASKCALL
| LUA_MASKRET
| LUA_MASKCOUNT
, 1);
201 if(nsig
< MAX_PENDING_SIGNALS
) {
202 signals
[nsig
++] = sig
;
207 * l_signal == signal(signal [, func [, chook]])
209 * signal = signal number or string
210 * func = Lua function to call
211 * chook = catch within C functions
212 * if caught, Lua function _must_
213 * exit, as the stack is most likely
214 * in an unstable state.
217 static int l_signal(lua_State
*L
) {
218 int args
= lua_gettop(L
);
219 int t
, sig
; /* type, signal */
221 /* get type of signal */
225 if(t
== LUA_TNUMBER
) {
226 sig
= (int) lua_tonumber(L
, 1);
227 } else if(t
== LUA_TSTRING
) {
228 lua_pushstring(L
, LUA_SIGNAL
);
229 lua_gettable(L
, LUA_REGISTRYINDEX
);
233 if(!lua_isnumber(L
, -1)) {
234 return luaL_error(L
, "invalid signal string");
237 sig
= (int) lua_tonumber(L
, -1);
238 lua_pop(L
, 1); /* get rid of number we pushed */
240 luaL_checknumber(L
, 1); /* will always error, with good error msg */
241 return luaL_error(L
, "unreachable: invalid number was accepted");
245 if(args
== 1 || lua_isnil(L
, 2)) { /* clear handler */
246 lua_pushstring(L
, LUA_SIGNAL
);
247 lua_gettable(L
, LUA_REGISTRYINDEX
);
248 lua_pushnumber(L
, sig
);
249 lua_gettable(L
, -2); /* return old handler */
250 lua_pushnumber(L
, sig
);
253 lua_remove(L
, -2); /* remove LUA_SIGNAL table */
254 signal(sig
, SIG_DFL
);
256 luaL_checktype(L
, 2, LUA_TFUNCTION
);
258 lua_pushstring(L
, LUA_SIGNAL
);
259 lua_gettable(L
, LUA_REGISTRYINDEX
);
261 lua_pushnumber(L
, sig
);
265 /* Set the state for the handler */
268 if(lua_toboolean(L
, 3)) { /* c hook? */
269 if(signal(sig
, handle
) == SIG_ERR
) {
270 lua_pushboolean(L
, 0);
272 lua_pushboolean(L
, 1);
274 } else { /* lua_hook */
275 if(signal(sig
, handle
) == SIG_ERR
) {
276 lua_pushboolean(L
, 0);
278 lua_pushboolean(L
, 1);
287 * l_raise == raise(signal)
289 * signal = signal number or string
292 static int l_raise(lua_State
*L
) {
293 /* int args = lua_gettop(L); */
294 int t
= 0; /* type */
301 if(t
== LUA_TNUMBER
) {
302 ret
= (lua_Number
) raise((int) lua_tonumber(L
, 1));
303 lua_pushnumber(L
, ret
);
304 } else if(t
== LUA_TSTRING
) {
305 lua_pushstring(L
, LUA_SIGNAL
);
306 lua_gettable(L
, LUA_REGISTRYINDEX
);
310 if(!lua_isnumber(L
, -1)) {
311 return luaL_error(L
, "invalid signal string");
314 ret
= (lua_Number
) raise((int) lua_tonumber(L
, -1));
315 lua_pop(L
, 1); /* get rid of number we pushed */
316 lua_pushnumber(L
, ret
);
318 luaL_checknumber(L
, 1); /* will always error, with good error msg */
324 #if defined(__unix__) || defined(__APPLE__)
326 /* define some posix only functions */
329 * l_kill == kill(pid, signal)
332 * signal = signal number or string
335 static int l_kill(lua_State
*L
) {
337 lua_Number ret
; /* return value */
339 luaL_checknumber(L
, 1); /* must be int for pid */
340 luaL_checkany(L
, 2); /* check for a second arg */
344 if(t
== LUA_TNUMBER
) {
345 ret
= (lua_Number
) kill((int) lua_tonumber(L
, 1),
346 (int) lua_tonumber(L
, 2));
347 lua_pushnumber(L
, ret
);
348 } else if(t
== LUA_TSTRING
) {
349 lua_pushstring(L
, LUA_SIGNAL
);
350 lua_gettable(L
, LUA_REGISTRYINDEX
);
354 if(!lua_isnumber(L
, -1)) {
355 return luaL_error(L
, "invalid signal string");
358 ret
= (lua_Number
) kill((int) lua_tonumber(L
, 1),
359 (int) lua_tonumber(L
, -1));
360 lua_pop(L
, 1); /* get rid of number we pushed */
361 lua_pushnumber(L
, ret
);
363 luaL_checknumber(L
, 2); /* will always error, with good error msg */
371 static const struct luaL_Reg lsignal_lib
[] = {
372 {"signal", l_signal
},
374 #if defined(__unix__) || defined(__APPLE__)
380 int luaopen_util_signal(lua_State
*L
) {
381 #if (LUA_VERSION_NUM > 501)
382 luaL_checkversion(L
);
386 /* add the library */
388 luaL_setfuncs(L
, lsignal_lib
, 0);
390 /* push lua_signals table into the registry */
391 /* put the signals inside the library table too,
392 * they are only a reference */
393 lua_pushstring(L
, LUA_SIGNAL
);
396 while(lua_signals
[i
].name
!= NULL
) {
398 lua_pushstring(L
, lua_signals
[i
].name
);
399 lua_pushnumber(L
, lua_signals
[i
].sig
);
402 lua_pushstring(L
, lua_signals
[i
].name
);
403 lua_pushnumber(L
, lua_signals
[i
].sig
);
408 /* add newtable to the registry */
409 lua_settable(L
, LUA_REGISTRYINDEX
);