1 /* $NetBSD: app.c,v 1.6 2014/12/10 04:38:01 christos Exp $ */
4 * Copyright (C) 2004, 2007, 2009, 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: app.c,v 1.9 2009/09/02 23:48:03 tbox Exp */
24 #include <sys/types.h>
33 #include <isc/boolean.h>
34 #include <isc/condition.h>
37 #include <isc/mutex.h>
38 #include <isc/event.h>
39 #include <isc/platform.h>
40 #include <isc/string.h>
44 #include <isc/thread.h>
47 * For BIND9 internal applications built with threads, we use a single app
48 * context and let multiple worker, I/O, timer threads do actual jobs.
51 static isc_thread_t blockedthread
;
54 * The following are intended for internal use (indicated by "isc__"
55 * prefix) but are not declared as static, allowing direct access from
58 isc_result_t
isc__app_start(void);
59 isc_result_t
isc__app_ctxstart(isc_appctx_t
*ctx
);
60 isc_result_t
isc__app_onrun(isc_mem_t
*mctx
, isc_task_t
*task
,
61 isc_taskaction_t action
, void *arg
);
62 isc_result_t
isc__app_ctxrun(isc_appctx_t
*ctx
);
63 isc_result_t
isc__app_run(void);
64 isc_result_t
isc__app_ctxshutdown(isc_appctx_t
*ctx
);
65 isc_result_t
isc__app_shutdown(void);
66 isc_result_t
isc__app_reload(void);
67 isc_result_t
isc__app_ctxsuspend(isc_appctx_t
*ctx
);
68 void isc__app_ctxfinish(isc_appctx_t
*ctx
);
69 void isc__app_finish(void);
70 void isc__app_block(void);
71 void isc__app_unblock(void);
72 isc_result_t
isc__appctx_create(isc_mem_t
*mctx
, isc_appctx_t
**ctxp
);
73 void isc__appctx_destroy(isc_appctx_t
**ctxp
);
74 void isc__appctx_settaskmgr(isc_appctx_t
*ctx
, isc_taskmgr_t
*taskmgr
);
75 void isc__appctx_setsocketmgr(isc_appctx_t
*ctx
, isc_socketmgr_t
*socketmgr
);
76 void isc__appctx_settimermgr(isc_appctx_t
*ctx
, isc_timermgr_t
*timermgr
);
77 isc_result_t
isc__app_ctxonrun(isc_appctx_t
*ctx
, isc_mem_t
*mctx
,
78 isc_task_t
*task
, isc_taskaction_t action
,
82 * The application context of this module. This implementation actually
83 * doesn't use it. (This may change in the future).
85 #define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x')
86 #define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC)
88 /* Events to wait for */
97 typedef struct isc__appctx
{
100 isc_eventlist_t on_run
;
102 isc_boolean_t shutdown_requested
;
103 isc_boolean_t running
;
105 * We assume that 'want_shutdown' can be read and written atomically.
107 isc_boolean_t want_shutdown
;
109 * We assume that 'want_reload' can be read and written atomically.
111 isc_boolean_t want_reload
;
113 isc_boolean_t blocked
;
115 HANDLE hEvents
[NUM_EVENTS
];
117 isc_taskmgr_t
*taskmgr
;
118 isc_socketmgr_t
*socketmgr
;
119 isc_timermgr_t
*timermgr
;
122 static isc__appctx_t isc_g_appctx
;
125 isc_appmethods_t methods
;
128 * The following are defined just for avoiding unused static functions.
130 void *run
, *shutdown
, *start
, *reload
, *finish
, *block
, *unblock
;
137 isc__app_ctxshutdown
,
139 isc__appctx_settaskmgr
,
140 isc__appctx_setsocketmgr
,
141 isc__appctx_settimermgr
,
144 (void *)isc__app_run
,
145 (void *)isc__app_shutdown
,
146 (void *)isc__app_start
,
147 (void *)isc__app_reload
,
148 (void *)isc__app_finish
,
149 (void *)isc__app_block
,
150 (void *)isc__app_unblock
154 * We need to remember which thread is the main thread...
156 static isc_thread_t main_thread
;
159 isc__app_ctxstart(isc_appctx_t
*ctx0
) {
160 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
163 REQUIRE(VALID_APPCTX(ctx
));
166 * Start an ISC library application.
169 main_thread
= GetCurrentThread();
171 result
= isc_mutex_init(&ctx
->lock
);
172 if (result
!= ISC_R_SUCCESS
)
175 ctx
->shutdown_requested
= ISC_FALSE
;
176 ctx
->running
= ISC_FALSE
;
177 ctx
->want_shutdown
= ISC_FALSE
;
178 ctx
->want_reload
= ISC_FALSE
;
179 ctx
->blocked
= ISC_FALSE
;
181 /* Create the reload event in a non-signaled state */
182 ctx
->hEvents
[RELOAD_EVENT
] = CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
184 /* Create the shutdown event in a non-signaled state */
185 ctx
->hEvents
[SHUTDOWN_EVENT
] = CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
187 ISC_LIST_INIT(ctx
->on_run
);
188 return (ISC_R_SUCCESS
);
192 isc__app_start(void) {
193 isc_g_appctx
.common
.impmagic
= APPCTX_MAGIC
;
194 isc_g_appctx
.common
.magic
= ISCAPI_APPCTX_MAGIC
;
195 isc_g_appctx
.common
.methods
= &appmethods
.methods
;
196 isc_g_appctx
.mctx
= NULL
;
197 /* The remaining members will be initialized in ctxstart() */
199 return (isc__app_ctxstart((isc_appctx_t
*)&isc_g_appctx
));
203 isc__app_onrun(isc_mem_t
*mctx
, isc_task_t
*task
, isc_taskaction_t action
,
206 return (isc__app_ctxonrun((isc_appctx_t
*)&isc_g_appctx
, mctx
,
211 isc__app_ctxonrun(isc_appctx_t
*ctx0
, isc_mem_t
*mctx
, isc_task_t
*task
,
212 isc_taskaction_t action
, void *arg
)
214 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
216 isc_task_t
*cloned_task
= NULL
;
222 result
= ISC_R_ALREADYRUNNING
;
227 * Note that we store the task to which we're going to send the event
228 * in the event's "sender" field.
230 isc_task_attach(task
, &cloned_task
);
231 event
= isc_event_allocate(mctx
, cloned_task
, ISC_APPEVENT_SHUTDOWN
,
232 action
, arg
, sizeof(*event
));
234 result
= ISC_R_NOMEMORY
;
238 ISC_LIST_APPEND(ctx
->on_run
, event
, ev_link
);
240 result
= ISC_R_SUCCESS
;
249 isc__app_ctxrun(isc_appctx_t
*ctx0
) {
250 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
251 isc_event_t
*event
, *next_event
;
253 HANDLE
*pHandles
= NULL
;
256 REQUIRE(VALID_APPCTX(ctx
));
258 REQUIRE(main_thread
== GetCurrentThread());
263 ctx
->running
= ISC_TRUE
;
266 * Post any on-run events (in FIFO order).
268 for (event
= ISC_LIST_HEAD(ctx
->on_run
);
270 event
= next_event
) {
271 next_event
= ISC_LIST_NEXT(event
, ev_link
);
272 ISC_LIST_UNLINK(ctx
->on_run
, event
, ev_link
);
273 task
= event
->ev_sender
;
274 event
->ev_sender
= NULL
;
275 isc_task_sendanddetach(&task
, &event
);
283 * There is no danger if isc_app_shutdown() is called before we wait
287 while (!ctx
->want_shutdown
) {
288 dwWaitResult
= WaitForMultipleObjects(NUM_EVENTS
, ctx
->hEvents
,
291 /* See why we returned */
293 if (WaitSucceeded(dwWaitResult
, NUM_EVENTS
)) {
295 * The return was due to one of the events
298 switch (WaitSucceededIndex(dwWaitResult
)) {
300 ctx
->want_reload
= ISC_TRUE
;
304 ctx
->want_shutdown
= ISC_TRUE
;
309 if (ctx
->want_reload
) {
310 ctx
->want_reload
= ISC_FALSE
;
311 return (ISC_R_RELOAD
);
314 if (ctx
->want_shutdown
&& ctx
->blocked
)
318 return (ISC_R_SUCCESS
);
323 return (isc__app_ctxrun((isc_appctx_t
*)&isc_g_appctx
));
327 isc__app_ctxshutdown(isc_appctx_t
*ctx0
) {
328 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
329 isc_boolean_t want_kill
= ISC_TRUE
;
331 REQUIRE(VALID_APPCTX(ctx
));
335 REQUIRE(ctx
->running
);
337 if (ctx
->shutdown_requested
)
338 want_kill
= ISC_FALSE
; /* We're only signaling once */
340 ctx
->shutdown_requested
= ISC_TRUE
;
345 SetEvent(ctx
->hEvents
[SHUTDOWN_EVENT
]);
347 return (ISC_R_SUCCESS
);
351 isc__app_shutdown(void) {
352 return (isc__app_ctxshutdown((isc_appctx_t
*)&isc_g_appctx
));
356 isc__app_ctxsuspend(isc_appctx_t
*ctx0
) {
357 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
358 isc_boolean_t want_kill
= ISC_TRUE
;
360 REQUIRE(VALID_APPCTX(ctx
));
364 REQUIRE(ctx
->running
);
367 * Don't send the reload signal if we're shutting down.
369 if (ctx
->shutdown_requested
)
370 want_kill
= ISC_FALSE
;
375 SetEvent(ctx
->hEvents
[RELOAD_EVENT
]);
377 return (ISC_R_SUCCESS
);
381 isc__app_reload(void) {
382 return (isc__app_ctxsuspend((isc_appctx_t
*)&isc_g_appctx
));
386 isc__app_ctxfinish(isc_appctx_t
*ctx0
) {
387 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
389 REQUIRE(VALID_APPCTX(ctx
));
391 DESTROYLOCK(&ctx
->lock
);
395 isc__app_finish(void) {
396 isc__app_ctxfinish((isc_appctx_t
*)&isc_g_appctx
);
400 isc__app_block(void) {
401 REQUIRE(isc_g_appctx
.running
);
402 REQUIRE(!isc_g_appctx
.blocked
);
404 isc_g_appctx
.blocked
= ISC_TRUE
;
405 blockedthread
= GetCurrentThread();
409 isc__app_unblock(void) {
410 REQUIRE(isc_g_appctx
.running
);
411 REQUIRE(isc_g_appctx
.blocked
);
413 isc_g_appctx
.blocked
= ISC_FALSE
;
414 REQUIRE(blockedthread
== GetCurrentThread());
418 isc__appctx_create(isc_mem_t
*mctx
, isc_appctx_t
**ctxp
) {
421 REQUIRE(mctx
!= NULL
);
422 REQUIRE(ctxp
!= NULL
&& *ctxp
== NULL
);
424 ctx
= isc_mem_get(mctx
, sizeof(*ctx
));
426 return (ISC_R_NOMEMORY
);
428 ctx
->common
.impmagic
= APPCTX_MAGIC
;
429 ctx
->common
.magic
= ISCAPI_APPCTX_MAGIC
;
430 ctx
->common
.methods
= &appmethods
.methods
;
433 isc_mem_attach(mctx
, &ctx
->mctx
);
436 ctx
->socketmgr
= NULL
;
437 ctx
->timermgr
= NULL
;
439 *ctxp
= (isc_appctx_t
*)ctx
;
441 return (ISC_R_SUCCESS
);
445 isc__appctx_destroy(isc_appctx_t
**ctxp
) {
448 REQUIRE(ctxp
!= NULL
);
449 ctx
= (isc__appctx_t
*)*ctxp
;
450 REQUIRE(VALID_APPCTX(ctx
));
452 isc_mem_putanddetach(&ctx
->mctx
, ctx
, sizeof(*ctx
));
458 isc__appctx_settaskmgr(isc_appctx_t
*ctx0
, isc_taskmgr_t
*taskmgr
) {
459 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
461 REQUIRE(VALID_APPCTX(ctx
));
463 ctx
->taskmgr
= taskmgr
;
467 isc__appctx_setsocketmgr(isc_appctx_t
*ctx0
, isc_socketmgr_t
*socketmgr
) {
468 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
470 REQUIRE(VALID_APPCTX(ctx
));
472 ctx
->socketmgr
= socketmgr
;
476 isc__appctx_settimermgr(isc_appctx_t
*ctx0
, isc_timermgr_t
*timermgr
) {
477 isc__appctx_t
*ctx
= (isc__appctx_t
*)ctx0
;
479 REQUIRE(VALID_APPCTX(ctx
));
481 ctx
->timermgr
= timermgr
;
485 isc__app_register(void) {
486 return (isc_app_register(isc__appctx_create
));
489 #include "../app_api.c"