2 * Copyright (C) 2004, 2005, 2007-2009, 2013 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: app.c,v 1.64 2009/11/04 05:58:46 marka Exp $ */
24 #include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
25 #include <sys/types.h>
34 #include <sys/epoll.h>
38 #include <isc/boolean.h>
39 #include <isc/condition.h>
42 #include <isc/mutex.h>
43 #include <isc/event.h>
44 #include <isc/platform.h>
45 #include <isc/strerror.h>
46 #include <isc/string.h>
52 * For BIND9 internal applications built with threads, we use a single app
53 * context and let multiple worker, I/O, timer threads do actual jobs.
54 * For other cases (including BIND9 built without threads) an app context acts
55 * as an event loop dispatching various events.
57 #if defined(ISC_PLATFORM_USETHREADS) && defined(BIND9)
58 #define USE_THREADS_SINGLECTX
61 #ifdef ISC_PLATFORM_USETHREADS
65 #ifndef USE_THREADS_SINGLECTX
66 #include "../timer_p.h"
67 #include "../task_p.h"
69 #endif /* USE_THREADS_SINGLECTX */
71 #ifdef ISC_PLATFORM_USETHREADS
72 static pthread_t blockedthread;
73 #endif /* ISC_PLATFORM_USETHREADS */
76 * The following can be either static or public, depending on build environment.
80 #define ISC_APPFUNC_SCOPE
82 #define ISC_APPFUNC_SCOPE static
85 ISC_APPFUNC_SCOPE isc_result_t isc__app_start(void);
86 ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxstart(isc_appctx_t *ctx);
87 ISC_APPFUNC_SCOPE isc_result_t isc__app_onrun(isc_mem_t *mctx,
89 isc_taskaction_t action,
91 ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxrun(isc_appctx_t *ctx);
92 ISC_APPFUNC_SCOPE isc_result_t isc__app_run(void);
93 ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxshutdown(isc_appctx_t *ctx);
94 ISC_APPFUNC_SCOPE isc_result_t isc__app_shutdown(void);
95 ISC_APPFUNC_SCOPE isc_result_t isc__app_reload(void);
96 ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxsuspend(isc_appctx_t *ctx);
97 ISC_APPFUNC_SCOPE void isc__app_ctxfinish(isc_appctx_t *ctx);
98 ISC_APPFUNC_SCOPE void isc__app_finish(void);
99 ISC_APPFUNC_SCOPE void isc__app_block(void);
100 ISC_APPFUNC_SCOPE void isc__app_unblock(void);
101 ISC_APPFUNC_SCOPE isc_result_t isc__appctx_create(isc_mem_t *mctx,
102 isc_appctx_t **ctxp);
103 ISC_APPFUNC_SCOPE void isc__appctx_destroy(isc_appctx_t **ctxp);
104 ISC_APPFUNC_SCOPE void isc__appctx_settaskmgr(isc_appctx_t *ctx,
105 isc_taskmgr_t *taskmgr);
106 ISC_APPFUNC_SCOPE void isc__appctx_setsocketmgr(isc_appctx_t *ctx,
107 isc_socketmgr_t *socketmgr);
108 ISC_APPFUNC_SCOPE void isc__appctx_settimermgr(isc_appctx_t *ctx,
109 isc_timermgr_t *timermgr);
110 ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxonrun(isc_appctx_t *ctx,
113 isc_taskaction_t action,
117 * The application context of this module. This implementation actually
118 * doesn't use it. (This may change in the future).
120 #define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x')
121 #define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC)
123 typedef struct isc__appctx {
127 isc_eventlist_t on_run;
128 isc_boolean_t shutdown_requested;
129 isc_boolean_t running;
132 * We assume that 'want_shutdown' can be read and written atomically.
134 isc_boolean_t want_shutdown;
136 * We assume that 'want_reload' can be read and written atomically.
138 isc_boolean_t want_reload;
140 isc_boolean_t blocked;
142 isc_taskmgr_t *taskmgr;
143 isc_socketmgr_t *socketmgr;
144 isc_timermgr_t *timermgr;
147 static isc__appctx_t isc_g_appctx;
150 isc_appmethods_t methods;
153 * The following are defined just for avoiding unused static functions.
156 void *run, *shutdown, *start, *onrun,
157 *reload, *finish, *block, *unblock;
165 isc__app_ctxshutdown,
167 isc__appctx_settaskmgr,
168 isc__appctx_setsocketmgr,
169 isc__appctx_settimermgr,
174 (void *)isc__app_run, (void *)isc__app_shutdown,
175 (void *)isc__app_start, (void *)isc__app_onrun, (void *)isc__app_reload,
176 (void *)isc__app_finish, (void *)isc__app_block,
177 (void *)isc__app_unblock
181 #ifdef HAVE_LINUXTHREADS
183 * Linux has sigwait(), but it appears to prevent signal handlers from
184 * running, even if they're not in the set being waited for. This makes
185 * it impossible to get the default actions for SIGILL, SIGSEGV, etc.
186 * Instead of messing with it, we just use sigsuspend() instead.
190 * We need to remember which thread is the main thread...
192 static pthread_t main_thread;
197 exit_action(int arg) {
199 isc_g_appctx.want_shutdown = ISC_TRUE;
203 reload_action(int arg) {
205 isc_g_appctx.want_reload = ISC_TRUE;
210 handle_signal(int sig, void (*handler)(int)) {
212 char strbuf[ISC_STRERRORSIZE];
214 memset(&sa, 0, sizeof(sa));
215 sa.sa_handler = handler;
217 if (sigfillset(&sa.sa_mask) != 0 ||
218 sigaction(sig, &sa, NULL) < 0) {
219 isc__strerror(errno, strbuf, sizeof(strbuf));
220 UNEXPECTED_ERROR(__FILE__, __LINE__,
221 isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP,
223 "handle_signal() %d setup: %s"),
225 return (ISC_R_UNEXPECTED);
228 return (ISC_R_SUCCESS);
231 ISC_APPFUNC_SCOPE isc_result_t
232 isc__app_ctxstart(isc_appctx_t *ctx0) {
233 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
236 REQUIRE(VALID_APPCTX(ctx));
239 * Start an ISC library application.
242 #ifdef NEED_PTHREAD_INIT
244 * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this.
246 presult = pthread_init();
248 isc__strerror(presult, strbuf, sizeof(strbuf));
249 UNEXPECTED_ERROR(__FILE__, __LINE__,
250 "isc_app_start() pthread_init: %s", strbuf);
251 return (ISC_R_UNEXPECTED);
255 #ifdef HAVE_LINUXTHREADS
256 main_thread = pthread_self();
259 result = isc_mutex_init(&ctx->lock);
260 if (result != ISC_R_SUCCESS)
263 ISC_LIST_INIT(ctx->on_run);
265 ctx->shutdown_requested = ISC_FALSE;
266 ctx->running = ISC_FALSE;
267 ctx->want_shutdown = ISC_FALSE;
268 ctx->want_reload = ISC_FALSE;
269 ctx->blocked = ISC_FALSE;
271 return (ISC_R_SUCCESS);
274 ISC_APPFUNC_SCOPE isc_result_t
275 isc__app_start(void) {
279 char strbuf[ISC_STRERRORSIZE];
281 isc_g_appctx.common.impmagic = APPCTX_MAGIC;
282 isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC;
283 isc_g_appctx.common.methods = &appmethods.methods;
284 isc_g_appctx.mctx = NULL;
285 /* The remaining members will be initialized in ctxstart() */
287 result = isc__app_ctxstart((isc_appctx_t *)&isc_g_appctx);
288 if (result != ISC_R_SUCCESS)
293 * Install do-nothing handlers for SIGINT and SIGTERM.
295 * We install them now because BSDI 3.1 won't block
296 * the default actions, regardless of what we do with
299 result = handle_signal(SIGINT, exit_action);
300 if (result != ISC_R_SUCCESS)
302 result = handle_signal(SIGTERM, exit_action);
303 if (result != ISC_R_SUCCESS)
308 * Always ignore SIGPIPE.
310 result = handle_signal(SIGPIPE, SIG_IGN);
311 if (result != ISC_R_SUCCESS)
315 * On Solaris 2, delivery of a signal whose action is SIG_IGN
316 * will not cause sigwait() to return. We may have inherited
317 * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent
318 * process (e.g, Solaris cron). Set an action of SIG_DFL to make
319 * sure sigwait() works as expected. Only do this for SIGTERM and
320 * SIGINT if we don't have sigwait(), since a different handler is
323 result = handle_signal(SIGHUP, SIG_DFL);
324 if (result != ISC_R_SUCCESS)
328 result = handle_signal(SIGTERM, SIG_DFL);
329 if (result != ISC_R_SUCCESS)
331 result = handle_signal(SIGINT, SIG_DFL);
332 if (result != ISC_R_SUCCESS)
336 #ifdef ISC_PLATFORM_USETHREADS
338 * Block SIGHUP, SIGINT, SIGTERM.
340 * If isc_app_start() is called from the main thread before any other
341 * threads have been created, then the pthread_sigmask() call below
342 * will result in all threads having SIGHUP, SIGINT and SIGTERM
343 * blocked by default, ensuring that only the thread that calls
344 * sigwait() for them will get those signals.
346 if (sigemptyset(&sset) != 0 ||
347 sigaddset(&sset, SIGHUP) != 0 ||
348 sigaddset(&sset, SIGINT) != 0 ||
349 sigaddset(&sset, SIGTERM) != 0) {
350 isc__strerror(errno, strbuf, sizeof(strbuf));
351 UNEXPECTED_ERROR(__FILE__, __LINE__,
352 "isc_app_start() sigsetops: %s", strbuf);
353 return (ISC_R_UNEXPECTED);
355 presult = pthread_sigmask(SIG_BLOCK, &sset, NULL);
357 isc__strerror(presult, strbuf, sizeof(strbuf));
358 UNEXPECTED_ERROR(__FILE__, __LINE__,
359 "isc_app_start() pthread_sigmask: %s",
361 return (ISC_R_UNEXPECTED);
363 #else /* ISC_PLATFORM_USETHREADS */
365 * Unblock SIGHUP, SIGINT, SIGTERM.
367 * If we're not using threads, we need to make sure that SIGHUP,
368 * SIGINT and SIGTERM are not inherited as blocked from the parent
371 if (sigemptyset(&sset) != 0 ||
372 sigaddset(&sset, SIGHUP) != 0 ||
373 sigaddset(&sset, SIGINT) != 0 ||
374 sigaddset(&sset, SIGTERM) != 0) {
375 isc__strerror(errno, strbuf, sizeof(strbuf));
376 UNEXPECTED_ERROR(__FILE__, __LINE__,
377 "isc_app_start() sigsetops: %s", strbuf);
378 return (ISC_R_UNEXPECTED);
380 presult = sigprocmask(SIG_UNBLOCK, &sset, NULL);
382 isc__strerror(presult, strbuf, sizeof(strbuf));
383 UNEXPECTED_ERROR(__FILE__, __LINE__,
384 "isc_app_start() sigprocmask: %s", strbuf);
385 return (ISC_R_UNEXPECTED);
387 #endif /* ISC_PLATFORM_USETHREADS */
389 return (ISC_R_SUCCESS);
392 ISC_APPFUNC_SCOPE isc_result_t
393 isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
396 return (isc__app_ctxonrun((isc_appctx_t *)&isc_g_appctx, mctx,
401 isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
402 isc_taskaction_t action, void *arg)
404 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
406 isc_task_t *cloned_task = NULL;
412 result = ISC_R_ALREADYRUNNING;
417 * Note that we store the task to which we're going to send the event
418 * in the event's "sender" field.
420 isc_task_attach(task, &cloned_task);
421 event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
422 action, arg, sizeof(*event));
424 result = ISC_R_NOMEMORY;
428 ISC_LIST_APPEND(ctx->on_run, event, ev_link);
430 result = ISC_R_SUCCESS;
438 #ifndef USE_THREADS_SINGLECTX
440 * Event loop for nonthreaded programs.
443 evloop(isc__appctx_t *ctx) {
446 while (!ctx->want_shutdown) {
448 isc_time_t when, now;
449 struct timeval tv, *tvp;
450 isc_socketwait_t *swait;
451 isc_boolean_t readytasks;
452 isc_boolean_t call_timer_dispatch = ISC_FALSE;
455 * Check the reload (or suspend) case first for exiting the
456 * loop as fast as possible in case:
457 * - the direct call to isc__taskmgr_dispatch() in
458 * isc__app_ctxrun() completes all the tasks so far,
459 * - there is thus currently no active task, and
460 * - there is a timer event
462 if (ctx->want_reload) {
463 ctx->want_reload = ISC_FALSE;
464 return (ISC_R_RELOAD);
467 readytasks = isc__taskmgr_ready(ctx->taskmgr);
472 call_timer_dispatch = ISC_TRUE;
474 result = isc__timermgr_nextevent(ctx->timermgr, &when);
475 if (result != ISC_R_SUCCESS)
481 us = isc_time_microdiff(&when, &now);
483 call_timer_dispatch = ISC_TRUE;
484 tv.tv_sec = us / 1000000;
485 tv.tv_usec = us % 1000000;
491 n = isc__socketmgr_waitevents(ctx->socketmgr, tvp, &swait);
493 if (n == 0 || call_timer_dispatch) {
495 * We call isc__timermgr_dispatch() only when
496 * necessary, in order to reduce overhead. If the
497 * select() call indicates a timeout, we need the
498 * dispatch. Even if not, if we set the 0-timeout
499 * for the select() call, we need to check the timer
500 * events. In the 'readytasks' case, there may be no
501 * timeout event actually, but there is no other way
502 * to reduce the overhead.
503 * Note that we do not have to worry about the case
504 * where a new timer is inserted during the select()
505 * call, since this loop only runs in the non-thread
508 isc__timermgr_dispatch(ctx->timermgr);
511 (void)isc__socketmgr_dispatch(ctx->socketmgr, swait);
512 (void)isc__taskmgr_dispatch(ctx->taskmgr);
514 return (ISC_R_SUCCESS);
516 #endif /* USE_THREADS_SINGLECTX */
518 #ifndef ISC_PLATFORM_USETHREADS
520 * This is a gross hack to support waiting for condition
521 * variables in nonthreaded programs in a limited way;
522 * see lib/isc/nothreads/include/isc/condition.h.
523 * We implement isc_condition_wait() by entering the
524 * event loop recursively until the want_shutdown flag
525 * is set by isc_condition_signal().
529 * \brief True if we are currently executing in the recursive
532 static isc_boolean_t in_recursive_evloop = ISC_FALSE;
535 * \brief True if we are exiting the event loop as the result of
536 * a call to isc_condition_signal() rather than a shutdown
539 static isc_boolean_t signalled = ISC_FALSE;
542 isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) {
548 INSIST(!in_recursive_evloop);
549 in_recursive_evloop = ISC_TRUE;
551 INSIST(*mp == 1); /* Mutex must be locked on entry. */
554 result = evloop(&isc_g_appctx);
555 if (result == ISC_R_RELOAD)
556 isc_g_appctx.want_reload = ISC_TRUE;
558 isc_g_appctx.want_shutdown = ISC_FALSE;
559 signalled = ISC_FALSE;
563 in_recursive_evloop = ISC_FALSE;
564 return (ISC_R_SUCCESS);
568 isc__nothread_signal_hack(isc_condition_t *cp) {
572 INSIST(in_recursive_evloop);
574 isc_g_appctx.want_shutdown = ISC_TRUE;
575 signalled = ISC_TRUE;
576 return (ISC_R_SUCCESS);
579 #endif /* ISC_PLATFORM_USETHREADS */
581 ISC_APPFUNC_SCOPE isc_result_t
582 isc__app_ctxrun(isc_appctx_t *ctx0) {
583 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
585 isc_event_t *event, *next_event;
587 #ifdef USE_THREADS_SINGLECTX
589 char strbuf[ISC_STRERRORSIZE];
593 #endif /* USE_THREADS_SINGLECTX */
595 REQUIRE(VALID_APPCTX(ctx));
597 #ifdef HAVE_LINUXTHREADS
598 REQUIRE(main_thread == pthread_self());
604 ctx->running = ISC_TRUE;
607 * Post any on-run events (in FIFO order).
609 for (event = ISC_LIST_HEAD(ctx->on_run);
611 event = next_event) {
612 next_event = ISC_LIST_NEXT(event, ev_link);
613 ISC_LIST_UNLINK(ctx->on_run, event, ev_link);
614 task = event->ev_sender;
615 event->ev_sender = NULL;
616 isc_task_sendanddetach(&task, &event);
627 * We do this here to ensure that the signal handler is installed
628 * (i.e. that it wasn't a "one-shot" handler).
630 if (ctx == &isc_g_appctx) {
631 result = handle_signal(SIGHUP, reload_action);
632 if (result != ISC_R_SUCCESS)
633 return (ISC_R_SUCCESS);
637 #ifdef USE_THREADS_SINGLECTX
639 * When we are using multiple contexts, we don't rely on signals.
641 if (ctx != &isc_g_appctx)
642 return (ISC_R_SUCCESS);
645 * There is no danger if isc_app_shutdown() is called before we wait
646 * for signals. Signals are blocked, so any such signal will simply
647 * be made pending and we will get it when we call sigwait().
650 while (!ctx->want_shutdown) {
653 * Wait for SIGHUP, SIGINT, or SIGTERM.
655 if (sigemptyset(&sset) != 0 ||
656 sigaddset(&sset, SIGHUP) != 0 ||
657 sigaddset(&sset, SIGINT) != 0 ||
658 sigaddset(&sset, SIGTERM) != 0) {
659 isc__strerror(errno, strbuf, sizeof(strbuf));
660 UNEXPECTED_ERROR(__FILE__, __LINE__,
661 "isc_app_run() sigsetops: %s", strbuf);
662 return (ISC_R_UNEXPECTED);
665 #ifndef HAVE_UNIXWARE_SIGWAIT
666 result = sigwait(&sset, &sig);
668 if (sig == SIGINT || sig == SIGTERM)
669 ctx->want_shutdown = ISC_TRUE;
670 else if (sig == SIGHUP)
671 ctx->want_reload = ISC_TRUE;
674 #else /* Using UnixWare sigwait semantics. */
675 sig = sigwait(&sset);
677 if (sig == SIGINT || sig == SIGTERM)
678 ctx->want_shutdown = ISC_TRUE;
679 else if (sig == SIGHUP)
680 ctx->want_reload = ISC_TRUE;
683 #endif /* HAVE_UNIXWARE_SIGWAIT */
684 #else /* Don't have sigwait(). */
686 * Listen for all signals.
688 if (sigemptyset(&sset) != 0) {
689 isc__strerror(errno, strbuf, sizeof(strbuf));
690 UNEXPECTED_ERROR(__FILE__, __LINE__,
691 "isc_app_run() sigsetops: %s",
693 return (ISC_R_UNEXPECTED);
695 result = sigsuspend(&sset);
696 #endif /* HAVE_SIGWAIT */
698 if (ctx->want_reload) {
699 ctx->want_reload = ISC_FALSE;
700 return (ISC_R_RELOAD);
703 if (ctx->want_shutdown && ctx->blocked)
707 #else /* USE_THREADS_SINGLECTX */
709 (void)isc__taskmgr_dispatch(ctx->taskmgr);
711 result = evloop(ctx);
712 if (result != ISC_R_SUCCESS)
715 #endif /* USE_THREADS_SINGLECTX */
717 return (ISC_R_SUCCESS);
720 ISC_APPFUNC_SCOPE isc_result_t
722 return (isc__app_ctxrun((isc_appctx_t *)&isc_g_appctx));
725 ISC_APPFUNC_SCOPE isc_result_t
726 isc__app_ctxshutdown(isc_appctx_t *ctx0) {
727 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
728 isc_boolean_t want_kill = ISC_TRUE;
729 char strbuf[ISC_STRERRORSIZE];
731 REQUIRE(VALID_APPCTX(ctx));
735 REQUIRE(ctx->running);
737 if (ctx->shutdown_requested)
738 want_kill = ISC_FALSE;
740 ctx->shutdown_requested = ISC_TRUE;
745 if (ctx != &isc_g_appctx)
746 ctx->want_shutdown = ISC_TRUE;
748 #ifdef HAVE_LINUXTHREADS
751 result = pthread_kill(main_thread, SIGTERM);
753 isc__strerror(result, strbuf, sizeof(strbuf));
754 UNEXPECTED_ERROR(__FILE__, __LINE__,
755 "isc_app_shutdown() "
758 return (ISC_R_UNEXPECTED);
761 if (kill(getpid(), SIGTERM) < 0) {
762 isc__strerror(errno, strbuf, sizeof(strbuf));
763 UNEXPECTED_ERROR(__FILE__, __LINE__,
764 "isc_app_shutdown() "
766 return (ISC_R_UNEXPECTED);
768 #endif /* HAVE_LINUXTHREADS */
772 return (ISC_R_SUCCESS);
775 ISC_APPFUNC_SCOPE isc_result_t
776 isc__app_shutdown() {
777 return (isc__app_ctxshutdown((isc_appctx_t *)&isc_g_appctx));
780 ISC_APPFUNC_SCOPE isc_result_t
781 isc__app_ctxsuspend(isc_appctx_t *ctx0) {
782 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
783 isc_boolean_t want_kill = ISC_TRUE;
784 char strbuf[ISC_STRERRORSIZE];
786 REQUIRE(VALID_APPCTX(ctx));
790 REQUIRE(ctx->running);
793 * Don't send the reload signal if we're shutting down.
795 if (ctx->shutdown_requested)
796 want_kill = ISC_FALSE;
801 if (ctx != &isc_g_appctx)
802 ctx->want_reload = ISC_TRUE;
804 #ifdef HAVE_LINUXTHREADS
807 result = pthread_kill(main_thread, SIGHUP);
809 isc__strerror(result, strbuf, sizeof(strbuf));
810 UNEXPECTED_ERROR(__FILE__, __LINE__,
814 return (ISC_R_UNEXPECTED);
817 if (kill(getpid(), SIGHUP) < 0) {
818 isc__strerror(errno, strbuf, sizeof(strbuf));
819 UNEXPECTED_ERROR(__FILE__, __LINE__,
822 return (ISC_R_UNEXPECTED);
828 return (ISC_R_SUCCESS);
831 ISC_APPFUNC_SCOPE isc_result_t
832 isc__app_reload(void) {
833 return (isc__app_ctxsuspend((isc_appctx_t *)&isc_g_appctx));
836 ISC_APPFUNC_SCOPE void
837 isc__app_ctxfinish(isc_appctx_t *ctx0) {
838 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
840 REQUIRE(VALID_APPCTX(ctx));
842 DESTROYLOCK(&ctx->lock);
845 ISC_APPFUNC_SCOPE void
846 isc__app_finish(void) {
847 isc__app_ctxfinish((isc_appctx_t *)&isc_g_appctx);
850 ISC_APPFUNC_SCOPE void
851 isc__app_block(void) {
852 #ifdef ISC_PLATFORM_USETHREADS
854 #endif /* ISC_PLATFORM_USETHREADS */
855 REQUIRE(isc_g_appctx.running);
856 REQUIRE(!isc_g_appctx.blocked);
858 isc_g_appctx.blocked = ISC_TRUE;
859 #ifdef ISC_PLATFORM_USETHREADS
860 blockedthread = pthread_self();
861 RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
862 sigaddset(&sset, SIGINT) == 0 &&
863 sigaddset(&sset, SIGTERM) == 0);
864 RUNTIME_CHECK(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) == 0);
865 #endif /* ISC_PLATFORM_USETHREADS */
868 ISC_APPFUNC_SCOPE void
869 isc__app_unblock(void) {
870 #ifdef ISC_PLATFORM_USETHREADS
872 #endif /* ISC_PLATFORM_USETHREADS */
874 REQUIRE(isc_g_appctx.running);
875 REQUIRE(isc_g_appctx.blocked);
877 isc_g_appctx.blocked = ISC_FALSE;
879 #ifdef ISC_PLATFORM_USETHREADS
880 REQUIRE(blockedthread == pthread_self());
882 RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
883 sigaddset(&sset, SIGINT) == 0 &&
884 sigaddset(&sset, SIGTERM) == 0);
885 RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
886 #endif /* ISC_PLATFORM_USETHREADS */
889 ISC_APPFUNC_SCOPE isc_result_t
890 isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) {
893 REQUIRE(mctx != NULL);
894 REQUIRE(ctxp != NULL && *ctxp == NULL);
896 ctx = isc_mem_get(mctx, sizeof(*ctx));
898 return (ISC_R_NOMEMORY);
900 ctx->common.impmagic = APPCTX_MAGIC;
901 ctx->common.magic = ISCAPI_APPCTX_MAGIC;
902 ctx->common.methods = &appmethods.methods;
905 isc_mem_attach(mctx, &ctx->mctx);
908 ctx->socketmgr = NULL;
909 ctx->timermgr = NULL;
911 *ctxp = (isc_appctx_t *)ctx;
913 return (ISC_R_SUCCESS);
916 ISC_APPFUNC_SCOPE void
917 isc__appctx_destroy(isc_appctx_t **ctxp) {
920 REQUIRE(ctxp != NULL);
921 ctx = (isc__appctx_t *)*ctxp;
922 REQUIRE(VALID_APPCTX(ctx));
924 isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx));
929 ISC_APPFUNC_SCOPE void
930 isc__appctx_settaskmgr(isc_appctx_t *ctx0, isc_taskmgr_t *taskmgr) {
931 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
933 REQUIRE(VALID_APPCTX(ctx));
935 ctx->taskmgr = taskmgr;
938 ISC_APPFUNC_SCOPE void
939 isc__appctx_setsocketmgr(isc_appctx_t *ctx0, isc_socketmgr_t *socketmgr) {
940 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
942 REQUIRE(VALID_APPCTX(ctx));
944 ctx->socketmgr = socketmgr;
947 ISC_APPFUNC_SCOPE void
948 isc__appctx_settimermgr(isc_appctx_t *ctx0, isc_timermgr_t *timermgr) {
949 isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
951 REQUIRE(VALID_APPCTX(ctx));
953 ctx->timermgr = timermgr;
956 #ifdef USE_APPIMPREGISTER
958 isc__app_register() {
959 return (isc_app_register(isc__appctx_create));