1 /* $NetBSD: app.c,v 1.1.1.1 2009/12/13 16:54:41 kardel Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2001 Internet Software Consortium. 6 * 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. 10 * 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. 18 */ 19 20 /* Id: app.c,v 1.7 2007/06/19 23:47:19 tbox Exp */ 21 22 #include <config.h> 23 24 #include <sys/types.h> 25 26 #include <stddef.h> 27 #include <stdlib.h> 28 #include <errno.h> 29 #include <unistd.h> 30 #include <process.h> 31 32 #include <isc/app.h> 33 #include <isc/boolean.h> 34 #include <isc/condition.h> 35 #include <isc/msgs.h> 36 #include <isc/mutex.h> 37 #include <isc/event.h> 38 #include <isc/platform.h> 39 #include <isc/string.h> 40 #include <isc/task.h> 41 #include <isc/time.h> 42 #include <isc/util.h> 43 #include <isc/thread.h> 44 45 static isc_eventlist_t on_run; 46 static isc_mutex_t lock; 47 static isc_boolean_t shutdown_requested = ISC_FALSE; 48 static isc_boolean_t running = ISC_FALSE; 49 /* 50 * We assume that 'want_shutdown' can be read and written atomically. 51 */ 52 static isc_boolean_t want_shutdown = ISC_FALSE; 53 /* 54 * We assume that 'want_reload' can be read and written atomically. 55 */ 56 static isc_boolean_t want_reload = ISC_FALSE; 57 58 static isc_boolean_t blocked = ISC_FALSE; 59 60 static isc_thread_t blockedthread; 61 62 /* Events to wait for */ 63 64 #define NUM_EVENTS 2 65 66 enum { 67 RELOAD_EVENT, 68 SHUTDOWN_EVENT 69 }; 70 71 static HANDLE hEvents[NUM_EVENTS]; 72 DWORD dwWaitResult; 73 74 /* 75 * We need to remember which thread is the main thread... 76 */ 77 static isc_thread_t main_thread; 78 79 isc_result_t 80 isc_app_start(void) { 81 isc_result_t result; 82 83 /* 84 * Start an ISC library application. 85 */ 86 87 main_thread = GetCurrentThread(); 88 89 result = isc_mutex_init(&lock); 90 if (result != ISC_R_SUCCESS) 91 return (result); 92 93 /* Create the reload event in a non-signaled state */ 94 hEvents[RELOAD_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL); 95 96 /* Create the shutdown event in a non-signaled state */ 97 hEvents[SHUTDOWN_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL); 98 99 ISC_LIST_INIT(on_run); 100 return (ISC_R_SUCCESS); 101 } 102 103 isc_result_t 104 isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, 105 void *arg) { 106 isc_event_t *event; 107 isc_task_t *cloned_task = NULL; 108 isc_result_t result; 109 110 111 LOCK(&lock); 112 if (running) { 113 result = ISC_R_ALREADYRUNNING; 114 goto unlock; 115 } 116 117 /* 118 * Note that we store the task to which we're going to send the event 119 * in the event's "sender" field. 120 */ 121 isc_task_attach(task, &cloned_task); 122 event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN, 123 action, arg, sizeof(*event)); 124 if (event == NULL) { 125 result = ISC_R_NOMEMORY; 126 goto unlock; 127 } 128 129 ISC_LIST_APPEND(on_run, event, ev_link); 130 result = ISC_R_SUCCESS; 131 132 unlock: 133 UNLOCK(&lock); 134 return (result); 135 } 136 137 isc_result_t 138 isc_app_run(void) { 139 isc_event_t *event, *next_event; 140 isc_task_t *task; 141 HANDLE *pHandles = NULL; 142 143 REQUIRE(main_thread == GetCurrentThread()); 144 LOCK(&lock); 145 if (!running) { 146 running = ISC_TRUE; 147 148 /* 149 * Post any on-run events (in FIFO order). 150 */ 151 for (event = ISC_LIST_HEAD(on_run); 152 event != NULL; 153 event = next_event) { 154 next_event = ISC_LIST_NEXT(event, ev_link); 155 ISC_LIST_UNLINK(on_run, event, ev_link); 156 task = event->ev_sender; 157 event->ev_sender = NULL; 158 isc_task_sendanddetach(&task, &event); 159 } 160 161 } 162 163 UNLOCK(&lock); 164 165 /* 166 * There is no danger if isc_app_shutdown() is called before we wait 167 * for events. 168 */ 169 170 while (!want_shutdown) { 171 dwWaitResult = WaitForMultipleObjects(NUM_EVENTS, hEvents, 172 FALSE, INFINITE); 173 174 /* See why we returned */ 175 176 if (WaitSucceeded(dwWaitResult, NUM_EVENTS)) { 177 /* 178 * The return was due to one of the events 179 * being signaled 180 */ 181 switch (WaitSucceededIndex(dwWaitResult)) { 182 case RELOAD_EVENT: 183 want_reload = ISC_TRUE; 184 break; 185 186 case SHUTDOWN_EVENT: 187 want_shutdown = ISC_TRUE; 188 break; 189 } 190 } 191 if (want_reload) { 192 want_reload = ISC_FALSE; 193 return (ISC_R_RELOAD); 194 } 195 196 if (want_shutdown && blocked) 197 exit(-1); 198 } 199 200 return (ISC_R_SUCCESS); 201 } 202 203 isc_result_t 204 isc_app_shutdown(void) { 205 isc_boolean_t want_kill = ISC_TRUE; 206 207 LOCK(&lock); 208 REQUIRE(running); 209 210 if (shutdown_requested) 211 want_kill = ISC_FALSE; /* We're only signaling once */ 212 else 213 shutdown_requested = ISC_TRUE; 214 215 UNLOCK(&lock); 216 if (want_kill) 217 SetEvent(hEvents[SHUTDOWN_EVENT]); 218 219 return (ISC_R_SUCCESS); 220 } 221 222 isc_result_t 223 isc_app_reload(void) { 224 isc_boolean_t want_reload = ISC_TRUE; 225 226 LOCK(&lock); 227 REQUIRE(running); 228 229 /* 230 * Don't send the reload signal if we're shutting down. 231 */ 232 if (shutdown_requested) 233 want_reload = ISC_FALSE; 234 235 UNLOCK(&lock); 236 if (want_reload) 237 SetEvent(hEvents[RELOAD_EVENT]); 238 239 return (ISC_R_SUCCESS); 240 } 241 242 void 243 isc_app_finish(void) { 244 DESTROYLOCK(&lock); 245 } 246 247 void 248 isc_app_block(void) { 249 REQUIRE(running); 250 REQUIRE(!blocked); 251 252 blocked = ISC_TRUE; 253 blockedthread = GetCurrentThread(); 254 } 255 256 void 257 isc_app_unblock(void) { 258 REQUIRE(running); 259 REQUIRE(blocked); 260 blocked = ISC_FALSE; 261 REQUIRE(blockedthread == GetCurrentThread()); 262 } 263