/***************************************************************************
*
* 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 <
http://www.gnu.org/licenses/>.
*
* Comments, questions and criticisms can be sent to:
[email protected]
*
* =======================================================================
*
* 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 <stdbool.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <syslog.h>
#include <lua.h>
/***************************************************************************/
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;
}