From 1853168ac9b85627a95a8067ef5c6cdc9f82b16d Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Fri, 8 Jun 2007 13:57:19 +0000 Subject: [PATCH] Process management/respawn. Bug #1173. PID file pazpar2.pid generated by default. --- src/Makefile.am | 5 +- src/pazpar2.c | 41 ++++++++----- src/pazpar2.h | 6 +- src/process.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 19 deletions(-) create mode 100644 src/process.c diff --git a/src/Makefile.am b/src/Makefile.am index 28f5788..7a70b39 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.25 2007-05-23 11:19:31 marc Exp $ +# $Id: Makefile.am,v 1.26 2007-06-08 13:57:19 adam Exp $ bin_PROGRAMS = pazpar2 icu_chain_test @@ -29,7 +29,8 @@ libpazpar2_a_SOURCES = config.c config.h eventl.c eventl.h \ util.c util.h zeerex.c zeerex.h database.c database.h \ settings.h settings.c sel_thread.c sel_thread.h getaddrinfo.c \ charsets.c charsets.h \ - client.c client.h connection.c connection.h host.h parameters.h + client.c client.h connection.c connection.h host.h parameters.h \ + process.c pazpar2_SOURCES = pazpar2.c pazpar2_LDADD = libpazpar2.a $(YAZLIB) $(ICU_LIBS) diff --git a/src/pazpar2.c b/src/pazpar2.c index e19a98a..6efd068 100644 --- a/src/pazpar2.c +++ b/src/pazpar2.c @@ -1,4 +1,4 @@ -/* $Id: pazpar2.c,v 1.86 2007-06-06 11:49:48 marc Exp $ +/* $Id: pazpar2.c,v 1.87 2007-06-08 13:57:19 adam Exp $ Copyright (c) 2006-2007, Index Data. This file is part of Pazpar2. @@ -31,10 +31,32 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "database.h" #include "settings.h" +void child_handler(void *data) +{ + yaz_log(YLOG_LOG, "child_handler"); + + start_proxy(); + //start_zproxy(); + init_settings(); + + if (*global_parameters.settings_path_override) + settings_read(global_parameters.settings_path_override); + else if (global_parameters.server->settings) + settings_read(global_parameters.server->settings); + else + yaz_log(YLOG_WARN, "No settings-directory specified"); + global_parameters.odr_in = odr_createmem(ODR_DECODE); + global_parameters.odr_out = odr_createmem(ODR_ENCODE); + + + pazpar2_event_loop(); +} + int main(int argc, char **argv) { int ret; char *arg; + const char *pidfile = "pazpar2.pid"; if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) yaz_log(YLOG_WARN|YLOG_ERRNO, "signal"); @@ -94,21 +116,8 @@ int main(int argc, char **argv) global_parameters.server = config->servers; start_http_listener(); - start_proxy(); - //start_zproxy(); - init_settings(); - - if (*global_parameters.settings_path_override) - settings_read(global_parameters.settings_path_override); - else if (global_parameters.server->settings) - settings_read(global_parameters.server->settings); - else - yaz_log(YLOG_WARN, "No settings-directory specified"); - global_parameters.odr_in = odr_createmem(ODR_DECODE); - global_parameters.odr_out = odr_createmem(ODR_ENCODE); - - pazpar2_event_loop(); - + pazpar2_process(global_parameters.debug_mode, 0, child_handler, 0, + pidfile, 0); return 0; } diff --git a/src/pazpar2.h b/src/pazpar2.h index c74b5fe..ff005ee 100644 --- a/src/pazpar2.h +++ b/src/pazpar2.h @@ -1,4 +1,4 @@ -/* $Id: pazpar2.h,v 1.37 2007-06-06 11:49:48 marc Exp $ +/* $Id: pazpar2.h,v 1.38 2007-06-08 13:57:19 adam Exp $ Copyright (c) 2006-2007, Index Data. This file is part of Pazpar2. @@ -175,6 +175,10 @@ struct record *ingest_record(struct client *cl, Z_External *rec, void session_alert_watch(struct session *s, int what); void pull_terms(NMEM nmem, struct ccl_rpn_node *n, char **termlist, int *num); +int pazpar2_process(int debug, int flags, + void (*work)(void *data), void *data, + const char *pidfile, const char *uid); + #endif /* diff --git a/src/process.c b/src/process.c new file mode 100644 index 0000000..9a97da7 --- /dev/null +++ b/src/process.c @@ -0,0 +1,173 @@ +/* $Id: process.c,v 1.1 2007-06-08 13:57:19 adam Exp $ + Copyright (c) 2006-2007, Index Data. + +This file is part of Pazpar2. + +Pazpar2 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 2, or (at your option) any later +version. + +Pazpar2 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 Pazpar2; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#if HAVE_CONFIG_H +#include "cconfig.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "pazpar2.h" + +static void write_pidfile(const char *pidfile) +{ + if (pidfile) + { + FILE *f = fopen(pidfile, "w"); + if (!f) + { + yaz_log(YLOG_ERRNO|YLOG_FATAL, "Couldn't create %s", pidfile); + exit(0); + } + fprintf(f, "%ld", (long) getpid()); + fclose(f); + } +} + +pid_t child_pid = 0; +void kill_child_handler(int num) +{ + if (child_pid) + kill(child_pid, num); +} + +int pazpar2_process(int debug, int flags, + void (*work)(void *data), void *data, + const char *pidfile, const char *uid /* not yet used */) +{ + int run = 1; + int cont = 1; + void (*old_sighup)(int); + void (*old_sigterm)(int); + + + if (debug) + { + /* in debug mode.. it's quite simple */ + write_pidfile(pidfile); + work(data); + exit(0); + } + /* running in production mode. */ + + /* keep signals in their original state and make sure that some signals + to parent process also gets sent to the child.. Normally this + should not happen. We want the _child_ process to be terminated + normally. However, if the parent process is terminated, we + kill the child too */ + old_sighup = signal(SIGHUP, kill_child_handler); + old_sigterm = signal(SIGTERM, kill_child_handler); + while (cont) + { + pid_t p = fork(); + pid_t p1; + int status; + if (p == (pid_t) (-1)) + { + + yaz_log(YLOG_FATAL|YLOG_ERRNO, "fork"); + exit(1); + } + else if (p == 0) + { + /* child */ + signal(SIGHUP, old_sighup); /* restore */ + signal(SIGTERM, old_sigterm);/* restore */ + + write_pidfile(pidfile); + work(data); + exit(0); + } + + /* enable signalling in kill_child_handler */ + child_pid = p; + + p1 = wait(&status); + yaz_log_reopen(); + + /* disable signalling in kill_child_handler */ + child_pid = 0; + + if (p1 != p) + { + yaz_log(YLOG_FATAL, "p1=%d != p=%d", p1, p); + exit(1); + } + + if (WIFSIGNALED(status)) + { + /* keep the child alive in case of errors, but _log_ */ + switch(WTERMSIG(status)) { + case SIGILL: + yaz_log(YLOG_WARN, "Received SIGILL from child %ld", (long) p); + cont = 1; + break; + case SIGABRT: + yaz_log(YLOG_WARN, "Received SIGABRT from child %ld", (long) p); + cont = 1; + break ; + case SIGSEGV: + yaz_log(YLOG_WARN, "Received SIGSEGV from child %ld", (long) p); + cont = 1; + break; + case SIGBUS: + yaz_log(YLOG_WARN, "Received SIGBUS from child %ld", (long) p); + cont = 1; + break; + case SIGTERM: + yaz_log(YLOG_LOG, "Received SIGTERM from child %ld", + (long) p); + cont = 0; + break; + default: + yaz_log(YLOG_WARN, "Received SIG %d from child %ld", + WTERMSIG(status), (long) p); + cont = 0; + } + } + else if (status == 0) + cont = 0; /* child exited normally */ + else + { /* child exited in an abnormal way */ + yaz_log(YLOG_LOG, "Exit %d from child %ld", status, (long) p); + cont = 1; + } + if (cont) /* respawn slower as we get more errors */ + sleep(1 + run/5); + run++; + } + return 0; +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ -- 1.7.10.4