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