diff options
| author | 2019-12-16 16:16:22 +0000 | |
|---|---|---|
| committer | 2019-12-16 16:16:22 +0000 | |
| commit | 2fc5abb04c862f358e234358caea4444e15db068 (patch) | |
| tree | 1c77d5b577fef0399be14245b2108ca9c1a8819d /usr.sbin/bind/lib/isc/unix/app.c | |
| parent | Need to include message size in the maximum buffer calculation. (diff) | |
| download | wireguard-openbsd-2fc5abb04c862f358e234358caea4444e15db068.tar.xz wireguard-openbsd-2fc5abb04c862f358e234358caea4444e15db068.zip | |
Update to bind-9.10.5-P3, which appears to have been the last ISC version.
We only use this tree to build dig and nslookup. Our previous version
predated edns0 support in those tools, and we want that. This is the worst
code I've looked at in years, with layers and layers of spaghetti abstraction
clearly unfit for reuse, but then reused anyways, and the old ones remain
behind. So this is a 8MB diff.
florian, sthen, and otto tried this merge before but failed.
Diffstat (limited to 'usr.sbin/bind/lib/isc/unix/app.c')
| -rw-r--r-- | usr.sbin/bind/lib/isc/unix/app.c | 741 |
1 files changed, 550 insertions, 191 deletions
diff --git a/usr.sbin/bind/lib/isc/unix/app.c b/usr.sbin/bind/lib/isc/unix/app.c index 4bb702f961b..edd0745db50 100644 --- a/usr.sbin/bind/lib/isc/unix/app.c +++ b/usr.sbin/bind/lib/isc/unix/app.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009, 2013-2015 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * @@ -15,8 +15,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $ISC: app.c,v 1.50.18.2.50.1 2008/07/29 04:47:31 each Exp $ */ - /*! \file */ #include <config.h> @@ -30,10 +28,14 @@ #include <unistd.h> #include <signal.h> #include <sys/time.h> +#ifdef HAVE_EPOLL +#include <sys/epoll.h> +#endif #include <isc/app.h> #include <isc/boolean.h> #include <isc/condition.h> +#include <isc/mem.h> #include <isc/msgs.h> #include <isc/mutex.h> #include <isc/event.h> @@ -46,29 +48,117 @@ #ifdef ISC_PLATFORM_USETHREADS #include <pthread.h> -#else /* ISC_PLATFORM_USETHREADS */ +#endif + +/*% + * For BIND9 internal applications built with threads, we use a single app + * context and let multiple worker, I/O, timer threads do actual jobs. + * For other cases (including BIND9 built without threads) an app context acts + * as an event loop dispatching various events. + */ +#ifndef ISC_PLATFORM_USETHREADS #include "../timer_p.h" #include "../task_p.h" #include "socket_p.h" #endif /* ISC_PLATFORM_USETHREADS */ -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_shutdown' can be read and written atomically. +#ifdef ISC_PLATFORM_USETHREADS +static pthread_t blockedthread; +#endif /* ISC_PLATFORM_USETHREADS */ + +/*% + * The following are intended for internal use (indicated by "isc__" + * prefix) but are not declared as static, allowing direct access from + * unit tests etc. */ -static isc_boolean_t want_shutdown = ISC_FALSE; +isc_result_t isc__app_start(void); +isc_result_t isc__app_ctxstart(isc_appctx_t *ctx); +isc_result_t isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, + isc_taskaction_t action, void *arg); +isc_result_t isc__app_ctxrun(isc_appctx_t *ctx); +isc_result_t isc__app_run(void); +isc_result_t isc__app_ctxshutdown(isc_appctx_t *ctx); +isc_result_t isc__app_shutdown(void); +isc_result_t isc__app_reload(void); +isc_result_t isc__app_ctxsuspend(isc_appctx_t *ctx); +void isc__app_ctxfinish(isc_appctx_t *ctx); +void isc__app_finish(void); +void isc__app_block(void); +void isc__app_unblock(void); +isc_result_t isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp); +void isc__appctx_destroy(isc_appctx_t **ctxp); +void isc__appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr); +void isc__appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr); +void isc__appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr); +isc_result_t isc__app_ctxonrun(isc_appctx_t *ctx, isc_mem_t *mctx, + isc_task_t *task, isc_taskaction_t action, + void *arg); + /* - * We assume that 'want_reload' can be read and written atomically. + * The application context of this module. This implementation actually + * doesn't use it. (This may change in the future). */ -static isc_boolean_t want_reload = ISC_FALSE; +#define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x') +#define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC) + +typedef struct isc__appctx { + isc_appctx_t common; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_eventlist_t on_run; + isc_boolean_t shutdown_requested; + isc_boolean_t running; + + /*! + * We assume that 'want_shutdown' can be read and written atomically. + */ + isc_boolean_t want_shutdown; + /* + * We assume that 'want_reload' can be read and written atomically. + */ + isc_boolean_t want_reload; -static isc_boolean_t blocked = ISC_FALSE; + isc_boolean_t blocked; + + isc_taskmgr_t *taskmgr; + isc_socketmgr_t *socketmgr; + isc_timermgr_t *timermgr; #ifdef ISC_PLATFORM_USETHREADS -static pthread_t blockedthread; + isc_mutex_t readylock; + isc_condition_t ready; #endif /* ISC_PLATFORM_USETHREADS */ +} isc__appctx_t; + +static isc__appctx_t isc_g_appctx; + +static struct { + isc_appmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ + void *run, *shutdown, *start, *reload, *finish, *block, *unblock; +} appmethods = { + { + isc__appctx_destroy, + isc__app_ctxstart, + isc__app_ctxrun, + isc__app_ctxsuspend, + isc__app_ctxshutdown, + isc__app_ctxfinish, + isc__appctx_settaskmgr, + isc__appctx_setsocketmgr, + isc__appctx_settimermgr, + isc__app_ctxonrun + }, + (void *)isc__app_run, + (void *)isc__app_shutdown, + (void *)isc__app_start, + (void *)isc__app_reload, + (void *)isc__app_finish, + (void *)isc__app_block, + (void *)isc__app_unblock +}; #ifdef HAVE_LINUXTHREADS /*! @@ -87,14 +177,14 @@ static pthread_t main_thread; #ifndef HAVE_SIGWAIT static void exit_action(int arg) { - UNUSED(arg); - want_shutdown = ISC_TRUE; + UNUSED(arg); + isc_g_appctx.want_shutdown = ISC_TRUE; } static void reload_action(int arg) { - UNUSED(arg); - want_reload = ISC_TRUE; + UNUSED(arg); + isc_g_appctx.want_reload = ISC_TRUE; } #endif @@ -121,12 +211,15 @@ handle_signal(int sig, void (*handler)(int)) { } isc_result_t -isc_app_start(void) { +isc__app_ctxstart(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; isc_result_t result; int presult; sigset_t sset; char strbuf[ISC_STRERRORSIZE]; + REQUIRE(VALID_APPCTX(ctx)); + /* * Start an ISC library application. */ @@ -144,14 +237,36 @@ isc_app_start(void) { } #endif +#ifdef ISC_PLATFORM_USETHREADS #ifdef HAVE_LINUXTHREADS main_thread = pthread_self(); -#endif +#endif /* HAVE_LINUXTHREADS */ - result = isc_mutex_init(&lock); + result = isc_mutex_init(&ctx->readylock); if (result != ISC_R_SUCCESS) return (result); + result = isc_condition_init(&ctx->ready); + if (result != ISC_R_SUCCESS) + goto cleanup_rlock; + + result = isc_mutex_init(&ctx->lock); + if (result != ISC_R_SUCCESS) + goto cleanup_rcond; +#else /* ISC_PLATFORM_USETHREADS */ + result = isc_mutex_init(&ctx->lock); + if (result != ISC_R_SUCCESS) + goto cleanup; +#endif /* ISC_PLATFORM_USETHREADS */ + + ISC_LIST_INIT(ctx->on_run); + + ctx->shutdown_requested = ISC_FALSE; + ctx->running = ISC_FALSE; + ctx->want_shutdown = ISC_FALSE; + ctx->want_reload = ISC_FALSE; + ctx->blocked = ISC_FALSE; + #ifndef HAVE_SIGWAIT /* * Install do-nothing handlers for SIGINT and SIGTERM. @@ -162,10 +277,10 @@ isc_app_start(void) { */ result = handle_signal(SIGINT, exit_action); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; result = handle_signal(SIGTERM, exit_action); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; #endif /* @@ -173,7 +288,7 @@ isc_app_start(void) { */ result = handle_signal(SIGPIPE, SIG_IGN); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; /* * On Solaris 2, delivery of a signal whose action is SIG_IGN @@ -186,15 +301,15 @@ isc_app_start(void) { */ result = handle_signal(SIGHUP, SIG_DFL); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; #ifdef HAVE_SIGWAIT result = handle_signal(SIGTERM, SIG_DFL); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; result = handle_signal(SIGINT, SIG_DFL); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; #endif #ifdef ISC_PLATFORM_USETHREADS @@ -214,7 +329,8 @@ isc_app_start(void) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() sigsetops: %s", strbuf); - return (ISC_R_UNEXPECTED); + result = ISC_R_UNEXPECTED; + goto cleanup; } presult = pthread_sigmask(SIG_BLOCK, &sset, NULL); if (presult != 0) { @@ -222,7 +338,8 @@ isc_app_start(void) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() pthread_sigmask: %s", strbuf); - return (ISC_R_UNEXPECTED); + result = ISC_R_UNEXPECTED; + goto cleanup; } #else /* ISC_PLATFORM_USETHREADS */ /* @@ -239,33 +356,63 @@ isc_app_start(void) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() sigsetops: %s", strbuf); - return (ISC_R_UNEXPECTED); + result = ISC_R_UNEXPECTED; + goto cleanup; } presult = sigprocmask(SIG_UNBLOCK, &sset, NULL); if (presult != 0) { - isc__strerror(presult, strbuf, sizeof(strbuf)); + isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() sigprocmask: %s", strbuf); - return (ISC_R_UNEXPECTED); + result = ISC_R_UNEXPECTED; + goto cleanup; } #endif /* ISC_PLATFORM_USETHREADS */ - ISC_LIST_INIT(on_run); - return (ISC_R_SUCCESS); + + cleanup: +#ifdef ISC_PLATFORM_USETHREADS + cleanup_rcond: + (void)isc_condition_destroy(&ctx->ready); + + cleanup_rlock: + (void)isc_mutex_destroy(&ctx->readylock); +#endif /* ISC_PLATFORM_USETHREADS */ + return (result); +} + +isc_result_t +isc__app_start(void) { + isc_g_appctx.common.impmagic = APPCTX_MAGIC; + isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC; + isc_g_appctx.common.methods = &appmethods.methods; + isc_g_appctx.mctx = NULL; + /* The remaining members will be initialized in ctxstart() */ + + return (isc__app_ctxstart((isc_appctx_t *)&isc_g_appctx)); } isc_result_t -isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, +isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, void *arg) { + return (isc__app_ctxonrun((isc_appctx_t *)&isc_g_appctx, mctx, + task, action, arg)); +} + +isc_result_t +isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task, + isc_taskaction_t action, void *arg) +{ + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; isc_event_t *event; isc_task_t *cloned_task = NULL; isc_result_t result; - LOCK(&lock); + LOCK(&ctx->lock); - if (running) { + if (ctx->running) { result = ISC_R_ALREADYRUNNING; goto unlock; } @@ -282,12 +429,12 @@ isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, goto unlock; } - ISC_LIST_APPEND(on_run, event, ev_link); + ISC_LIST_APPEND(ctx->on_run, event, ev_link); result = ISC_R_SUCCESS; unlock: - UNLOCK(&lock); + UNLOCK(&ctx->lock); return (result); } @@ -297,25 +444,38 @@ isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, * Event loop for nonthreaded programs. */ static isc_result_t -evloop() { +evloop(isc__appctx_t *ctx) { isc_result_t result; - while (!want_shutdown) { + + while (!ctx->want_shutdown) { int n; isc_time_t when, now; struct timeval tv, *tvp; - fd_set *readfds, *writefds; - int maxfd; + isc_socketwait_t *swait; isc_boolean_t readytasks; isc_boolean_t call_timer_dispatch = ISC_FALSE; - readytasks = isc__taskmgr_ready(); + /* + * Check the reload (or suspend) case first for exiting the + * loop as fast as possible in case: + * - the direct call to isc__taskmgr_dispatch() in + * isc__app_ctxrun() completes all the tasks so far, + * - there is thus currently no active task, and + * - there is a timer event + */ + if (ctx->want_reload) { + ctx->want_reload = ISC_FALSE; + return (ISC_R_RELOAD); + } + + readytasks = isc__taskmgr_ready(ctx->taskmgr); if (readytasks) { tv.tv_sec = 0; tv.tv_usec = 0; tvp = &tv; call_timer_dispatch = ISC_TRUE; } else { - result = isc__timermgr_nextevent(&when); + result = isc__timermgr_nextevent(ctx->timermgr, &when); if (result != ISC_R_SUCCESS) tvp = NULL; else { @@ -331,15 +491,15 @@ evloop() { } } - isc__socketmgr_getfdsets(&readfds, &writefds, &maxfd); - n = select(maxfd, readfds, writefds, NULL, tvp); + swait = NULL; + n = isc__socketmgr_waitevents(ctx->socketmgr, tvp, &swait); if (n == 0 || call_timer_dispatch) { /* * We call isc__timermgr_dispatch() only when * necessary, in order to reduce overhead. If the * select() call indicates a timeout, we need the - * dispatch. Even if not, if we set the 0-timeout + * dispatch. Even if not, if we set the 0-timeout * for the select() call, we need to check the timer * events. In the 'readytasks' case, there may be no * timeout event actually, but there is no other way @@ -349,17 +509,11 @@ evloop() { * call, since this loop only runs in the non-thread * mode. */ - isc__timermgr_dispatch(); + isc__timermgr_dispatch(ctx->timermgr); } if (n > 0) - (void)isc__socketmgr_dispatch(readfds, writefds, - maxfd); - (void)isc__taskmgr_dispatch(); - - if (want_reload) { - want_reload = ISC_FALSE; - return (ISC_R_RELOAD); - } + (void)isc__socketmgr_dispatch(ctx->socketmgr, swait); + (void)isc__taskmgr_dispatch(ctx->taskmgr); } return (ISC_R_SUCCESS); } @@ -399,11 +553,11 @@ isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) { INSIST(*mp == 1); /* Mutex must be locked on entry. */ --*mp; - result = evloop(); + result = evloop(&isc_g_appctx); if (result == ISC_R_RELOAD) - want_reload = ISC_TRUE; + isc_g_appctx.want_reload = ISC_TRUE; if (signalled) { - want_shutdown = ISC_FALSE; + isc_g_appctx.want_shutdown = ISC_FALSE; signalled = ISC_FALSE; } @@ -419,43 +573,45 @@ isc__nothread_signal_hack(isc_condition_t *cp) { INSIST(in_recursive_evloop); - want_shutdown = ISC_TRUE; + isc_g_appctx.want_shutdown = ISC_TRUE; signalled = ISC_TRUE; return (ISC_R_SUCCESS); } - #endif /* ISC_PLATFORM_USETHREADS */ isc_result_t -isc_app_run(void) { +isc__app_ctxrun(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; int result; isc_event_t *event, *next_event; isc_task_t *task; #ifdef ISC_PLATFORM_USETHREADS sigset_t sset; char strbuf[ISC_STRERRORSIZE]; -#endif /* ISC_PLATFORM_USETHREADS */ #ifdef HAVE_SIGWAIT int sig; -#endif +#endif /* HAVE_SIGWAIT */ +#endif /* ISC_PLATFORM_USETHREADS */ + + REQUIRE(VALID_APPCTX(ctx)); #ifdef HAVE_LINUXTHREADS REQUIRE(main_thread == pthread_self()); #endif - LOCK(&lock); + LOCK(&ctx->lock); - if (!running) { - running = ISC_TRUE; + if (!ctx->running) { + ctx->running = ISC_TRUE; /* * Post any on-run events (in FIFO order). */ - for (event = ISC_LIST_HEAD(on_run); + for (event = ISC_LIST_HEAD(ctx->on_run); event != NULL; event = next_event) { next_event = ISC_LIST_NEXT(event, ev_link); - ISC_LIST_UNLINK(on_run, event, ev_link); + ISC_LIST_UNLINK(ctx->on_run, event, ev_link); task = event->ev_sender; event->ev_sender = NULL; isc_task_sendanddetach(&task, &event); @@ -463,195 +619,324 @@ isc_app_run(void) { } - UNLOCK(&lock); + UNLOCK(&ctx->lock); -#ifndef HAVE_SIGWAIT +#ifndef ISC_PLATFORM_USETHREADS + if (isc_bind9 && ctx == &isc_g_appctx) { + result = handle_signal(SIGHUP, reload_action); + if (result != ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + } + + (void) isc__taskmgr_dispatch(ctx->taskmgr); + result = evloop(ctx); + return (result); +#else /* ISC_PLATFORM_USETHREADS */ /* - * Catch SIGHUP. - * - * We do this here to ensure that the signal handler is installed - * (i.e. that it wasn't a "one-shot" handler). + * BIND9 internal tools using multiple contexts do not + * rely on signal. */ - result = handle_signal(SIGHUP, reload_action); - if (result != ISC_R_SUCCESS) + if (isc_bind9 && ctx != &isc_g_appctx) return (ISC_R_SUCCESS); -#endif -#ifdef ISC_PLATFORM_USETHREADS /* - * There is no danger if isc_app_shutdown() is called before we wait - * for signals. Signals are blocked, so any such signal will simply - * be made pending and we will get it when we call sigwait(). + * There is no danger if isc_app_shutdown() is called before we + * wait for signals. Signals are blocked, so any such signal will + * simply be made pending and we will get it when we call + * sigwait(). */ - - while (!want_shutdown) { + while (!ctx->want_shutdown) { #ifdef HAVE_SIGWAIT - /* - * Wait for SIGHUP, SIGINT, or SIGTERM. - */ - if (sigemptyset(&sset) != 0 || - sigaddset(&sset, SIGHUP) != 0 || - sigaddset(&sset, SIGINT) != 0 || - sigaddset(&sset, SIGTERM) != 0) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_run() sigsetops: %s", strbuf); - return (ISC_R_UNEXPECTED); - } + if (isc_bind9) { + /* + * BIND9 internal; single context: + * Wait for SIGHUP, SIGINT, or SIGTERM. + */ + if (sigemptyset(&sset) != 0 || + sigaddset(&sset, SIGHUP) != 0 || + sigaddset(&sset, SIGINT) != 0 || + sigaddset(&sset, SIGTERM) != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_run() sigsetops: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } #ifndef HAVE_UNIXWARE_SIGWAIT - result = sigwait(&sset, &sig); - if (result == 0) { - if (sig == SIGINT || - sig == SIGTERM) - want_shutdown = ISC_TRUE; - else if (sig == SIGHUP) - want_reload = ISC_TRUE; - } + result = sigwait(&sset, &sig); + if (result == 0) { + if (sig == SIGINT || sig == SIGTERM) + ctx->want_shutdown = ISC_TRUE; + else if (sig == SIGHUP) + ctx->want_reload = ISC_TRUE; + } #else /* Using UnixWare sigwait semantics. */ - sig = sigwait(&sset); - if (sig >= 0) { - if (sig == SIGINT || - sig == SIGTERM) - want_shutdown = ISC_TRUE; - else if (sig == SIGHUP) - want_reload = ISC_TRUE; - } - + sig = sigwait(&sset); + if (sig >= 0) { + if (sig == SIGINT || sig == SIGTERM) + ctx->want_shutdown = ISC_TRUE; + else if (sig == SIGHUP) + ctx->want_reload = ISC_TRUE; + } #endif /* HAVE_UNIXWARE_SIGWAIT */ + } else { + /* + * External, or BIND9 using multiple contexts: + * wait until woken up. + */ + LOCK(&ctx->readylock); + if (ctx->want_shutdown) { + /* shutdown() won the race. */ + UNLOCK(&ctx->readylock); + break; + } + if (!ctx->want_reload) + WAIT(&ctx->ready, &ctx->readylock); + UNLOCK(&ctx->readylock); + } #else /* Don't have sigwait(). */ - /* - * Listen for all signals. - */ - if (sigemptyset(&sset) != 0) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_run() sigsetops: %s", strbuf); - return (ISC_R_UNEXPECTED); + if (isc_bind9) { + /* + * BIND9 internal; single context: + * Install a signal handler for SIGHUP, then wait for + * all signals. + */ + result = handle_signal(SIGHUP, reload_action); + if (result != ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + + if (sigemptyset(&sset) != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_run() sigsetops: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } +#ifdef HAVE_GPERFTOOLS_PROFILER + if (sigaddset(&sset, SIGALRM) != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_run() sigsetops: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } +#endif + (void)sigsuspend(&sset); + } else { + /* + * External, or BIND9 using multiple contexts: + * wait until woken up. + */ + LOCK(&ctx->readylock); + if (ctx->want_shutdown) { + /* shutdown() won the race. */ + UNLOCK(&ctx->readylock); + break; + } + if (!ctx->want_reload) + WAIT(&ctx->ready, &ctx->readylock); + UNLOCK(&ctx->readylock); } - result = sigsuspend(&sset); #endif /* HAVE_SIGWAIT */ - if (want_reload) { - want_reload = ISC_FALSE; + if (ctx->want_reload) { + ctx->want_reload = ISC_FALSE; return (ISC_R_RELOAD); } - if (want_shutdown && blocked) + if (ctx->want_shutdown && ctx->blocked) exit(1); } -#else /* ISC_PLATFORM_USETHREADS */ - - (void)isc__taskmgr_dispatch(); - - result = evloop(); - if (result != ISC_R_SUCCESS) - return (result); - + return (ISC_R_SUCCESS); #endif /* ISC_PLATFORM_USETHREADS */ +} - return (ISC_R_SUCCESS); +isc_result_t +isc__app_run(void) { + return (isc__app_ctxrun((isc_appctx_t *)&isc_g_appctx)); } isc_result_t -isc_app_shutdown(void) { +isc__app_ctxshutdown(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; isc_boolean_t want_kill = ISC_TRUE; +#ifdef ISC_PLATFORM_USETHREADS char strbuf[ISC_STRERRORSIZE]; +#endif /* ISC_PLATFORM_USETHREADS */ + + REQUIRE(VALID_APPCTX(ctx)); - LOCK(&lock); + LOCK(&ctx->lock); - REQUIRE(running); + REQUIRE(ctx->running); - if (shutdown_requested) + if (ctx->shutdown_requested) want_kill = ISC_FALSE; else - shutdown_requested = ISC_TRUE; + ctx->shutdown_requested = ISC_TRUE; - UNLOCK(&lock); + UNLOCK(&ctx->lock); if (want_kill) { + if (isc_bind9 && ctx != &isc_g_appctx) + /* BIND9 internal, but using multiple contexts */ + ctx->want_shutdown = ISC_TRUE; + else { +#ifndef ISC_PLATFORM_USETHREADS + ctx->want_shutdown = ISC_TRUE; +#else /* ISC_PLATFORM_USETHREADS */ #ifdef HAVE_LINUXTHREADS - int result; - - result = pthread_kill(main_thread, SIGTERM); - if (result != 0) { - isc__strerror(result, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_shutdown() pthread_kill: %s", - strbuf); - return (ISC_R_UNEXPECTED); - } + if (isc_bind9) { + /* BIND9 internal, single context */ + int result; + + result = pthread_kill(main_thread, SIGTERM); + if (result != 0) { + isc__strerror(result, + strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_shutdown() " + "pthread_kill: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } + } #else - if (kill(getpid(), SIGTERM) < 0) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_shutdown() kill: %s", strbuf); - return (ISC_R_UNEXPECTED); + if (isc_bind9) { + /* BIND9 internal, single context */ + if (kill(getpid(), SIGTERM) < 0) { + isc__strerror(errno, + strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_shutdown() " + "kill: %s", strbuf); + return (ISC_R_UNEXPECTED); + } + } +#endif /* HAVE_LINUXTHREADS */ + else { + /* External, multiple contexts */ + LOCK(&ctx->readylock); + ctx->want_shutdown = ISC_TRUE; + UNLOCK(&ctx->readylock); + SIGNAL(&ctx->ready); + } +#endif /* ISC_PLATFORM_USETHREADS */ } -#endif } return (ISC_R_SUCCESS); } isc_result_t -isc_app_reload(void) { +isc__app_shutdown(void) { + return (isc__app_ctxshutdown((isc_appctx_t *)&isc_g_appctx)); +} + +isc_result_t +isc__app_ctxsuspend(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; isc_boolean_t want_kill = ISC_TRUE; +#ifdef ISC_PLATFORM_USETHREADS char strbuf[ISC_STRERRORSIZE]; +#endif + + REQUIRE(VALID_APPCTX(ctx)); - LOCK(&lock); + LOCK(&ctx->lock); - REQUIRE(running); + REQUIRE(ctx->running); /* * Don't send the reload signal if we're shutting down. */ - if (shutdown_requested) + if (ctx->shutdown_requested) want_kill = ISC_FALSE; - UNLOCK(&lock); + UNLOCK(&ctx->lock); if (want_kill) { + if (isc_bind9 && ctx != &isc_g_appctx) + /* BIND9 internal, but using multiple contexts */ + ctx->want_reload = ISC_TRUE; + else { +#ifndef ISC_PLATFORM_USETHREADS + ctx->want_reload = ISC_TRUE; +#else /* ISC_PLATFORM_USETHREADS */ #ifdef HAVE_LINUXTHREADS - int result; - - result = pthread_kill(main_thread, SIGHUP); - if (result != 0) { - isc__strerror(result, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_reload() pthread_kill: %s", - strbuf); - return (ISC_R_UNEXPECTED); - } + if (isc_bind9) { + /* BIND9 internal, single context */ + int result; + + result = pthread_kill(main_thread, SIGHUP); + if (result != 0) { + isc__strerror(result, + strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_reload() " + "pthread_kill: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } + } #else - if (kill(getpid(), SIGHUP) < 0) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_reload() kill: %s", strbuf); - return (ISC_R_UNEXPECTED); + if (isc_bind9) { + /* BIND9 internal, single context */ + if (kill(getpid(), SIGHUP) < 0) { + isc__strerror(errno, + strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_reload() " + "kill: %s", strbuf); + return (ISC_R_UNEXPECTED); + } + } +#endif /* HAVE_LINUXTHREADS */ + else { + /* External, multiple contexts */ + LOCK(&ctx->readylock); + ctx->want_reload = ISC_TRUE; + UNLOCK(&ctx->readylock); + SIGNAL(&ctx->ready); + } +#endif /* ISC_PLATFORM_USETHREADS */ } -#endif } return (ISC_R_SUCCESS); } +isc_result_t +isc__app_reload(void) { + return (isc__app_ctxsuspend((isc_appctx_t *)&isc_g_appctx)); +} + void -isc_app_finish(void) { - DESTROYLOCK(&lock); +isc__app_ctxfinish(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + DESTROYLOCK(&ctx->lock); +} + +void +isc__app_finish(void) { + isc__app_ctxfinish((isc_appctx_t *)&isc_g_appctx); } void -isc_app_block(void) { +isc__app_block(void) { #ifdef ISC_PLATFORM_USETHREADS sigset_t sset; #endif /* ISC_PLATFORM_USETHREADS */ - REQUIRE(running); - REQUIRE(!blocked); + REQUIRE(isc_g_appctx.running); + REQUIRE(!isc_g_appctx.blocked); - blocked = ISC_TRUE; + isc_g_appctx.blocked = ISC_TRUE; #ifdef ISC_PLATFORM_USETHREADS blockedthread = pthread_self(); RUNTIME_CHECK(sigemptyset(&sset) == 0 && @@ -662,22 +947,96 @@ isc_app_block(void) { } void -isc_app_unblock(void) { +isc__app_unblock(void) { #ifdef ISC_PLATFORM_USETHREADS sigset_t sset; #endif /* ISC_PLATFORM_USETHREADS */ - REQUIRE(running); - REQUIRE(blocked); + REQUIRE(isc_g_appctx.running); + REQUIRE(isc_g_appctx.blocked); - blocked = ISC_FALSE; + isc_g_appctx.blocked = ISC_FALSE; #ifdef ISC_PLATFORM_USETHREADS REQUIRE(blockedthread == pthread_self()); RUNTIME_CHECK(sigemptyset(&sset) == 0 && - sigaddset(&sset, SIGINT) == 0 && + sigaddset(&sset, SIGINT) == 0 && sigaddset(&sset, SIGTERM) == 0); RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0); #endif /* ISC_PLATFORM_USETHREADS */ } + +isc_result_t +isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) { + isc__appctx_t *ctx; + + REQUIRE(mctx != NULL); + REQUIRE(ctxp != NULL && *ctxp == NULL); + + ctx = isc_mem_get(mctx, sizeof(*ctx)); + if (ctx == NULL) + return (ISC_R_NOMEMORY); + + ctx->common.impmagic = APPCTX_MAGIC; + ctx->common.magic = ISCAPI_APPCTX_MAGIC; + ctx->common.methods = &appmethods.methods; + + ctx->mctx = NULL; + isc_mem_attach(mctx, &ctx->mctx); + + ctx->taskmgr = NULL; + ctx->socketmgr = NULL; + ctx->timermgr = NULL; + + *ctxp = (isc_appctx_t *)ctx; + + return (ISC_R_SUCCESS); +} + +void +isc__appctx_destroy(isc_appctx_t **ctxp) { + isc__appctx_t *ctx; + + REQUIRE(ctxp != NULL); + ctx = (isc__appctx_t *)*ctxp; + REQUIRE(VALID_APPCTX(ctx)); + + isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx)); + + *ctxp = NULL; +} + +void +isc__appctx_settaskmgr(isc_appctx_t *ctx0, isc_taskmgr_t *taskmgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->taskmgr = taskmgr; +} + +void +isc__appctx_setsocketmgr(isc_appctx_t *ctx0, isc_socketmgr_t *socketmgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->socketmgr = socketmgr; +} + +void +isc__appctx_settimermgr(isc_appctx_t *ctx0, isc_timermgr_t *timermgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->timermgr = timermgr; +} + +isc_result_t +isc__app_register(void) { + return (isc_app_register(isc__appctx_create)); +} + +#include "../app_api.c" |
