-/* $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.
#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");
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;
}
-/* $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.
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
/*
--- /dev/null
+/* $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 <signal.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include <yaz/log.h>
+
+#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
+ */