/*************************************************************************** * * Copyright 2016 by Sean Conner. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Comments, questions and criticisms can be sent to: sean@conman.org * * ======================================================================= * * This entire file exists *because* I can't properly handle SIGCHLD in the * server process. What I want to do is just get the reason for a handler * process terminating, but not wanting to deal with EINTR, so I set the * handler to restart system calls. But while I can do that in Lua, the Lua * signal handler doesn't get control until the Lua VM gets control, and if * we're sitting in a system call, that might take some time. So, we do this * in C, which can get the job done. * * This code is straightforward---just export a single function to Lua that * run called, catches SIGCHLD, and the signal handler will reap the * children. * *************************************************************************/ #ifdef __GNUC__ # define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include /***************************************************************************/ static void handle_sigchld(int sig __attribute__((unused))) { while(true) { int status; pid_t child = waitpid(-1,&status,WUNTRACED | WCONTINUED | WNOHANG); if (child < 0) { if (errno == ECHILD) return; syslog(LOG_ERR,"waitpid() = %s",strerror(errno)); } else if (child == 0) return; else { if WIFEXITED(status) { if (WEXITSTATUS(status) != 0) syslog(LOG_ERR,"handler process %d returned %d",(int)child,WEXITSTATUS(status)); } else syslog(LOG_ERR,"handler process %d aborted: %s",(int)child,strsignal(WTERMSIG(status))); } } } /***************************************************************************/ int luaopen_reapchild(lua_State *L) { struct sigaction act; act.sa_handler = handle_sigchld; act.sa_flags = SA_RESTART; sigemptyset(&act.sa_mask); lua_pushboolean(L,sigaction(SIGCHLD,&act,NULL) == 0); return 1; } .