]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/isc/unix/app.c
Update BIND to 9.9.8
[FreeBSD/stable/9.git] / contrib / bind9 / lib / isc / unix / app.c
1 /*
2  * Copyright (C) 2004, 2005, 2007-2009, 2013-2015  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: app.c,v 1.64 2009/11/04 05:58:46 marka Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <sys/param.h>  /* Openserver 5.0.6A and FD_SETSIZE */
25 #include <sys/types.h>
26
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <sys/time.h>
33 #ifdef HAVE_EPOLL
34 #include <sys/epoll.h>
35 #endif
36
37 #include <isc/app.h>
38 #include <isc/boolean.h>
39 #include <isc/condition.h>
40 #include <isc/mem.h>
41 #include <isc/msgs.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>
47 #include <isc/task.h>
48 #include <isc/time.h>
49 #include <isc/util.h>
50
51 /*%
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.
56  */
57 #if defined(ISC_PLATFORM_USETHREADS) && defined(BIND9)
58 #define USE_THREADS_SINGLECTX
59 #endif
60
61 #ifdef ISC_PLATFORM_USETHREADS
62 #include <pthread.h>
63 #endif
64
65 #ifndef USE_THREADS_SINGLECTX
66 #include "../timer_p.h"
67 #include "../task_p.h"
68 #include "socket_p.h"
69 #endif /* USE_THREADS_SINGLECTX */
70
71 #ifdef ISC_PLATFORM_USETHREADS
72 static pthread_t                blockedthread;
73 #endif /* ISC_PLATFORM_USETHREADS */
74
75 /*%
76  * The following can be either static or public, depending on build environment.
77  */
78
79 #ifdef BIND9
80 #define ISC_APPFUNC_SCOPE
81 #else
82 #define ISC_APPFUNC_SCOPE static
83 #endif
84
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,
88                                               isc_task_t *task,
89                                               isc_taskaction_t action,
90                                               void *arg);
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_boolean_t isc__app_isrunning(void);
94 ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxshutdown(isc_appctx_t *ctx);
95 ISC_APPFUNC_SCOPE isc_result_t isc__app_shutdown(void);
96 ISC_APPFUNC_SCOPE isc_result_t isc__app_reload(void);
97 ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxsuspend(isc_appctx_t *ctx);
98 ISC_APPFUNC_SCOPE void isc__app_ctxfinish(isc_appctx_t *ctx);
99 ISC_APPFUNC_SCOPE void isc__app_finish(void);
100 ISC_APPFUNC_SCOPE void isc__app_block(void);
101 ISC_APPFUNC_SCOPE void isc__app_unblock(void);
102 ISC_APPFUNC_SCOPE isc_result_t isc__appctx_create(isc_mem_t *mctx,
103                                                   isc_appctx_t **ctxp);
104 ISC_APPFUNC_SCOPE void isc__appctx_destroy(isc_appctx_t **ctxp);
105 ISC_APPFUNC_SCOPE void isc__appctx_settaskmgr(isc_appctx_t *ctx,
106                                               isc_taskmgr_t *taskmgr);
107 ISC_APPFUNC_SCOPE void isc__appctx_setsocketmgr(isc_appctx_t *ctx,
108                                                 isc_socketmgr_t *socketmgr);
109 ISC_APPFUNC_SCOPE void isc__appctx_settimermgr(isc_appctx_t *ctx,
110                                                isc_timermgr_t *timermgr);
111 ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxonrun(isc_appctx_t *ctx,
112                                                  isc_mem_t *mctx,
113                                                  isc_task_t *task,
114                                                  isc_taskaction_t action,
115                                                  void *arg);
116
117 /*
118  * The application context of this module.  This implementation actually
119  * doesn't use it. (This may change in the future).
120  */
121 #define APPCTX_MAGIC            ISC_MAGIC('A', 'p', 'c', 'x')
122 #define VALID_APPCTX(c)         ISC_MAGIC_VALID(c, APPCTX_MAGIC)
123
124 typedef struct isc__appctx {
125         isc_appctx_t            common;
126         isc_mem_t               *mctx;
127         isc_mutex_t             lock;
128         isc_eventlist_t         on_run;
129         isc_boolean_t           shutdown_requested;
130         isc_boolean_t           running;
131
132         /*!
133          * We assume that 'want_shutdown' can be read and written atomically.
134          */
135         isc_boolean_t           want_shutdown;
136         /*
137          * We assume that 'want_reload' can be read and written atomically.
138          */
139         isc_boolean_t           want_reload;
140
141         isc_boolean_t           blocked;
142
143         isc_taskmgr_t           *taskmgr;
144         isc_socketmgr_t         *socketmgr;
145         isc_timermgr_t          *timermgr;
146 } isc__appctx_t;
147
148 static isc__appctx_t isc_g_appctx;
149 static isc_boolean_t is_running = ISC_FALSE;
150
151 static struct {
152         isc_appmethods_t methods;
153
154         /*%
155          * The following are defined just for avoiding unused static functions.
156          */
157 #ifndef BIND9
158         void *run, *shutdown, *start, *onrun,
159              *reload, *finish, *block, *unblock,
160              *isrunning;
161 #endif
162 } appmethods = {
163         {
164                 isc__appctx_destroy,
165                 isc__app_ctxstart,
166                 isc__app_ctxrun,
167                 isc__app_ctxsuspend,
168                 isc__app_ctxshutdown,
169                 isc__app_ctxfinish,
170                 isc__appctx_settaskmgr,
171                 isc__appctx_setsocketmgr,
172                 isc__appctx_settimermgr,
173                 isc__app_ctxonrun
174         }
175 #ifndef BIND9
176         ,
177         (void *)isc__app_run, (void *)isc__app_shutdown,
178         (void *)isc__app_start, (void *)isc__app_onrun, (void *)isc__app_reload,
179         (void *)isc__app_finish, (void *)isc__app_block,
180         (void *)isc__app_unblock, (void *)isc__app_isrunning
181 #endif
182 };
183
184 #ifdef HAVE_LINUXTHREADS
185 /*!
186  * Linux has sigwait(), but it appears to prevent signal handlers from
187  * running, even if they're not in the set being waited for.  This makes
188  * it impossible to get the default actions for SIGILL, SIGSEGV, etc.
189  * Instead of messing with it, we just use sigsuspend() instead.
190  */
191 #undef HAVE_SIGWAIT
192 /*!
193  * We need to remember which thread is the main thread...
194  */
195 static pthread_t                main_thread;
196 #endif
197
198 #ifndef HAVE_SIGWAIT
199 static void
200 exit_action(int arg) {
201         UNUSED(arg);
202         isc_g_appctx.want_shutdown = ISC_TRUE;
203 }
204
205 static void
206 reload_action(int arg) {
207         UNUSED(arg);
208         isc_g_appctx.want_reload = ISC_TRUE;
209 }
210 #endif
211
212 static isc_result_t
213 handle_signal(int sig, void (*handler)(int)) {
214         struct sigaction sa;
215         char strbuf[ISC_STRERRORSIZE];
216
217         memset(&sa, 0, sizeof(sa));
218         sa.sa_handler = handler;
219
220         if (sigfillset(&sa.sa_mask) != 0 ||
221             sigaction(sig, &sa, NULL) < 0) {
222                 isc__strerror(errno, strbuf, sizeof(strbuf));
223                 UNEXPECTED_ERROR(__FILE__, __LINE__,
224                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP,
225                                                ISC_MSG_SIGNALSETUP,
226                                                "handle_signal() %d setup: %s"),
227                                  sig, strbuf);
228                 return (ISC_R_UNEXPECTED);
229         }
230
231         return (ISC_R_SUCCESS);
232 }
233
234 ISC_APPFUNC_SCOPE isc_result_t
235 isc__app_ctxstart(isc_appctx_t *ctx0) {
236         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
237         isc_result_t result;
238
239         REQUIRE(VALID_APPCTX(ctx));
240
241         /*
242          * Start an ISC library application.
243          */
244
245 #ifdef NEED_PTHREAD_INIT
246         /*
247          * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this.
248          */
249         presult = pthread_init();
250         if (presult != 0) {
251                 isc__strerror(presult, strbuf, sizeof(strbuf));
252                 UNEXPECTED_ERROR(__FILE__, __LINE__,
253                                  "isc_app_start() pthread_init: %s", strbuf);
254                 return (ISC_R_UNEXPECTED);
255         }
256 #endif
257
258 #ifdef HAVE_LINUXTHREADS
259         main_thread = pthread_self();
260 #endif
261
262         result = isc_mutex_init(&ctx->lock);
263         if (result != ISC_R_SUCCESS)
264                 return (result);
265
266         ISC_LIST_INIT(ctx->on_run);
267
268         ctx->shutdown_requested = ISC_FALSE;
269         ctx->running = ISC_FALSE;
270         ctx->want_shutdown = ISC_FALSE;
271         ctx->want_reload = ISC_FALSE;
272         ctx->blocked = ISC_FALSE;
273
274         return (ISC_R_SUCCESS);
275 }
276
277 ISC_APPFUNC_SCOPE isc_result_t
278 isc__app_start(void) {
279         isc_result_t result;
280         int presult;
281         sigset_t sset;
282         char strbuf[ISC_STRERRORSIZE];
283
284         isc_g_appctx.common.impmagic = APPCTX_MAGIC;
285         isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC;
286         isc_g_appctx.common.methods = &appmethods.methods;
287         isc_g_appctx.mctx = NULL;
288         /* The remaining members will be initialized in ctxstart() */
289
290         result = isc__app_ctxstart((isc_appctx_t *)&isc_g_appctx);
291         if (result != ISC_R_SUCCESS)
292                 return (result);
293
294 #ifndef HAVE_SIGWAIT
295         /*
296          * Install do-nothing handlers for SIGINT and SIGTERM.
297          *
298          * We install them now because BSDI 3.1 won't block
299          * the default actions, regardless of what we do with
300          * pthread_sigmask().
301          */
302         result = handle_signal(SIGINT, exit_action);
303         if (result != ISC_R_SUCCESS)
304                 return (result);
305         result = handle_signal(SIGTERM, exit_action);
306         if (result != ISC_R_SUCCESS)
307                 return (result);
308 #endif
309
310         /*
311          * Always ignore SIGPIPE.
312          */
313         result = handle_signal(SIGPIPE, SIG_IGN);
314         if (result != ISC_R_SUCCESS)
315                 return (result);
316
317         /*
318          * On Solaris 2, delivery of a signal whose action is SIG_IGN
319          * will not cause sigwait() to return. We may have inherited
320          * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent
321          * process (e.g, Solaris cron).  Set an action of SIG_DFL to make
322          * sure sigwait() works as expected.  Only do this for SIGTERM and
323          * SIGINT if we don't have sigwait(), since a different handler is
324          * installed above.
325          */
326         result = handle_signal(SIGHUP, SIG_DFL);
327         if (result != ISC_R_SUCCESS)
328                 return (result);
329
330 #ifdef HAVE_SIGWAIT
331         result = handle_signal(SIGTERM, SIG_DFL);
332         if (result != ISC_R_SUCCESS)
333                 return (result);
334         result = handle_signal(SIGINT, SIG_DFL);
335         if (result != ISC_R_SUCCESS)
336                 return (result);
337 #endif
338
339 #ifdef ISC_PLATFORM_USETHREADS
340         /*
341          * Block SIGHUP, SIGINT, SIGTERM.
342          *
343          * If isc_app_start() is called from the main thread before any other
344          * threads have been created, then the pthread_sigmask() call below
345          * will result in all threads having SIGHUP, SIGINT and SIGTERM
346          * blocked by default, ensuring that only the thread that calls
347          * sigwait() for them will get those signals.
348          */
349         if (sigemptyset(&sset) != 0 ||
350             sigaddset(&sset, SIGHUP) != 0 ||
351             sigaddset(&sset, SIGINT) != 0 ||
352             sigaddset(&sset, SIGTERM) != 0) {
353                 isc__strerror(errno, strbuf, sizeof(strbuf));
354                 UNEXPECTED_ERROR(__FILE__, __LINE__,
355                                  "isc_app_start() sigsetops: %s", strbuf);
356                 return (ISC_R_UNEXPECTED);
357         }
358         presult = pthread_sigmask(SIG_BLOCK, &sset, NULL);
359         if (presult != 0) {
360                 isc__strerror(presult, strbuf, sizeof(strbuf));
361                 UNEXPECTED_ERROR(__FILE__, __LINE__,
362                                  "isc_app_start() pthread_sigmask: %s",
363                                  strbuf);
364                 return (ISC_R_UNEXPECTED);
365         }
366 #else /* ISC_PLATFORM_USETHREADS */
367         /*
368          * Unblock SIGHUP, SIGINT, SIGTERM.
369          *
370          * If we're not using threads, we need to make sure that SIGHUP,
371          * SIGINT and SIGTERM are not inherited as blocked from the parent
372          * process.
373          */
374         if (sigemptyset(&sset) != 0 ||
375             sigaddset(&sset, SIGHUP) != 0 ||
376             sigaddset(&sset, SIGINT) != 0 ||
377             sigaddset(&sset, SIGTERM) != 0) {
378                 isc__strerror(errno, strbuf, sizeof(strbuf));
379                 UNEXPECTED_ERROR(__FILE__, __LINE__,
380                                  "isc_app_start() sigsetops: %s", strbuf);
381                 return (ISC_R_UNEXPECTED);
382         }
383         presult = sigprocmask(SIG_UNBLOCK, &sset, NULL);
384         if (presult != 0) {
385                 isc__strerror(errno, strbuf, sizeof(strbuf));
386                 UNEXPECTED_ERROR(__FILE__, __LINE__,
387                                  "isc_app_start() sigprocmask: %s", strbuf);
388                 return (ISC_R_UNEXPECTED);
389         }
390 #endif /* ISC_PLATFORM_USETHREADS */
391
392         return (ISC_R_SUCCESS);
393 }
394
395 ISC_APPFUNC_SCOPE isc_result_t
396 isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
397               void *arg)
398 {
399         return (isc__app_ctxonrun((isc_appctx_t *)&isc_g_appctx, mctx,
400                                   task, action, arg));
401 }
402
403 isc_result_t
404 isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
405                   isc_taskaction_t action, void *arg)
406 {
407         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
408         isc_event_t *event;
409         isc_task_t *cloned_task = NULL;
410         isc_result_t result;
411
412         LOCK(&ctx->lock);
413
414         if (ctx->running) {
415                 result = ISC_R_ALREADYRUNNING;
416                 goto unlock;
417         }
418
419         /*
420          * Note that we store the task to which we're going to send the event
421          * in the event's "sender" field.
422          */
423         isc_task_attach(task, &cloned_task);
424         event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
425                                    action, arg, sizeof(*event));
426         if (event == NULL) {
427                 result = ISC_R_NOMEMORY;
428                 goto unlock;
429         }
430
431         ISC_LIST_APPEND(ctx->on_run, event, ev_link);
432
433         result = ISC_R_SUCCESS;
434
435  unlock:
436         UNLOCK(&ctx->lock);
437
438         return (result);
439 }
440
441 #ifndef USE_THREADS_SINGLECTX
442 /*!
443  * Event loop for nonthreaded programs.
444  */
445 static isc_result_t
446 evloop(isc__appctx_t *ctx) {
447         isc_result_t result;
448
449         while (!ctx->want_shutdown) {
450                 int n;
451                 isc_time_t when, now;
452                 struct timeval tv, *tvp;
453                 isc_socketwait_t *swait;
454                 isc_boolean_t readytasks;
455                 isc_boolean_t call_timer_dispatch = ISC_FALSE;
456
457                 /*
458                  * Check the reload (or suspend) case first for exiting the
459                  * loop as fast as possible in case:
460                  *   - the direct call to isc__taskmgr_dispatch() in
461                  *     isc__app_ctxrun() completes all the tasks so far,
462                  *   - there is thus currently no active task, and
463                  *   - there is a timer event
464                  */
465                 if (ctx->want_reload) {
466                         ctx->want_reload = ISC_FALSE;
467                         return (ISC_R_RELOAD);
468                 }
469
470                 readytasks = isc__taskmgr_ready(ctx->taskmgr);
471                 if (readytasks) {
472                         tv.tv_sec = 0;
473                         tv.tv_usec = 0;
474                         tvp = &tv;
475                         call_timer_dispatch = ISC_TRUE;
476                 } else {
477                         result = isc__timermgr_nextevent(ctx->timermgr, &when);
478                         if (result != ISC_R_SUCCESS)
479                                 tvp = NULL;
480                         else {
481                                 isc_uint64_t us;
482
483                                 TIME_NOW(&now);
484                                 us = isc_time_microdiff(&when, &now);
485                                 if (us == 0)
486                                         call_timer_dispatch = ISC_TRUE;
487                                 tv.tv_sec = us / 1000000;
488                                 tv.tv_usec = us % 1000000;
489                                 tvp = &tv;
490                         }
491                 }
492
493                 swait = NULL;
494                 n = isc__socketmgr_waitevents(ctx->socketmgr, tvp, &swait);
495
496                 if (n == 0 || call_timer_dispatch) {
497                         /*
498                          * We call isc__timermgr_dispatch() only when
499                          * necessary, in order to reduce overhead.  If the
500                          * select() call indicates a timeout, we need the
501                          * dispatch.  Even if not, if we set the 0-timeout
502                          * for the select() call, we need to check the timer
503                          * events.  In the 'readytasks' case, there may be no
504                          * timeout event actually, but there is no other way
505                          * to reduce the overhead.
506                          * Note that we do not have to worry about the case
507                          * where a new timer is inserted during the select()
508                          * call, since this loop only runs in the non-thread
509                          * mode.
510                          */
511                         isc__timermgr_dispatch(ctx->timermgr);
512                 }
513                 if (n > 0)
514                         (void)isc__socketmgr_dispatch(ctx->socketmgr, swait);
515                 (void)isc__taskmgr_dispatch(ctx->taskmgr);
516         }
517         return (ISC_R_SUCCESS);
518 }
519 #endif  /* USE_THREADS_SINGLECTX */
520
521 #ifndef ISC_PLATFORM_USETHREADS
522 /*
523  * This is a gross hack to support waiting for condition
524  * variables in nonthreaded programs in a limited way;
525  * see lib/isc/nothreads/include/isc/condition.h.
526  * We implement isc_condition_wait() by entering the
527  * event loop recursively until the want_shutdown flag
528  * is set by isc_condition_signal().
529  */
530
531 /*!
532  * \brief True if we are currently executing in the recursive
533  * event loop.
534  */
535 static isc_boolean_t in_recursive_evloop = ISC_FALSE;
536
537 /*!
538  * \brief True if we are exiting the event loop as the result of
539  * a call to isc_condition_signal() rather than a shutdown
540  * or reload.
541  */
542 static isc_boolean_t signalled = ISC_FALSE;
543
544 isc_result_t
545 isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) {
546         isc_result_t result;
547
548         UNUSED(cp);
549         UNUSED(mp);
550
551         INSIST(!in_recursive_evloop);
552         in_recursive_evloop = ISC_TRUE;
553
554         INSIST(*mp == 1); /* Mutex must be locked on entry. */
555         --*mp;
556
557         result = evloop(&isc_g_appctx);
558         if (result == ISC_R_RELOAD)
559                 isc_g_appctx.want_reload = ISC_TRUE;
560         if (signalled) {
561                 isc_g_appctx.want_shutdown = ISC_FALSE;
562                 signalled = ISC_FALSE;
563         }
564
565         ++*mp;
566         in_recursive_evloop = ISC_FALSE;
567         return (ISC_R_SUCCESS);
568 }
569
570 isc_result_t
571 isc__nothread_signal_hack(isc_condition_t *cp) {
572
573         UNUSED(cp);
574
575         INSIST(in_recursive_evloop);
576
577         isc_g_appctx.want_shutdown = ISC_TRUE;
578         signalled = ISC_TRUE;
579         return (ISC_R_SUCCESS);
580 }
581
582 #endif /* ISC_PLATFORM_USETHREADS */
583
584 ISC_APPFUNC_SCOPE isc_result_t
585 isc__app_ctxrun(isc_appctx_t *ctx0) {
586         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
587         int result;
588         isc_event_t *event, *next_event;
589         isc_task_t *task;
590 #ifdef USE_THREADS_SINGLECTX
591         sigset_t sset;
592         char strbuf[ISC_STRERRORSIZE];
593 #ifdef HAVE_SIGWAIT
594         int sig;
595 #endif
596 #endif /* USE_THREADS_SINGLECTX */
597
598         REQUIRE(VALID_APPCTX(ctx));
599
600 #ifdef HAVE_LINUXTHREADS
601         REQUIRE(main_thread == pthread_self());
602 #endif
603
604         LOCK(&ctx->lock);
605
606         if (!ctx->running) {
607                 ctx->running = ISC_TRUE;
608
609                 /*
610                  * Post any on-run events (in FIFO order).
611                  */
612                 for (event = ISC_LIST_HEAD(ctx->on_run);
613                      event != NULL;
614                      event = next_event) {
615                         next_event = ISC_LIST_NEXT(event, ev_link);
616                         ISC_LIST_UNLINK(ctx->on_run, event, ev_link);
617                         task = event->ev_sender;
618                         event->ev_sender = NULL;
619                         isc_task_sendanddetach(&task, &event);
620                 }
621
622         }
623
624         UNLOCK(&ctx->lock);
625
626 #ifndef HAVE_SIGWAIT
627         /*
628          * Catch SIGHUP.
629          *
630          * We do this here to ensure that the signal handler is installed
631          * (i.e. that it wasn't a "one-shot" handler).
632          */
633         if (ctx == &isc_g_appctx) {
634                 result = handle_signal(SIGHUP, reload_action);
635                 if (result != ISC_R_SUCCESS)
636                         return (ISC_R_SUCCESS);
637         }
638 #endif
639
640 #ifdef USE_THREADS_SINGLECTX
641         /*
642          * When we are using multiple contexts, we don't rely on signals.
643          */
644         if (ctx != &isc_g_appctx)
645                 return (ISC_R_SUCCESS);
646
647         /*
648          * There is no danger if isc_app_shutdown() is called before we wait
649          * for signals.  Signals are blocked, so any such signal will simply
650          * be made pending and we will get it when we call sigwait().
651          */
652
653         while (!ctx->want_shutdown) {
654 #ifdef HAVE_SIGWAIT
655                 /*
656                  * Wait for SIGHUP, SIGINT, or SIGTERM.
657                  */
658                 if (sigemptyset(&sset) != 0 ||
659                     sigaddset(&sset, SIGHUP) != 0 ||
660                     sigaddset(&sset, SIGINT) != 0 ||
661                     sigaddset(&sset, SIGTERM) != 0) {
662                         isc__strerror(errno, strbuf, sizeof(strbuf));
663                         UNEXPECTED_ERROR(__FILE__, __LINE__,
664                                          "isc_app_run() sigsetops: %s", strbuf);
665                         return (ISC_R_UNEXPECTED);
666                 }
667
668 #ifndef HAVE_UNIXWARE_SIGWAIT
669                 result = sigwait(&sset, &sig);
670                 if (result == 0) {
671                         if (sig == SIGINT || sig == SIGTERM)
672                                 ctx->want_shutdown = ISC_TRUE;
673                         else if (sig == SIGHUP)
674                                 ctx->want_reload = ISC_TRUE;
675                 }
676
677 #else /* Using UnixWare sigwait semantics. */
678                 sig = sigwait(&sset);
679                 if (sig >= 0) {
680                         if (sig == SIGINT || sig == SIGTERM)
681                                 ctx->want_shutdown = ISC_TRUE;
682                         else if (sig == SIGHUP)
683                                 ctx->want_reload = ISC_TRUE;
684                 }
685
686 #endif /* HAVE_UNIXWARE_SIGWAIT */
687 #else  /* Don't have sigwait(). */
688                 /*
689                  * Listen for all signals.
690                  */
691                 if (sigemptyset(&sset) != 0) {
692                         isc__strerror(errno, strbuf, sizeof(strbuf));
693                         UNEXPECTED_ERROR(__FILE__, __LINE__,
694                                          "isc_app_run() sigsetops: %s",
695                                          strbuf);
696                         return (ISC_R_UNEXPECTED);
697                 }
698 #ifdef HAVE_GPERFTOOLS_PROFILER
699                 if (sigaddset(&sset, SIGALRM) != 0) {
700                         isc__strerror(errno, strbuf, sizeof(strbuf));
701                         UNEXPECTED_ERROR(__FILE__, __LINE__,
702                                          "isc_app_run() sigsetops: %s",
703                                          strbuf);
704                         return (ISC_R_UNEXPECTED);
705                 }
706 #endif
707                 (void)sigsuspend(&sset);
708 #endif /* HAVE_SIGWAIT */
709
710                 if (ctx->want_reload) {
711                         ctx->want_reload = ISC_FALSE;
712                         return (ISC_R_RELOAD);
713                 }
714
715                 if (ctx->want_shutdown && ctx->blocked)
716                         exit(1);
717         }
718
719 #else /* USE_THREADS_SINGLECTX */
720
721         (void)isc__taskmgr_dispatch(ctx->taskmgr);
722
723         result = evloop(ctx);
724         if (result != ISC_R_SUCCESS)
725                 return (result);
726
727 #endif /* USE_THREADS_SINGLECTX */
728
729         return (ISC_R_SUCCESS);
730 }
731
732 ISC_APPFUNC_SCOPE isc_result_t
733 isc__app_run(void) {
734         isc_result_t result;
735
736         is_running = ISC_TRUE;
737         result = isc__app_ctxrun((isc_appctx_t *)&isc_g_appctx);
738         is_running = ISC_FALSE;
739
740         return (result);
741 }
742
743 ISC_APPFUNC_SCOPE isc_boolean_t
744 isc__app_isrunning(void) {
745         return (is_running);
746 }
747
748 ISC_APPFUNC_SCOPE isc_result_t
749 isc__app_ctxshutdown(isc_appctx_t *ctx0) {
750         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
751         isc_boolean_t want_kill = ISC_TRUE;
752         char strbuf[ISC_STRERRORSIZE];
753
754         REQUIRE(VALID_APPCTX(ctx));
755
756         LOCK(&ctx->lock);
757
758         REQUIRE(ctx->running);
759
760         if (ctx->shutdown_requested)
761                 want_kill = ISC_FALSE;
762         else
763                 ctx->shutdown_requested = ISC_TRUE;
764
765         UNLOCK(&ctx->lock);
766
767         if (want_kill) {
768                 if (ctx != &isc_g_appctx)
769                         ctx->want_shutdown = ISC_TRUE;
770                 else {
771 #ifdef HAVE_LINUXTHREADS
772                         int result;
773
774                         result = pthread_kill(main_thread, SIGTERM);
775                         if (result != 0) {
776                                 isc__strerror(result, strbuf, sizeof(strbuf));
777                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
778                                                  "isc_app_shutdown() "
779                                                  "pthread_kill: %s",
780                                                  strbuf);
781                                 return (ISC_R_UNEXPECTED);
782                         }
783 #else
784                         if (kill(getpid(), SIGTERM) < 0) {
785                                 isc__strerror(errno, strbuf, sizeof(strbuf));
786                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
787                                                  "isc_app_shutdown() "
788                                                  "kill: %s", strbuf);
789                                 return (ISC_R_UNEXPECTED);
790                         }
791 #endif  /* HAVE_LINUXTHREADS */
792                 }
793         }
794
795         return (ISC_R_SUCCESS);
796 }
797
798 ISC_APPFUNC_SCOPE isc_result_t
799 isc__app_shutdown(void) {
800         return (isc__app_ctxshutdown((isc_appctx_t *)&isc_g_appctx));
801 }
802
803 ISC_APPFUNC_SCOPE isc_result_t
804 isc__app_ctxsuspend(isc_appctx_t *ctx0) {
805         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
806         isc_boolean_t want_kill = ISC_TRUE;
807         char strbuf[ISC_STRERRORSIZE];
808
809         REQUIRE(VALID_APPCTX(ctx));
810
811         LOCK(&ctx->lock);
812
813         REQUIRE(ctx->running);
814
815         /*
816          * Don't send the reload signal if we're shutting down.
817          */
818         if (ctx->shutdown_requested)
819                 want_kill = ISC_FALSE;
820
821         UNLOCK(&ctx->lock);
822
823         if (want_kill) {
824                 if (ctx != &isc_g_appctx)
825                         ctx->want_reload = ISC_TRUE;
826                 else {
827 #ifdef HAVE_LINUXTHREADS
828                         int result;
829
830                         result = pthread_kill(main_thread, SIGHUP);
831                         if (result != 0) {
832                                 isc__strerror(result, strbuf, sizeof(strbuf));
833                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
834                                                  "isc_app_reload() "
835                                                  "pthread_kill: %s",
836                                                  strbuf);
837                                 return (ISC_R_UNEXPECTED);
838                         }
839 #else
840                         if (kill(getpid(), SIGHUP) < 0) {
841                                 isc__strerror(errno, strbuf, sizeof(strbuf));
842                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
843                                                  "isc_app_reload() "
844                                                  "kill: %s", strbuf);
845                                 return (ISC_R_UNEXPECTED);
846                         }
847 #endif
848                 }
849         }
850
851         return (ISC_R_SUCCESS);
852 }
853
854 ISC_APPFUNC_SCOPE isc_result_t
855 isc__app_reload(void) {
856         return (isc__app_ctxsuspend((isc_appctx_t *)&isc_g_appctx));
857 }
858
859 ISC_APPFUNC_SCOPE void
860 isc__app_ctxfinish(isc_appctx_t *ctx0) {
861         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
862
863         REQUIRE(VALID_APPCTX(ctx));
864
865         DESTROYLOCK(&ctx->lock);
866 }
867
868 ISC_APPFUNC_SCOPE void
869 isc__app_finish(void) {
870         isc__app_ctxfinish((isc_appctx_t *)&isc_g_appctx);
871 }
872
873 ISC_APPFUNC_SCOPE void
874 isc__app_block(void) {
875 #ifdef ISC_PLATFORM_USETHREADS
876         sigset_t sset;
877 #endif /* ISC_PLATFORM_USETHREADS */
878         REQUIRE(isc_g_appctx.running);
879         REQUIRE(!isc_g_appctx.blocked);
880
881         isc_g_appctx.blocked = ISC_TRUE;
882 #ifdef ISC_PLATFORM_USETHREADS
883         blockedthread = pthread_self();
884         RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
885                       sigaddset(&sset, SIGINT) == 0 &&
886                       sigaddset(&sset, SIGTERM) == 0);
887         RUNTIME_CHECK(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) == 0);
888 #endif /* ISC_PLATFORM_USETHREADS */
889 }
890
891 ISC_APPFUNC_SCOPE void
892 isc__app_unblock(void) {
893 #ifdef ISC_PLATFORM_USETHREADS
894         sigset_t sset;
895 #endif /* ISC_PLATFORM_USETHREADS */
896
897         REQUIRE(isc_g_appctx.running);
898         REQUIRE(isc_g_appctx.blocked);
899
900         isc_g_appctx.blocked = ISC_FALSE;
901
902 #ifdef ISC_PLATFORM_USETHREADS
903         REQUIRE(blockedthread == pthread_self());
904
905         RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
906                       sigaddset(&sset, SIGINT) == 0 &&
907                       sigaddset(&sset, SIGTERM) == 0);
908         RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
909 #endif /* ISC_PLATFORM_USETHREADS */
910 }
911
912 ISC_APPFUNC_SCOPE isc_result_t
913 isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) {
914         isc__appctx_t *ctx;
915
916         REQUIRE(mctx != NULL);
917         REQUIRE(ctxp != NULL && *ctxp == NULL);
918
919         ctx = isc_mem_get(mctx, sizeof(*ctx));
920         if (ctx == NULL)
921                 return (ISC_R_NOMEMORY);
922
923         ctx->common.impmagic = APPCTX_MAGIC;
924         ctx->common.magic = ISCAPI_APPCTX_MAGIC;
925         ctx->common.methods = &appmethods.methods;
926
927         ctx->mctx = NULL;
928         isc_mem_attach(mctx, &ctx->mctx);
929
930         ctx->taskmgr = NULL;
931         ctx->socketmgr = NULL;
932         ctx->timermgr = NULL;
933
934         *ctxp = (isc_appctx_t *)ctx;
935
936         return (ISC_R_SUCCESS);
937 }
938
939 ISC_APPFUNC_SCOPE void
940 isc__appctx_destroy(isc_appctx_t **ctxp) {
941         isc__appctx_t *ctx;
942
943         REQUIRE(ctxp != NULL);
944         ctx = (isc__appctx_t *)*ctxp;
945         REQUIRE(VALID_APPCTX(ctx));
946
947         isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx));
948
949         *ctxp = NULL;
950 }
951
952 ISC_APPFUNC_SCOPE void
953 isc__appctx_settaskmgr(isc_appctx_t *ctx0, isc_taskmgr_t *taskmgr) {
954         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
955
956         REQUIRE(VALID_APPCTX(ctx));
957
958         ctx->taskmgr = taskmgr;
959 }
960
961 ISC_APPFUNC_SCOPE void
962 isc__appctx_setsocketmgr(isc_appctx_t *ctx0, isc_socketmgr_t *socketmgr) {
963         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
964
965         REQUIRE(VALID_APPCTX(ctx));
966
967         ctx->socketmgr = socketmgr;
968 }
969
970 ISC_APPFUNC_SCOPE void
971 isc__appctx_settimermgr(isc_appctx_t *ctx0, isc_timermgr_t *timermgr) {
972         isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
973
974         REQUIRE(VALID_APPCTX(ctx));
975
976         ctx->timermgr = timermgr;
977 }
978
979 #ifdef USE_APPIMPREGISTER
980 isc_result_t
981 isc__app_register(void) {
982         return (isc_app_register(isc__appctx_create));
983 }
984 #endif