$search
00001 /* 00002 * lsignal.c -- Signal Handler Library for Lua 00003 * 00004 * Copyright (C) 2010 Patrick J. Donnelly (batrick@batbytes.com) 00005 * 00006 * This software is distributed under the same license as Lua 5.0: 00007 * 00008 * Permission is hereby granted, free of charge, to any person obtaining a 00009 * copy of this software and associated documentation files (the "Software"), 00010 * to deal in the Software without restriction, including without limitation 00011 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00012 * and/or sell copies of the Software, and to permit persons to whom the 00013 * Software is furnished to do so, subject to the following conditions: 00014 * 00015 * The above copyright notice and this permission notice shall be included 00016 * in all copies or substantial portions of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00019 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00020 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00021 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 00022 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00023 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00024 * OTHER DEALINGS IN THE SOFTWARE. 00025 */ 00026 00027 #define LUA_LIB_NAME "signal" 00028 #define LUA_LIB_VERSION 1.2 00029 #define LUA_SIGNAL_NAME "LUA_SIGNAL" 00030 00031 #if !(defined(_POSIX_SOURCE) || defined(sun) || defined(__sun)) 00032 #define INCLUDE_KILL 1 00033 #define INCLUDE_PAUSE 1 00034 #define USE_SIGACTION 1 00035 #endif 00036 00037 #include <lua.h> 00038 #include <lauxlib.h> 00039 00040 #include <assert.h> 00041 #include <errno.h> 00042 #include <signal.h> 00043 #include <stdlib.h> 00044 #include <string.h> 00045 00046 struct lua_signal 00047 { 00048 const char *name; /* name of the signal */ 00049 const int sig; /* the signal */ 00050 }; 00051 00052 static const struct lua_signal lua_signals[] = { 00053 /* ANSI C signals */ 00054 #ifdef SIGABRT 00055 {"SIGABRT", SIGABRT}, 00056 #endif 00057 #ifdef SIGFPE 00058 {"SIGFPE", SIGFPE}, 00059 #endif 00060 #ifdef SIGILL 00061 {"SIGILL", SIGILL}, 00062 #endif 00063 #ifdef SIGINT 00064 {"SIGINT", SIGINT}, 00065 #endif 00066 #ifdef SIGSEGV 00067 {"SIGSEGV", SIGSEGV}, 00068 #endif 00069 #ifdef SIGTERM 00070 {"SIGTERM", SIGTERM}, 00071 #endif 00072 /* posix signals */ 00073 #ifdef SIGHUP 00074 {"SIGHUP", SIGHUP}, 00075 #endif 00076 #ifdef SIGQUIT 00077 {"SIGQUIT", SIGQUIT}, 00078 #endif 00079 #ifdef SIGTRAP 00080 {"SIGTRAP", SIGTRAP}, 00081 #endif 00082 #ifdef SIGKILL 00083 {"SIGKILL", SIGKILL}, 00084 #endif 00085 #ifdef SIGUSR1 00086 {"SIGUSR1", SIGUSR1}, 00087 #endif 00088 #ifdef SIGUSR2 00089 {"SIGUSR2", SIGUSR2}, 00090 #endif 00091 #ifdef SIGPIPE 00092 {"SIGPIPE", SIGPIPE}, 00093 #endif 00094 #ifdef SIGALRM 00095 {"SIGALRM", SIGALRM}, 00096 #endif 00097 #ifdef SIGCHLD 00098 {"SIGCHLD", SIGCHLD}, 00099 #endif 00100 #ifdef SIGCONT 00101 {"SIGCONT", SIGCONT}, 00102 #endif 00103 #ifdef SIGSTOP 00104 {"SIGSTOP", SIGSTOP}, 00105 #endif 00106 #ifdef SIGTTIN 00107 {"SIGTTIN", SIGTTIN}, 00108 #endif 00109 #ifdef SIGTTOU 00110 {"SIGTTOU", SIGTTOU}, 00111 #endif 00112 /* some BSD signals */ 00113 #ifdef SIGIOT 00114 {"SIGIOT", SIGIOT}, 00115 #endif 00116 #ifdef SIGBUS 00117 {"SIGBUS", SIGBUS}, 00118 #endif 00119 #ifdef SIGCLD 00120 {"SIGCLD", SIGCLD}, 00121 #endif 00122 #ifdef SIGURG 00123 {"SIGURG", SIGURG}, 00124 #endif 00125 #ifdef SIGXCPU 00126 {"SIGXCPU", SIGXCPU}, 00127 #endif 00128 #ifdef SIGXFSZ 00129 {"SIGXFSZ", SIGXFSZ}, 00130 #endif 00131 #ifdef SIGVTALRM 00132 {"SIGVTALRM", SIGVTALRM}, 00133 #endif 00134 #ifdef SIGPROF 00135 {"SIGPROF", SIGPROF}, 00136 #endif 00137 #ifdef SIGWINCH 00138 {"SIGWINCH", SIGWINCH}, 00139 #endif 00140 #ifdef SIGPOLL 00141 {"SIGPOLL", SIGPOLL}, 00142 #endif 00143 #ifdef SIGIO 00144 {"SIGIO", SIGIO}, 00145 #endif 00146 /* add odd signals */ 00147 #ifdef SIGSTKFLT 00148 {"SIGSTKFLT", SIGSTKFLT}, /* stack fault */ 00149 #endif 00150 #ifdef SIGSYS 00151 {"SIGSYS", SIGSYS}, 00152 #endif 00153 {NULL, 0} 00154 }; 00155 00156 /* 00157 * The signal counts in the 1st half of the array are modified by 00158 * the handler. The corresponding signal counts in the 2nd half 00159 * are modifed by the hook routine. 00160 */ 00161 static volatile sig_atomic_t *signal_stack = NULL; 00162 static int signal_stack_top; 00163 static lua_State *ML = NULL; 00164 static struct hook { 00165 lua_Hook hook; 00166 int mask; 00167 int count; 00168 } old_hook = {NULL, 0, 0}; 00169 00170 static void hook (lua_State *L, lua_Debug *ar) 00171 { 00172 int i, j; 00173 assert(L == ML); 00174 for (i = 0; i < signal_stack_top; i++) 00175 while (signal_stack[i] != signal_stack[i+signal_stack_top]) 00176 { 00177 lua_getfield(L, LUA_REGISTRYINDEX, LUA_SIGNAL_NAME); 00178 lua_pushinteger(L, i); 00179 lua_rawget(L, -2); 00180 lua_replace(L, -2); /* replace _R.LUA_SIGNAL_NAME */ 00181 assert(lua_isfunction(L, -1)); 00182 for (j = 0; lua_signals[j].name != NULL; j++) 00183 if (lua_signals[j].sig == i) 00184 { 00185 lua_pushstring(L, lua_signals[j].name); 00186 break; 00187 } 00188 if (lua_signals[j].name == NULL) lua_pushliteral(L, ""); 00189 lua_pushinteger(L, i); 00190 lua_call(L, 2, 0); 00191 signal_stack[i+signal_stack_top]++; 00192 } 00193 lua_sethook(ML, old_hook.hook, old_hook.mask, old_hook.count); 00194 old_hook.hook = NULL; 00195 } 00196 00197 static void handle (int sig) 00198 { 00199 assert(ML != NULL); 00200 if (old_hook.hook == NULL) /* replace it */ 00201 { 00202 old_hook.hook = lua_gethook(ML); 00203 old_hook.mask = lua_gethookmask(ML); 00204 old_hook.count = lua_gethookcount(ML); 00205 lua_sethook(ML, hook, LUA_MASKCOUNT, 1); 00206 } 00207 signal_stack[sig]++; 00208 } 00209 00210 static int get_signal (lua_State *L, int idx) 00211 { 00212 switch (lua_type(L, idx)) 00213 { 00214 case LUA_TNUMBER: 00215 return (int) lua_tointeger(L, idx); 00216 case LUA_TSTRING: 00217 lua_pushvalue(L, idx); 00218 lua_rawget(L, LUA_ENVIRONINDEX); 00219 if (!lua_isnumber(L, -1)) 00220 return luaL_argerror(L, idx, "invalid signal string"); 00221 lua_replace(L, idx); 00222 return (int) lua_tointeger(L, idx); 00223 default: 00224 return luaL_argerror(L, idx, "expected signal string/number"); 00225 } 00226 } 00227 00228 static int status (lua_State *L, int s) 00229 { 00230 if (s) 00231 { 00232 lua_pushboolean(L, 1); 00233 return 1; 00234 } 00235 else 00236 { 00237 lua_pushnil(L); 00238 lua_pushstring(L, strerror(errno)); 00239 return 2; 00240 } 00241 } 00242 00243 /* 00244 * old_handler[, err] == signal(signal [, func]) 00245 * 00246 * signal = signal number or string 00247 * func/"ignore"/"default" = Lua function to call 00248 */ 00249 static int l_signal (lua_State *L) 00250 { 00251 enum {IGNORE, DEFAULT, SET}; 00252 static const char *options[] = {"ignore", "default", NULL}; 00253 int sig = get_signal(L, 1); 00254 int option; 00255 00256 if (lua_isstring(L, 2)) 00257 option = luaL_checkoption(L, 2, NULL, options); 00258 else if (lua_isnil(L, 2)) 00259 option = DEFAULT; 00260 else 00261 option = (luaL_checktype(L, 2, LUA_TFUNCTION), SET); 00262 00263 lua_pushvalue(L, 1); 00264 lua_rawget(L, LUA_ENVIRONINDEX); /* return old handler */ 00265 00266 lua_pushvalue(L, 1); 00267 switch (option) 00268 { 00269 case IGNORE: 00270 lua_pushnil(L); 00271 lua_rawset(L, LUA_ENVIRONINDEX); 00272 signal(sig, SIG_IGN); 00273 signal_stack[sig+signal_stack_top] = signal_stack[sig] = 0; 00274 break; 00275 case DEFAULT: 00276 lua_pushnil(L); 00277 lua_rawset(L, LUA_ENVIRONINDEX); 00278 signal(sig, SIG_DFL); 00279 signal_stack[sig+signal_stack_top] = signal_stack[sig] = 0; 00280 break; 00281 case SET: 00282 lua_pushvalue(L, 2); 00283 lua_rawset(L, LUA_ENVIRONINDEX); 00284 00285 #if USE_SIGACTION 00286 { 00287 struct sigaction act; 00288 act.sa_handler = handle; 00289 sigemptyset(&act.sa_mask); 00290 act.sa_flags = 0; 00291 if (sigaction(sig, &act, NULL)) 00292 return status(L, 0); 00293 } 00294 #else 00295 if (signal(sig, handle) == SIG_ERR) 00296 return status(L, 0); 00297 #endif 00298 break; 00299 default: assert(0); 00300 } 00301 00302 return 1; 00303 } 00304 00305 /* 00306 * status, err = raise(signal) 00307 * 00308 * signal = signal number or string 00309 */ 00310 static int l_raise (lua_State *L) 00311 { 00312 return status(L, raise(get_signal(L, 1)) == 0); 00313 } 00314 00315 #if INCLUDE_KILL 00316 00317 /* define some posix only functions */ 00318 00319 /* 00320 * status, err = kill(pid, signal) 00321 * 00322 * pid = process id 00323 * signal = signal number or string 00324 */ 00325 static int l_kill (lua_State *L) 00326 { 00327 return status(L, kill(luaL_checkinteger(L, 1), get_signal(L, 2)) == 0); 00328 } 00329 00330 #endif 00331 00332 #if INCLUDE_PAUSE 00333 00334 static int l_pause (lua_State *L) /* race condition free */ 00335 { 00336 sigset_t mask, old_mask; 00337 if (sigfillset(&mask) == -1) return status(L, 0); 00338 if (sigprocmask(SIG_BLOCK, &mask, &old_mask) == -1) return status(L, 0); 00339 if (sigsuspend(&old_mask) != -1) abort(); /* that's strange */ 00340 return status(L, 0); 00341 } 00342 00343 #endif 00344 00345 static int interrupted (lua_State *L) 00346 { 00347 return luaL_error(L, "interrupted!"); 00348 } 00349 00350 static int library_gc (lua_State *L) 00351 { 00352 if (ML == L) { 00353 lua_getfield(L, LUA_REGISTRYINDEX, LUA_SIGNAL_NAME); 00354 lua_pushnil(L); 00355 while (lua_next(L, -2)) 00356 { 00357 if (lua_isnumber(L, -2)) /* <signal, function> */ 00358 signal((int) lua_tointeger(L, -2), SIG_DFL); 00359 lua_pop(L, 1); /* value */ 00360 } 00361 signal_stack = NULL; 00362 ML = NULL; 00363 old_hook.hook = NULL; 00364 signal_stack_top = 0; 00365 } 00366 return 0; 00367 } 00368 00369 int luaopen_signal (lua_State *L) 00370 { 00371 static const struct luaL_Reg lib[] = { 00372 {"signal", l_signal}, 00373 {"raise", l_raise}, 00374 #if INCLUDE_KILL 00375 {"kill", l_kill}, 00376 #endif 00377 #if INCLUDE_PAUSE 00378 {"pause", l_pause}, 00379 #endif 00380 {NULL, NULL} 00381 }; 00382 00383 int i; 00384 int max_signal; 00385 00386 ML = L; 00387 if (lua_pushthread(L)) 00388 lua_pop(L, 1); 00389 else 00390 luaL_error(L, "library should be opened by the main thread"); 00391 00392 /* environment */ 00393 lua_newtable(L); 00394 lua_replace(L, LUA_ENVIRONINDEX); 00395 lua_pushvalue(L, LUA_ENVIRONINDEX); 00396 lua_setfield(L, LUA_REGISTRYINDEX, LUA_SIGNAL_NAME); /* for hooks */ 00397 00398 /* add the library */ 00399 luaL_register(L, LUA_LIB_NAME, lib); 00400 lua_pushnumber(L, LUA_LIB_VERSION); 00401 lua_setfield(L, -2, "version"); 00402 00403 for (i = 0, max_signal = 0; lua_signals[i].name != NULL; i++) 00404 if (lua_signals[i].sig > max_signal) 00405 max_signal = lua_signals[i].sig+1; /* +1 !!! (for < loops) */ 00406 00407 signal_stack = lua_newuserdata(L, sizeof(volatile sig_atomic_t)*max_signal*2); 00408 lua_newtable(L); 00409 lua_pushcfunction(L, library_gc); 00410 lua_setfield(L, -2, "__gc"); 00411 lua_setmetatable(L, -2); /* when userdata is gc'd, close library */ 00412 memset((void *) signal_stack, 0, sizeof(volatile sig_atomic_t)*max_signal*2); 00413 signal_stack_top = max_signal; 00414 lua_pushboolean(L, 1); 00415 lua_rawset(L, LUA_ENVIRONINDEX); 00416 00417 while (i--) /* i set from previous for loop */ 00418 { 00419 lua_pushstring(L, lua_signals[i].name); 00420 lua_pushinteger(L, lua_signals[i].sig); 00421 lua_rawset(L, LUA_ENVIRONINDEX); /* add copy to environment table */ 00422 lua_pushstring(L, lua_signals[i].name); 00423 lua_pushinteger(L, lua_signals[i].sig); 00424 lua_settable(L, -3); /* add copy to signal table */ 00425 } 00426 00427 /* set default interrupt handler */ 00428 lua_getfield(L, -1, "signal"); 00429 lua_pushinteger(L, SIGINT); 00430 lua_pushcfunction(L, interrupted); 00431 lua_call(L, 2, 0); 00432 00433 return 1; 00434 }