reload support

This commit is contained in:
Bob Halley 2000-01-22 01:39:35 +00:00
parent 010170f711
commit 97f1a75cf0
2 changed files with 131 additions and 20 deletions

View file

@ -39,6 +39,10 @@ static isc_eventlist_t on_run;
static isc_mutex_t lock;
static isc_boolean_t shutdown_requested = ISC_FALSE;
static isc_boolean_t running = ISC_FALSE;
/*
* We assume that 'want_reload' can be read and written atomically.
*/
static isc_boolean_t want_reload = ISC_FALSE;
#ifdef HAVE_LINUXTHREADS
static pthread_t main_thread;
@ -47,7 +51,13 @@ static pthread_t main_thread;
#ifndef HAVE_SIGWAIT
static void
no_action(int arg) {
(void)arg;
(void)arg;
}
static void
reload_action(int arg) {
(void)arg;
want_reload = ISC_TRUE;
}
#endif
@ -124,14 +134,15 @@ isc_app_start(void) {
return (result);
/*
* Block SIGINT and SIGTERM.
* Block SIGHUP, SIGINT, SIGTERM.
*
* If isc_app_start() is called from the main thread before any other
* threads have been created, then the pthread_sigmask() call below
* will result in all threads having SIGINT and SIGTERM blocked by
* default.
* will result in all threads having SIGHUP, SIGINT and SIGTERM
* blocked by default.
*/
if (sigemptyset(&sset) != 0 ||
sigaddset(&sset, SIGHUP) != 0 ||
sigaddset(&sset, SIGINT) != 0 ||
sigaddset(&sset, SIGTERM) != 0) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
@ -213,23 +224,38 @@ isc_app_run(void) {
LOCK(&lock);
running = ISC_TRUE;
if (!running) {
running = ISC_TRUE;
/*
* Post any on-run events (in FIFO order).
*/
for (event = ISC_LIST_HEAD(on_run);
event != NULL;
event = next_event) {
next_event = ISC_LIST_NEXT(event, link);
ISC_LIST_UNLINK(on_run, event, link);
task = event->sender;
event->sender = (void *)&running;
isc_task_sendanddetach(&task, &event);
}
/*
* Post any on-run events (in FIFO order).
*/
for (event = ISC_LIST_HEAD(on_run);
event != NULL;
event = next_event) {
next_event = ISC_LIST_NEXT(event, link);
ISC_LIST_UNLINK(on_run, event, link);
task = event->sender;
event->sender = (void *)&running;
isc_task_sendanddetach(&task, &event);
}
UNLOCK(&lock);
#ifndef HAVE_SIGWAIT
/*
* Catch SIGHUP.
*
* We do this here to ensure that the signal handler is installed
* (i.e. that it wasn't a "one-shot" handler).
*/
result = handle_signal(SIGHUP, reload_action);
if (result != ISC_R_SUCCESS)
return (ISC_R_SUCCESS);
#endif
/*
* There is no danger if isc_app_shutdown() is called before we wait
* for signals. Signals are blocked, so any such signal will simply
@ -238,12 +264,13 @@ isc_app_run(void) {
#ifdef HAVE_SIGWAIT
/*
* Wait for SIGINT or SIGTERM.
* Wait for SIGHUP, SIGINT, or SIGTERM.
*/
if (sigemptyset(&sset) != 0 ||
#ifdef HAVE_LINUXTHREADS
sigaddset(&sset, SIGABRT) != 0 ||
#endif
sigaddset(&sset, SIGHUP) != 0 ||
sigaddset(&sset, SIGINT) != 0 ||
sigaddset(&sset, SIGTERM) != 0) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
@ -252,12 +279,19 @@ isc_app_run(void) {
return (ISC_R_UNEXPECTED);
}
result = sigwait(&sset, &sig);
/*
* sigwait() prevents signal handlers from running, so we have
* to check if it was SIGHUP ourselves.
*/
if (result == 0 && sig == SIGHUP)
want_reload = ISC_TRUE;
#else
/*
* Block all signals except for SIGINT and SIGTERM, and then
* Block all signals except for SIGHUP, SIGINT, and SIGTERM, and then
* wait for one of them to occur.
*/
if (sigfillset(&sset) != 0 ||
sigdelset(&sset, SIGHUP) != 0 ||
sigdelset(&sset, SIGINT) != 0 ||
sigdelset(&sset, SIGTERM) != 0) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
@ -268,6 +302,16 @@ isc_app_run(void) {
result = sigsuspend(&sset);
#endif
if (want_reload) {
/*
* SIGHUP is blocked now (it's only unblocked when we're
* calling sigsuspend()/sigwait()), so there's no race with
* the reload_action signal handler when we clear want_reload.
*/
want_reload = ISC_FALSE;
return (ISC_R_RELOAD);
}
return (ISC_R_SUCCESS);
}
@ -314,6 +358,50 @@ isc_app_shutdown(void) {
return (ISC_R_SUCCESS);
}
isc_result_t
isc_app_reload(void) {
isc_boolean_t want_kill = ISC_TRUE;
/*
* Request application reload.
*/
LOCK(&lock);
REQUIRE(running);
/*
* Don't send the reload signal if we're shutting down.
*/
if (shutdown_requested)
want_kill = ISC_FALSE;
UNLOCK(&lock);
if (want_kill) {
#ifdef HAVE_LINUXTHREADS
int result;
result = pthread_kill(main_thread, SIGHUP);
if (result != 0) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_app_shutdown() pthread_kill: %s",
strerror(result));
return (ISC_R_UNEXPECTED);
}
#else
if (kill(getpid(), SIGHUP) < 0) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_app_shutdown() kill: %s",
strerror(errno));
return (ISC_R_UNEXPECTED);
}
#endif
}
return (ISC_R_SUCCESS);
}
void
isc_app_finish(void) {
/*

View file

@ -44,6 +44,11 @@
*
* isc_app_finish(); Call very late in main().
*
* Applications that want to use SIGHUP/isc_app_reload() to trigger reloading
* should check the result of isc_app_run() and call the reload routine if
* the result is ISC_R_RELOAD. They should then call isc_app_run() again
* to resume waiting for reload or termination.
*
* Use of this module is not required. In particular, isc_app_start() is
* NOT an ISC library initialization routine.
*
@ -118,6 +123,10 @@ isc_app_run(void);
* Ensures:
* Any events requested via isc_app_onrun() will have been posted (in
* FIFO order) before isc_app_run() blocks.
*
* Returns:
* ISC_R_SUCCESS Shutdown has been requested.
* ISC_R_RELOAD Reload has been requested.
*/
isc_result_t
@ -126,7 +135,21 @@ isc_app_shutdown(void);
* Request application shutdown.
*
* Notes:
* It is safe to call isc_app_shutdown() multiple times.
* It is safe to call isc_app_shutdown() multiple times. Shutdown will
* only be triggered once.
*
* Requires:
* isc_app_run() has been called.
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_UNEXPECTED
*/
isc_result_t
isc_app_reload(void);
/*
* Request application reload.
*
* Requires:
* isc_app_run() has been called.