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