app.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007-2009, 2013-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <sys/param.h>  /* Openserver 5.0.6A and FD_SETSIZE */
00023 #include <sys/types.h>
00024 
00025 #include <stddef.h>
00026 #include <stdlib.h>
00027 #include <errno.h>
00028 #include <unistd.h>
00029 #include <signal.h>
00030 #include <sys/time.h>
00031 #ifdef HAVE_EPOLL
00032 #include <sys/epoll.h>
00033 #endif
00034 
00035 #include <isc/app.h>
00036 #include <isc/boolean.h>
00037 #include <isc/condition.h>
00038 #include <isc/mem.h>
00039 #include <isc/msgs.h>
00040 #include <isc/mutex.h>
00041 #include <isc/event.h>
00042 #include <isc/platform.h>
00043 #include <isc/strerror.h>
00044 #include <isc/string.h>
00045 #include <isc/task.h>
00046 #include <isc/time.h>
00047 #include <isc/util.h>
00048 
00049 #ifdef ISC_PLATFORM_USETHREADS
00050 #include <pthread.h>
00051 #endif
00052 
00053 /*%
00054  * For BIND9 internal applications built with threads, we use a single app
00055  * context and let multiple worker, I/O, timer threads do actual jobs.
00056  * For other cases (including BIND9 built without threads) an app context acts
00057  * as an event loop dispatching various events.
00058  */
00059 #ifndef ISC_PLATFORM_USETHREADS
00060 #include "../timer_p.h"
00061 #include "../task_p.h"
00062 #include "socket_p.h"
00063 #endif /* ISC_PLATFORM_USETHREADS */
00064 
00065 #ifdef ISC_PLATFORM_USETHREADS
00066 static pthread_t                blockedthread;
00067 #endif /* ISC_PLATFORM_USETHREADS */
00068 
00069 /*%
00070  * The following are intended for internal use (indicated by "isc__"
00071  * prefix) but are not declared as static, allowing direct access from
00072  * unit tests etc.
00073  */
00074 isc_result_t isc__app_start(void);
00075 isc_result_t isc__app_ctxstart(isc_appctx_t *ctx);
00076 isc_result_t isc__app_onrun(isc_mem_t *mctx, isc_task_t *task,
00077                             isc_taskaction_t action, void *arg);
00078 isc_result_t isc__app_ctxrun(isc_appctx_t *ctx);
00079 isc_result_t isc__app_run(void);
00080 isc_result_t isc__app_ctxshutdown(isc_appctx_t *ctx);
00081 isc_result_t isc__app_shutdown(void);
00082 isc_result_t isc__app_reload(void);
00083 isc_result_t isc__app_ctxsuspend(isc_appctx_t *ctx);
00084 void isc__app_ctxfinish(isc_appctx_t *ctx);
00085 void isc__app_finish(void);
00086 void isc__app_block(void);
00087 void isc__app_unblock(void);
00088 isc_result_t isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp);
00089 void isc__appctx_destroy(isc_appctx_t **ctxp);
00090 void isc__appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr);
00091 void isc__appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr);
00092 void isc__appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr);
00093 isc_result_t isc__app_ctxonrun(isc_appctx_t *ctx, isc_mem_t *mctx,
00094                                isc_task_t *task, isc_taskaction_t action,
00095                                void *arg);
00096 
00097 /*
00098  * The application context of this module.  This implementation actually
00099  * doesn't use it. (This may change in the future).
00100  */
00101 #define APPCTX_MAGIC            ISC_MAGIC('A', 'p', 'c', 'x')
00102 #define VALID_APPCTX(c)         ISC_MAGIC_VALID(c, APPCTX_MAGIC)
00103 
00104 typedef struct isc__appctx {
00105         isc_appctx_t            common;
00106         isc_mem_t               *mctx;
00107         isc_mutex_t             lock;
00108         isc_eventlist_t         on_run;
00109         isc_boolean_t           shutdown_requested;
00110         isc_boolean_t           running;
00111 
00112         /*!
00113          * We assume that 'want_shutdown' can be read and written atomically.
00114          */
00115         isc_boolean_t           want_shutdown;
00116         /*
00117          * We assume that 'want_reload' can be read and written atomically.
00118          */
00119         isc_boolean_t           want_reload;
00120 
00121         isc_boolean_t           blocked;
00122 
00123         isc_taskmgr_t           *taskmgr;
00124         isc_socketmgr_t         *socketmgr;
00125         isc_timermgr_t          *timermgr;
00126 #ifdef ISC_PLATFORM_USETHREADS
00127         isc_mutex_t             readylock;
00128         isc_condition_t         ready;
00129 #endif /* ISC_PLATFORM_USETHREADS */
00130 } isc__appctx_t;
00131 
00132 static isc__appctx_t isc_g_appctx;
00133 
00134 static struct {
00135         isc_appmethods_t methods;
00136 
00137         /*%
00138          * The following are defined just for avoiding unused static functions.
00139          */
00140         void *run, *shutdown, *start, *reload, *finish, *block, *unblock;
00141 } appmethods = {
00142         {
00143                 isc__appctx_destroy,
00144                 isc__app_ctxstart,
00145                 isc__app_ctxrun,
00146                 isc__app_ctxsuspend,
00147                 isc__app_ctxshutdown,
00148                 isc__app_ctxfinish,
00149                 isc__appctx_settaskmgr,
00150                 isc__appctx_setsocketmgr,
00151                 isc__appctx_settimermgr,
00152                 isc__app_ctxonrun
00153         },
00154         (void *)isc__app_run,
00155         (void *)isc__app_shutdown,
00156         (void *)isc__app_start,
00157         (void *)isc__app_reload,
00158         (void *)isc__app_finish,
00159         (void *)isc__app_block,
00160         (void *)isc__app_unblock
00161 };
00162 
00163 #ifdef HAVE_LINUXTHREADS
00164 /*!
00165  * Linux has sigwait(), but it appears to prevent signal handlers from
00166  * running, even if they're not in the set being waited for.  This makes
00167  * it impossible to get the default actions for SIGILL, SIGSEGV, etc.
00168  * Instead of messing with it, we just use sigsuspend() instead.
00169  */
00170 #undef HAVE_SIGWAIT
00171 /*!
00172  * We need to remember which thread is the main thread...
00173  */
00174 static pthread_t                main_thread;
00175 #endif
00176 
00177 #ifndef HAVE_SIGWAIT
00178 static void
00179 exit_action(int arg) {
00180         UNUSED(arg);
00181         isc_g_appctx.want_shutdown = ISC_TRUE;
00182 }
00183 
00184 static void
00185 reload_action(int arg) {
00186         UNUSED(arg);
00187         isc_g_appctx.want_reload = ISC_TRUE;
00188 }
00189 #endif
00190 
00191 static isc_result_t
00192 handle_signal(int sig, void (*handler)(int)) {
00193         struct sigaction sa;
00194         char strbuf[ISC_STRERRORSIZE];
00195 
00196         memset(&sa, 0, sizeof(sa));
00197         sa.sa_handler = handler;
00198 
00199         if (sigfillset(&sa.sa_mask) != 0 ||
00200             sigaction(sig, &sa, NULL) < 0) {
00201                 isc__strerror(errno, strbuf, sizeof(strbuf));
00202                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00203                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP,
00204                                                ISC_MSG_SIGNALSETUP,
00205                                                "handle_signal() %d setup: %s"),
00206                                  sig, strbuf);
00207                 return (ISC_R_UNEXPECTED);
00208         }
00209 
00210         return (ISC_R_SUCCESS);
00211 }
00212 
00213 isc_result_t
00214 isc__app_ctxstart(isc_appctx_t *ctx0) {
00215         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
00216         isc_result_t result;
00217         int presult;
00218         sigset_t sset;
00219         char strbuf[ISC_STRERRORSIZE];
00220 
00221         REQUIRE(VALID_APPCTX(ctx));
00222 
00223         /*
00224          * Start an ISC library application.
00225          */
00226 
00227 #ifdef NEED_PTHREAD_INIT
00228         /*
00229          * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this.
00230          */
00231         presult = pthread_init();
00232         if (presult != 0) {
00233                 isc__strerror(presult, strbuf, sizeof(strbuf));
00234                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00235                                  "isc_app_start() pthread_init: %s", strbuf);
00236                 return (ISC_R_UNEXPECTED);
00237         }
00238 #endif
00239 
00240 #ifdef ISC_PLATFORM_USETHREADS
00241 #ifdef HAVE_LINUXTHREADS
00242         main_thread = pthread_self();
00243 #endif /* HAVE_LINUXTHREADS */
00244 
00245         result = isc_mutex_init(&ctx->readylock);
00246         if (result != ISC_R_SUCCESS)
00247                 return (result);
00248 
00249         result = isc_condition_init(&ctx->ready);
00250         if (result != ISC_R_SUCCESS)
00251                 goto cleanup_rlock;
00252 
00253         result = isc_mutex_init(&ctx->lock);
00254         if (result != ISC_R_SUCCESS)
00255                 goto cleanup_rcond;
00256 #else /* ISC_PLATFORM_USETHREADS */
00257         result = isc_mutex_init(&ctx->lock);
00258         if (result != ISC_R_SUCCESS)
00259                 goto cleanup;
00260 #endif /* ISC_PLATFORM_USETHREADS */
00261 
00262         ISC_LIST_INIT(ctx->on_run);
00263 
00264         ctx->shutdown_requested = ISC_FALSE;
00265         ctx->running = ISC_FALSE;
00266         ctx->want_shutdown = ISC_FALSE;
00267         ctx->want_reload = ISC_FALSE;
00268         ctx->blocked = ISC_FALSE;
00269 
00270 #ifndef HAVE_SIGWAIT
00271         /*
00272          * Install do-nothing handlers for SIGINT and SIGTERM.
00273          *
00274          * We install them now because BSDI 3.1 won't block
00275          * the default actions, regardless of what we do with
00276          * pthread_sigmask().
00277          */
00278         result = handle_signal(SIGINT, exit_action);
00279         if (result != ISC_R_SUCCESS)
00280                 goto cleanup;
00281         result = handle_signal(SIGTERM, exit_action);
00282         if (result != ISC_R_SUCCESS)
00283                 goto cleanup;
00284 #endif
00285 
00286         /*
00287          * Always ignore SIGPIPE.
00288          */
00289         result = handle_signal(SIGPIPE, SIG_IGN);
00290         if (result != ISC_R_SUCCESS)
00291                 goto cleanup;
00292 
00293         /*
00294          * On Solaris 2, delivery of a signal whose action is SIG_IGN
00295          * will not cause sigwait() to return. We may have inherited
00296          * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent
00297          * process (e.g, Solaris cron).  Set an action of SIG_DFL to make
00298          * sure sigwait() works as expected.  Only do this for SIGTERM and
00299          * SIGINT if we don't have sigwait(), since a different handler is
00300          * installed above.
00301          */
00302         result = handle_signal(SIGHUP, SIG_DFL);
00303         if (result != ISC_R_SUCCESS)
00304                 goto cleanup;
00305 
00306 #ifdef HAVE_SIGWAIT
00307         result = handle_signal(SIGTERM, SIG_DFL);
00308         if (result != ISC_R_SUCCESS)
00309                 goto cleanup;
00310         result = handle_signal(SIGINT, SIG_DFL);
00311         if (result != ISC_R_SUCCESS)
00312                 goto cleanup;
00313 #endif
00314 
00315 #ifdef ISC_PLATFORM_USETHREADS
00316         /*
00317          * Block SIGHUP, SIGINT, SIGTERM.
00318          *
00319          * If isc_app_start() is called from the main thread before any other
00320          * threads have been created, then the pthread_sigmask() call below
00321          * will result in all threads having SIGHUP, SIGINT and SIGTERM
00322          * blocked by default, ensuring that only the thread that calls
00323          * sigwait() for them will get those signals.
00324          */
00325         if (sigemptyset(&sset) != 0 ||
00326             sigaddset(&sset, SIGHUP) != 0 ||
00327             sigaddset(&sset, SIGINT) != 0 ||
00328             sigaddset(&sset, SIGTERM) != 0) {
00329                 isc__strerror(errno, strbuf, sizeof(strbuf));
00330                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00331                                  "isc_app_start() sigsetops: %s", strbuf);
00332                 result = ISC_R_UNEXPECTED;
00333                 goto cleanup;
00334         }
00335         presult = pthread_sigmask(SIG_BLOCK, &sset, NULL);
00336         if (presult != 0) {
00337                 isc__strerror(presult, strbuf, sizeof(strbuf));
00338                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00339                                  "isc_app_start() pthread_sigmask: %s",
00340                                  strbuf);
00341                 result = ISC_R_UNEXPECTED;
00342                 goto cleanup;
00343         }
00344 #else /* ISC_PLATFORM_USETHREADS */
00345         /*
00346          * Unblock SIGHUP, SIGINT, SIGTERM.
00347          *
00348          * If we're not using threads, we need to make sure that SIGHUP,
00349          * SIGINT and SIGTERM are not inherited as blocked from the parent
00350          * process.
00351          */
00352         if (sigemptyset(&sset) != 0 ||
00353             sigaddset(&sset, SIGHUP) != 0 ||
00354             sigaddset(&sset, SIGINT) != 0 ||
00355             sigaddset(&sset, SIGTERM) != 0) {
00356                 isc__strerror(errno, strbuf, sizeof(strbuf));
00357                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00358                                  "isc_app_start() sigsetops: %s", strbuf);
00359                 result = ISC_R_UNEXPECTED;
00360                 goto cleanup;
00361         }
00362         presult = sigprocmask(SIG_UNBLOCK, &sset, NULL);
00363         if (presult != 0) {
00364                 isc__strerror(errno, strbuf, sizeof(strbuf));
00365                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00366                                  "isc_app_start() sigprocmask: %s", strbuf);
00367                 result = ISC_R_UNEXPECTED;
00368                 goto cleanup;
00369         }
00370 #endif /* ISC_PLATFORM_USETHREADS */
00371 
00372         return (ISC_R_SUCCESS);
00373 
00374  cleanup:
00375 #ifdef ISC_PLATFORM_USETHREADS
00376  cleanup_rcond:
00377         (void)isc_condition_destroy(&ctx->ready);
00378 
00379  cleanup_rlock:
00380         (void)isc_mutex_destroy(&ctx->readylock);
00381 #endif /* ISC_PLATFORM_USETHREADS */
00382         return (result);
00383 }
00384 
00385 isc_result_t
00386 isc__app_start(void) {
00387         isc_g_appctx.common.impmagic = APPCTX_MAGIC;
00388         isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC;
00389         isc_g_appctx.common.methods = &appmethods.methods;
00390         isc_g_appctx.mctx = NULL;
00391         /* The remaining members will be initialized in ctxstart() */
00392 
00393         return (isc__app_ctxstart((isc_appctx_t *)&isc_g_appctx));
00394 }
00395 
00396 isc_result_t
00397 isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
00398               void *arg)
00399 {
00400         return (isc__app_ctxonrun((isc_appctx_t *)&isc_g_appctx, mctx,
00401                                   task, action, arg));
00402 }
00403 
00404 isc_result_t
00405 isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
00406                   isc_taskaction_t action, void *arg)
00407 {
00408         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
00409         isc_event_t *event;
00410         isc_task_t *cloned_task = NULL;
00411         isc_result_t result;
00412 
00413         LOCK(&ctx->lock);
00414 
00415         if (ctx->running) {
00416                 result = ISC_R_ALREADYRUNNING;
00417                 goto unlock;
00418         }
00419 
00420         /*
00421          * Note that we store the task to which we're going to send the event
00422          * in the event's "sender" field.
00423          */
00424         isc_task_attach(task, &cloned_task);
00425         event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
00426                                    action, arg, sizeof(*event));
00427         if (event == NULL) {
00428                 result = ISC_R_NOMEMORY;
00429                 goto unlock;
00430         }
00431 
00432         ISC_LIST_APPEND(ctx->on_run, event, ev_link);
00433 
00434         result = ISC_R_SUCCESS;
00435 
00436  unlock:
00437         UNLOCK(&ctx->lock);
00438 
00439         return (result);
00440 }
00441 
00442 #ifndef ISC_PLATFORM_USETHREADS
00443 /*!
00444  * Event loop for nonthreaded programs.
00445  */
00446 static isc_result_t
00447 evloop(isc__appctx_t *ctx) {
00448         isc_result_t result;
00449 
00450         while (!ctx->want_shutdown) {
00451                 int n;
00452                 isc_time_t when, now;
00453                 struct timeval tv, *tvp;
00454                 isc_socketwait_t *swait;
00455                 isc_boolean_t readytasks;
00456                 isc_boolean_t call_timer_dispatch = ISC_FALSE;
00457 
00458                 /*
00459                  * Check the reload (or suspend) case first for exiting the
00460                  * loop as fast as possible in case:
00461                  *   - the direct call to isc__taskmgr_dispatch() in
00462                  *     isc__app_ctxrun() completes all the tasks so far,
00463                  *   - there is thus currently no active task, and
00464                  *   - there is a timer event
00465                  */
00466                 if (ctx->want_reload) {
00467                         ctx->want_reload = ISC_FALSE;
00468                         return (ISC_R_RELOAD);
00469                 }
00470 
00471                 readytasks = isc__taskmgr_ready(ctx->taskmgr);
00472                 if (readytasks) {
00473                         tv.tv_sec = 0;
00474                         tv.tv_usec = 0;
00475                         tvp = &tv;
00476                         call_timer_dispatch = ISC_TRUE;
00477                 } else {
00478                         result = isc__timermgr_nextevent(ctx->timermgr, &when);
00479                         if (result != ISC_R_SUCCESS)
00480                                 tvp = NULL;
00481                         else {
00482                                 isc_uint64_t us;
00483 
00484                                 TIME_NOW(&now);
00485                                 us = isc_time_microdiff(&when, &now);
00486                                 if (us == 0)
00487                                         call_timer_dispatch = ISC_TRUE;
00488                                 tv.tv_sec = us / 1000000;
00489                                 tv.tv_usec = us % 1000000;
00490                                 tvp = &tv;
00491                         }
00492                 }
00493 
00494                 swait = NULL;
00495                 n = isc__socketmgr_waitevents(ctx->socketmgr, tvp, &swait);
00496 
00497                 if (n == 0 || call_timer_dispatch) {
00498                         /*
00499                          * We call isc__timermgr_dispatch() only when
00500                          * necessary, in order to reduce overhead.  If the
00501                          * select() call indicates a timeout, we need the
00502                          * dispatch.  Even if not, if we set the 0-timeout
00503                          * for the select() call, we need to check the timer
00504                          * events.  In the 'readytasks' case, there may be no
00505                          * timeout event actually, but there is no other way
00506                          * to reduce the overhead.
00507                          * Note that we do not have to worry about the case
00508                          * where a new timer is inserted during the select()
00509                          * call, since this loop only runs in the non-thread
00510                          * mode.
00511                          */
00512                         isc__timermgr_dispatch(ctx->timermgr);
00513                 }
00514                 if (n > 0)
00515                         (void)isc__socketmgr_dispatch(ctx->socketmgr, swait);
00516                 (void)isc__taskmgr_dispatch(ctx->taskmgr);
00517         }
00518         return (ISC_R_SUCCESS);
00519 }
00520 
00521 /*
00522  * This is a gross hack to support waiting for condition
00523  * variables in nonthreaded programs in a limited way;
00524  * see lib/isc/nothreads/include/isc/condition.h.
00525  * We implement isc_condition_wait() by entering the
00526  * event loop recursively until the want_shutdown flag
00527  * is set by isc_condition_signal().
00528  */
00529 
00530 /*!
00531  * \brief True if we are currently executing in the recursive
00532  * event loop.
00533  */
00534 static isc_boolean_t in_recursive_evloop = ISC_FALSE;
00535 
00536 /*!
00537  * \brief True if we are exiting the event loop as the result of
00538  * a call to isc_condition_signal() rather than a shutdown
00539  * or reload.
00540  */
00541 static isc_boolean_t signalled = ISC_FALSE;
00542 
00543 isc_result_t
00544 isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) {
00545         isc_result_t result;
00546 
00547         UNUSED(cp);
00548         UNUSED(mp);
00549 
00550         INSIST(!in_recursive_evloop);
00551         in_recursive_evloop = ISC_TRUE;
00552 
00553         INSIST(*mp == 1); /* Mutex must be locked on entry. */
00554         --*mp;
00555 
00556         result = evloop(&isc_g_appctx);
00557         if (result == ISC_R_RELOAD)
00558                 isc_g_appctx.want_reload = ISC_TRUE;
00559         if (signalled) {
00560                 isc_g_appctx.want_shutdown = ISC_FALSE;
00561                 signalled = ISC_FALSE;
00562         }
00563 
00564         ++*mp;
00565         in_recursive_evloop = ISC_FALSE;
00566         return (ISC_R_SUCCESS);
00567 }
00568 
00569 isc_result_t
00570 isc__nothread_signal_hack(isc_condition_t *cp) {
00571 
00572         UNUSED(cp);
00573 
00574         INSIST(in_recursive_evloop);
00575 
00576         isc_g_appctx.want_shutdown = ISC_TRUE;
00577         signalled = ISC_TRUE;
00578         return (ISC_R_SUCCESS);
00579 }
00580 #endif /* ISC_PLATFORM_USETHREADS */
00581 
00582 isc_result_t
00583 isc__app_ctxrun(isc_appctx_t *ctx0) {
00584         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
00585         int result;
00586         isc_event_t *event, *next_event;
00587         isc_task_t *task;
00588 #ifdef ISC_PLATFORM_USETHREADS
00589         sigset_t sset;
00590         char strbuf[ISC_STRERRORSIZE];
00591 #ifdef HAVE_SIGWAIT
00592         int sig;
00593 #endif /* HAVE_SIGWAIT */
00594 #endif /* ISC_PLATFORM_USETHREADS */
00595 
00596         REQUIRE(VALID_APPCTX(ctx));
00597 
00598 #ifdef HAVE_LINUXTHREADS
00599         REQUIRE(main_thread == pthread_self());
00600 #endif
00601 
00602         LOCK(&ctx->lock);
00603 
00604         if (!ctx->running) {
00605                 ctx->running = ISC_TRUE;
00606 
00607                 /*
00608                  * Post any on-run events (in FIFO order).
00609                  */
00610                 for (event = ISC_LIST_HEAD(ctx->on_run);
00611                      event != NULL;
00612                      event = next_event) {
00613                         next_event = ISC_LIST_NEXT(event, ev_link);
00614                         ISC_LIST_UNLINK(ctx->on_run, event, ev_link);
00615                         task = event->ev_sender;
00616                         event->ev_sender = NULL;
00617                         isc_task_sendanddetach(&task, &event);
00618                 }
00619 
00620         }
00621 
00622         UNLOCK(&ctx->lock);
00623 
00624 #ifndef ISC_PLATFORM_USETHREADS
00625         if (isc_bind9 && ctx == &isc_g_appctx) {
00626                 result = handle_signal(SIGHUP, reload_action);
00627                 if (result != ISC_R_SUCCESS)
00628                         return (ISC_R_SUCCESS);
00629         }
00630 
00631         (void) isc__taskmgr_dispatch(ctx->taskmgr);
00632         result = evloop(ctx);
00633         return (result);
00634 #else /* ISC_PLATFORM_USETHREADS */
00635         /*
00636          * BIND9 internal tools using multiple contexts do not
00637          * rely on signal.
00638          */
00639         if (isc_bind9 && ctx != &isc_g_appctx)
00640                 return (ISC_R_SUCCESS);
00641 
00642         /*
00643          * There is no danger if isc_app_shutdown() is called before we
00644          * wait for signals.  Signals are blocked, so any such signal will
00645          * simply be made pending and we will get it when we call
00646          * sigwait().
00647          */
00648         while (!ctx->want_shutdown) {
00649 #ifdef HAVE_SIGWAIT
00650                 if (isc_bind9) {
00651                         /*
00652                          * BIND9 internal; single context:
00653                          * Wait for SIGHUP, SIGINT, or SIGTERM.
00654                          */
00655                         if (sigemptyset(&sset) != 0 ||
00656                             sigaddset(&sset, SIGHUP) != 0 ||
00657                             sigaddset(&sset, SIGINT) != 0 ||
00658                             sigaddset(&sset, SIGTERM) != 0) {
00659                                 isc__strerror(errno, strbuf, sizeof(strbuf));
00660                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00661                                                  "isc_app_run() sigsetops: %s",
00662                                                  strbuf);
00663                                 return (ISC_R_UNEXPECTED);
00664                         }
00665 
00666 #ifndef HAVE_UNIXWARE_SIGWAIT
00667                         result = sigwait(&sset, &sig);
00668                         if (result == 0) {
00669                                 if (sig == SIGINT || sig == SIGTERM)
00670                                         ctx->want_shutdown = ISC_TRUE;
00671                                 else if (sig == SIGHUP)
00672                                         ctx->want_reload = ISC_TRUE;
00673                         }
00674 
00675 #else /* Using UnixWare sigwait semantics. */
00676                         sig = sigwait(&sset);
00677                         if (sig >= 0) {
00678                                 if (sig == SIGINT || sig == SIGTERM)
00679                                         ctx->want_shutdown = ISC_TRUE;
00680                                 else if (sig == SIGHUP)
00681                                         ctx->want_reload = ISC_TRUE;
00682                         }
00683 #endif /* HAVE_UNIXWARE_SIGWAIT */
00684                 } else {
00685                         /*
00686                          * External, or BIND9 using multiple contexts:
00687                          * wait until woken up.
00688                          */
00689                         LOCK(&ctx->readylock);
00690                         if (ctx->want_shutdown) {
00691                                 /* shutdown() won the race. */
00692                                 UNLOCK(&ctx->readylock);
00693                                 break;
00694                         }
00695                         if (!ctx->want_reload)
00696                                 WAIT(&ctx->ready, &ctx->readylock);
00697                         UNLOCK(&ctx->readylock);
00698                 }
00699 #else  /* Don't have sigwait(). */
00700                 if (isc_bind9) {
00701                         /*
00702                          * BIND9 internal; single context:
00703                          * Install a signal handler for SIGHUP, then wait for
00704                          * all signals.
00705                          */
00706                         result = handle_signal(SIGHUP, reload_action);
00707                         if (result != ISC_R_SUCCESS)
00708                                 return (ISC_R_SUCCESS);
00709 
00710                         if (sigemptyset(&sset) != 0) {
00711                                 isc__strerror(errno, strbuf, sizeof(strbuf));
00712                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00713                                                  "isc_app_run() sigsetops: %s",
00714                                                  strbuf);
00715                                 return (ISC_R_UNEXPECTED);
00716                         }
00717 #ifdef HAVE_GPERFTOOLS_PROFILER
00718                         if (sigaddset(&sset, SIGALRM) != 0) {
00719                                 isc__strerror(errno, strbuf, sizeof(strbuf));
00720                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00721                                                  "isc_app_run() sigsetops: %s",
00722                                                  strbuf);
00723                                 return (ISC_R_UNEXPECTED);
00724                         }
00725 #endif
00726                         result = sigsuspend(&sset);
00727                 } else {
00728                         /*
00729                          * External, or BIND9 using multiple contexts:
00730                          * wait until woken up.
00731                          */
00732                         LOCK(&ctx->readylock);
00733                         if (ctx->want_shutdown) {
00734                                 /* shutdown() won the race. */
00735                                 UNLOCK(&ctx->readylock);
00736                                 break;
00737                         }
00738                         if (!ctx->want_reload)
00739                                 WAIT(&ctx->ready, &ctx->readylock);
00740                         UNLOCK(&ctx->readylock);
00741                 }
00742 #endif /* HAVE_SIGWAIT */
00743 
00744                 if (ctx->want_reload) {
00745                         ctx->want_reload = ISC_FALSE;
00746                         return (ISC_R_RELOAD);
00747                 }
00748 
00749                 if (ctx->want_shutdown && ctx->blocked)
00750                         exit(1);
00751         }
00752 
00753         return (ISC_R_SUCCESS);
00754 #endif /* ISC_PLATFORM_USETHREADS */
00755 }
00756 
00757 isc_result_t
00758 isc__app_run(void) {
00759         return (isc__app_ctxrun((isc_appctx_t *)&isc_g_appctx));
00760 }
00761 
00762 isc_result_t
00763 isc__app_ctxshutdown(isc_appctx_t *ctx0) {
00764         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
00765         isc_boolean_t want_kill = ISC_TRUE;
00766 #ifdef ISC_PLATFORM_USETHREADS
00767         char strbuf[ISC_STRERRORSIZE];
00768 #endif /* ISC_PLATFORM_USETHREADS */
00769 
00770         REQUIRE(VALID_APPCTX(ctx));
00771 
00772         LOCK(&ctx->lock);
00773 
00774         REQUIRE(ctx->running);
00775 
00776         if (ctx->shutdown_requested)
00777                 want_kill = ISC_FALSE;
00778         else
00779                 ctx->shutdown_requested = ISC_TRUE;
00780 
00781         UNLOCK(&ctx->lock);
00782 
00783         if (want_kill) {
00784                 if (isc_bind9 && ctx != &isc_g_appctx)
00785                         /* BIND9 internal, but using multiple contexts */
00786                         ctx->want_shutdown = ISC_TRUE;
00787                 else {
00788 #ifndef ISC_PLATFORM_USETHREADS
00789                         ctx->want_shutdown = ISC_TRUE;
00790 #else /* ISC_PLATFORM_USETHREADS */
00791 #ifdef HAVE_LINUXTHREADS
00792                         if (isc_bind9) {
00793                                 /* BIND9 internal, single context */
00794                                 int result;
00795 
00796                                 result = pthread_kill(main_thread, SIGTERM);
00797                                 if (result != 0) {
00798                                         isc__strerror(result,
00799                                                       strbuf, sizeof(strbuf));
00800                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00801                                                          "isc_app_shutdown() "
00802                                                          "pthread_kill: %s",
00803                                                          strbuf);
00804                                         return (ISC_R_UNEXPECTED);
00805                                 }
00806                         }
00807 #else
00808                         if (isc_bind9) {
00809                                 /* BIND9 internal, single context */
00810                                 if (kill(getpid(), SIGTERM) < 0) {
00811                                         isc__strerror(errno,
00812                                                       strbuf, sizeof(strbuf));
00813                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00814                                                          "isc_app_shutdown() "
00815                                                          "kill: %s", strbuf);
00816                                         return (ISC_R_UNEXPECTED);
00817                                 }
00818                         }
00819 #endif /* HAVE_LINUXTHREADS */
00820                         else {
00821                                 /* External, multiple contexts */
00822                                 LOCK(&ctx->readylock);
00823                                 ctx->want_shutdown = ISC_TRUE;
00824                                 UNLOCK(&ctx->readylock);
00825                                 SIGNAL(&ctx->ready);
00826                         }
00827 #endif /* ISC_PLATFORM_USETHREADS */
00828                 }
00829         }
00830 
00831         return (ISC_R_SUCCESS);
00832 }
00833 
00834 isc_result_t
00835 isc__app_shutdown(void) {
00836         return (isc__app_ctxshutdown((isc_appctx_t *)&isc_g_appctx));
00837 }
00838 
00839 isc_result_t
00840 isc__app_ctxsuspend(isc_appctx_t *ctx0) {
00841         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
00842         isc_boolean_t want_kill = ISC_TRUE;
00843 #ifdef ISC_PLATFORM_USETHREADS
00844         char strbuf[ISC_STRERRORSIZE];
00845 #endif
00846 
00847         REQUIRE(VALID_APPCTX(ctx));
00848 
00849         LOCK(&ctx->lock);
00850 
00851         REQUIRE(ctx->running);
00852 
00853         /*
00854          * Don't send the reload signal if we're shutting down.
00855          */
00856         if (ctx->shutdown_requested)
00857                 want_kill = ISC_FALSE;
00858 
00859         UNLOCK(&ctx->lock);
00860 
00861         if (want_kill) {
00862                 if (isc_bind9 && ctx != &isc_g_appctx)
00863                         /* BIND9 internal, but using multiple contexts */
00864                         ctx->want_reload = ISC_TRUE;
00865                 else {
00866 #ifndef ISC_PLATFORM_USETHREADS
00867                         ctx->want_reload = ISC_TRUE;
00868 #else /* ISC_PLATFORM_USETHREADS */
00869 #ifdef HAVE_LINUXTHREADS
00870                         if (isc_bind9) {
00871                                 /* BIND9 internal, single context */
00872                                 int result;
00873 
00874                                 result = pthread_kill(main_thread, SIGHUP);
00875                                 if (result != 0) {
00876                                         isc__strerror(result,
00877                                                       strbuf, sizeof(strbuf));
00878                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00879                                                          "isc_app_reload() "
00880                                                          "pthread_kill: %s",
00881                                                          strbuf);
00882                                         return (ISC_R_UNEXPECTED);
00883                                 }
00884                         }
00885 #else
00886                         if (isc_bind9) {
00887                                 /* BIND9 internal, single context */
00888                                 if (kill(getpid(), SIGHUP) < 0) {
00889                                         isc__strerror(errno,
00890                                                       strbuf, sizeof(strbuf));
00891                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00892                                                          "isc_app_reload() "
00893                                                          "kill: %s", strbuf);
00894                                         return (ISC_R_UNEXPECTED);
00895                                 }
00896                         }
00897 #endif /* HAVE_LINUXTHREADS */
00898                         else {
00899                                 /* External, multiple contexts */
00900                                 LOCK(&ctx->readylock);
00901                                 ctx->want_reload = ISC_TRUE;
00902                                 UNLOCK(&ctx->readylock);
00903                                 SIGNAL(&ctx->ready);
00904                         }
00905 #endif /* ISC_PLATFORM_USETHREADS */
00906                 }
00907         }
00908 
00909         return (ISC_R_SUCCESS);
00910 }
00911 
00912 isc_result_t
00913 isc__app_reload(void) {
00914         return (isc__app_ctxsuspend((isc_appctx_t *)&isc_g_appctx));
00915 }
00916 
00917 void
00918 isc__app_ctxfinish(isc_appctx_t *ctx0) {
00919         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
00920 
00921         REQUIRE(VALID_APPCTX(ctx));
00922 
00923         DESTROYLOCK(&ctx->lock);
00924 }
00925 
00926 void
00927 isc__app_finish(void) {
00928         isc__app_ctxfinish((isc_appctx_t *)&isc_g_appctx);
00929 }
00930 
00931 void
00932 isc__app_block(void) {
00933 #ifdef ISC_PLATFORM_USETHREADS
00934         sigset_t sset;
00935 #endif /* ISC_PLATFORM_USETHREADS */
00936         REQUIRE(isc_g_appctx.running);
00937         REQUIRE(!isc_g_appctx.blocked);
00938 
00939         isc_g_appctx.blocked = ISC_TRUE;
00940 #ifdef ISC_PLATFORM_USETHREADS
00941         blockedthread = pthread_self();
00942         RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
00943                       sigaddset(&sset, SIGINT) == 0 &&
00944                       sigaddset(&sset, SIGTERM) == 0);
00945         RUNTIME_CHECK(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) == 0);
00946 #endif /* ISC_PLATFORM_USETHREADS */
00947 }
00948 
00949 void
00950 isc__app_unblock(void) {
00951 #ifdef ISC_PLATFORM_USETHREADS
00952         sigset_t sset;
00953 #endif /* ISC_PLATFORM_USETHREADS */
00954 
00955         REQUIRE(isc_g_appctx.running);
00956         REQUIRE(isc_g_appctx.blocked);
00957 
00958         isc_g_appctx.blocked = ISC_FALSE;
00959 
00960 #ifdef ISC_PLATFORM_USETHREADS
00961         REQUIRE(blockedthread == pthread_self());
00962 
00963         RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
00964                       sigaddset(&sset, SIGINT) == 0 &&
00965                       sigaddset(&sset, SIGTERM) == 0);
00966         RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
00967 #endif /* ISC_PLATFORM_USETHREADS */
00968 }
00969 
00970 isc_result_t
00971 isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) {
00972         isc__appctx_t *ctx;
00973 
00974         REQUIRE(mctx != NULL);
00975         REQUIRE(ctxp != NULL && *ctxp == NULL);
00976 
00977         ctx = isc_mem_get(mctx, sizeof(*ctx));
00978         if (ctx == NULL)
00979                 return (ISC_R_NOMEMORY);
00980 
00981         ctx->common.impmagic = APPCTX_MAGIC;
00982         ctx->common.magic = ISCAPI_APPCTX_MAGIC;
00983         ctx->common.methods = &appmethods.methods;
00984 
00985         ctx->mctx = NULL;
00986         isc_mem_attach(mctx, &ctx->mctx);
00987 
00988         ctx->taskmgr = NULL;
00989         ctx->socketmgr = NULL;
00990         ctx->timermgr = NULL;
00991 
00992         *ctxp = (isc_appctx_t *)ctx;
00993 
00994         return (ISC_R_SUCCESS);
00995 }
00996 
00997 void
00998 isc__appctx_destroy(isc_appctx_t **ctxp) {
00999         isc__appctx_t *ctx;
01000 
01001         REQUIRE(ctxp != NULL);
01002         ctx = (isc__appctx_t *)*ctxp;
01003         REQUIRE(VALID_APPCTX(ctx));
01004 
01005         isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx));
01006 
01007         *ctxp = NULL;
01008 }
01009 
01010 void
01011 isc__appctx_settaskmgr(isc_appctx_t *ctx0, isc_taskmgr_t *taskmgr) {
01012         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
01013 
01014         REQUIRE(VALID_APPCTX(ctx));
01015 
01016         ctx->taskmgr = taskmgr;
01017 }
01018 
01019 void
01020 isc__appctx_setsocketmgr(isc_appctx_t *ctx0, isc_socketmgr_t *socketmgr) {
01021         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
01022 
01023         REQUIRE(VALID_APPCTX(ctx));
01024 
01025         ctx->socketmgr = socketmgr;
01026 }
01027 
01028 void
01029 isc__appctx_settimermgr(isc_appctx_t *ctx0, isc_timermgr_t *timermgr) {
01030         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
01031 
01032         REQUIRE(VALID_APPCTX(ctx));
01033 
01034         ctx->timermgr = timermgr;
01035 }
01036 
01037 isc_result_t
01038 isc__app_register(void) {
01039         return (isc_app_register(isc__appctx_create));
01040 }
01041 
01042 #include "../app_api.c"

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha