xref: /netbsd/external/bsd/ntp/dist/lib/isc/win32/app.c (revision 6550d01e)
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