File: | src/usr.bin/dig/lib/isc/task.c |
Warning: | line 496, column 3 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") | ||||
3 | * | ||||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||||
5 | * purpose with or without fee is hereby granted, provided that the above | ||||
6 | * copyright notice and this permission notice appear in all copies. | ||||
7 | * | ||||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH | ||||
9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||||
10 | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, | ||||
11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||||
12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | ||||
13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||||
14 | * PERFORMANCE OF THIS SOFTWARE. | ||||
15 | */ | ||||
16 | |||||
17 | /*! \file | ||||
18 | * \author Principal Author: Bob Halley | ||||
19 | */ | ||||
20 | |||||
21 | /* | ||||
22 | * XXXRTH Need to document the states a task can be in, and the rules | ||||
23 | * for changing states. | ||||
24 | */ | ||||
25 | |||||
26 | #include <stdlib.h> | ||||
27 | #include <string.h> | ||||
28 | #include <time.h> | ||||
29 | |||||
30 | #include <isc/event.h> | ||||
31 | #include <isc/task.h> | ||||
32 | #include <isc/util.h> | ||||
33 | |||||
34 | #include "task_p.h" | ||||
35 | |||||
36 | /*** | ||||
37 | *** Types. | ||||
38 | ***/ | ||||
39 | |||||
40 | typedef enum { | ||||
41 | task_state_idle, task_state_ready, task_state_running, | ||||
42 | task_state_done | ||||
43 | } task_state_t; | ||||
44 | |||||
45 | struct isc_task { | ||||
46 | /* Not locked. */ | ||||
47 | isc_taskmgr_t * manager; | ||||
48 | /* Locked by task lock. */ | ||||
49 | task_state_t state; | ||||
50 | unsigned int references; | ||||
51 | isc_eventlist_t events; | ||||
52 | isc_eventlist_t on_shutdown; | ||||
53 | unsigned int nevents; | ||||
54 | unsigned int quantum; | ||||
55 | unsigned int flags; | ||||
56 | time_t now; | ||||
57 | char name[16]; | ||||
58 | void * tag; | ||||
59 | /* Locked by task manager lock. */ | ||||
60 | LINK(isc_task_t)struct { isc_task_t *prev, *next; } link; | ||||
61 | LINK(isc_task_t)struct { isc_task_t *prev, *next; } ready_link; | ||||
62 | LINK(isc_task_t)struct { isc_task_t *prev, *next; } ready_priority_link; | ||||
63 | }; | ||||
64 | |||||
65 | #define TASK_F_SHUTTINGDOWN0x01 0x01 | ||||
66 | #define TASK_F_PRIVILEGED0x02 0x02 | ||||
67 | |||||
68 | #define TASK_SHUTTINGDOWN(t)(((t)->flags & 0x01) != 0) (((t)->flags & TASK_F_SHUTTINGDOWN0x01) \ | ||||
69 | != 0) | ||||
70 | |||||
71 | typedef ISC_LIST(isc_task_t)struct { isc_task_t *head, *tail; } isc_tasklist_t; | ||||
72 | |||||
73 | struct isc_taskmgr { | ||||
74 | /* Not locked. */ | ||||
75 | /* Locked by task manager lock. */ | ||||
76 | unsigned int default_quantum; | ||||
77 | LIST(isc_task_t)struct { isc_task_t *head, *tail; } tasks; | ||||
78 | isc_tasklist_t ready_tasks; | ||||
79 | isc_tasklist_t ready_priority_tasks; | ||||
80 | isc_taskmgrmode_t mode; | ||||
81 | unsigned int tasks_running; | ||||
82 | unsigned int tasks_ready; | ||||
83 | int pause_requested; | ||||
84 | int exclusive_requested; | ||||
85 | int exiting; | ||||
86 | |||||
87 | /* | ||||
88 | * Multiple threads can read/write 'excl' at the same time, so we need | ||||
89 | * to protect the access. We can't use 'lock' since isc_task_detach() | ||||
90 | * will try to acquire it. | ||||
91 | */ | ||||
92 | isc_task_t *excl; | ||||
93 | unsigned int refs; | ||||
94 | }; | ||||
95 | |||||
96 | #define DEFAULT_TASKMGR_QUANTUM10 10 | ||||
97 | #define DEFAULT_DEFAULT_QUANTUM5 5 | ||||
98 | #define FINISHED(m)((m)->exiting && (((m)->tasks).head == ((void * )0))) ((m)->exiting && EMPTY((m)->tasks)(((m)->tasks).head == ((void *)0))) | ||||
99 | |||||
100 | static isc_taskmgr_t *taskmgr = NULL((void *)0); | ||||
101 | |||||
102 | static inline int | ||||
103 | empty_readyq(isc_taskmgr_t *manager); | ||||
104 | |||||
105 | static inline isc_task_t * | ||||
106 | pop_readyq(isc_taskmgr_t *manager); | ||||
107 | |||||
108 | static inline void | ||||
109 | push_readyq(isc_taskmgr_t *manager, isc_task_t *task); | ||||
110 | |||||
111 | /*** | ||||
112 | *** Tasks. | ||||
113 | ***/ | ||||
114 | |||||
115 | static void | ||||
116 | task_finished(isc_task_t *task) { | ||||
117 | isc_taskmgr_t *manager = task->manager; | ||||
118 | |||||
119 | REQUIRE(EMPTY(task->events))((void) ((((task->events).head == ((void *)0))) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 119, isc_assertiontype_require , "((task->events).head == ((void *)0))"), 0))); | ||||
120 | REQUIRE(task->nevents == 0)((void) ((task->nevents == 0) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 120, isc_assertiontype_require, "task->nevents == 0"), 0 ))); | ||||
121 | REQUIRE(EMPTY(task->on_shutdown))((void) ((((task->on_shutdown).head == ((void *)0))) || (( isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c", 121 , isc_assertiontype_require, "((task->on_shutdown).head == ((void *)0))" ), 0))); | ||||
122 | REQUIRE(task->references == 0)((void) ((task->references == 0) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 122, isc_assertiontype_require , "task->references == 0"), 0))); | ||||
123 | REQUIRE(task->state == task_state_done)((void) ((task->state == task_state_done) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 123, isc_assertiontype_require , "task->state == task_state_done"), 0))); | ||||
124 | |||||
125 | UNLINK(manager->tasks, task, link)do { do { if ((task)->link.next != ((void *)0)) (task)-> link.next->link.prev = (task)->link.prev; else { ((void ) (((manager->tasks).tail == (task)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 125, isc_assertiontype_insist , "(manager->tasks).tail == (task)"), 0))); (manager->tasks ).tail = (task)->link.prev; } if ((task)->link.prev != ( (void *)0)) (task)->link.prev->link.next = (task)->link .next; else { ((void) (((manager->tasks).head == (task)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 125, isc_assertiontype_insist, "(manager->tasks).head == (task)" ), 0))); (manager->tasks).head = (task)->link.next; } ( task)->link.prev = (void *)(-1); (task)->link.next = (void *)(-1); ((void) (((manager->tasks).head != (task)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 125, isc_assertiontype_insist , "(manager->tasks).head != (task)"), 0))); ((void) (((manager ->tasks).tail != (task)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 125, isc_assertiontype_insist, "(manager->tasks).tail != (task)" ), 0))); } while (0); } while (0); | ||||
126 | |||||
127 | free(task); | ||||
128 | } | ||||
129 | |||||
130 | isc_result_t | ||||
131 | isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, | ||||
132 | isc_task_t **taskp) | ||||
133 | { | ||||
134 | isc_task_t *task; | ||||
135 | int exiting; | ||||
136 | |||||
137 | REQUIRE(taskp != NULL && *taskp == NULL)((void) ((taskp != ((void *)0) && *taskp == ((void *) 0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 137, isc_assertiontype_require, "taskp != ((void *)0) && *taskp == ((void *)0)" ), 0))); | ||||
138 | |||||
139 | task = malloc(sizeof(*task)); | ||||
140 | if (task == NULL((void *)0)) | ||||
141 | return (ISC_R_NOMEMORY1); | ||||
142 | task->manager = manager; | ||||
143 | task->state = task_state_idle; | ||||
144 | task->references = 1; | ||||
145 | INIT_LIST(task->events)do { (task->events).head = ((void *)0); (task->events). tail = ((void *)0); } while (0); | ||||
146 | INIT_LIST(task->on_shutdown)do { (task->on_shutdown).head = ((void *)0); (task->on_shutdown ).tail = ((void *)0); } while (0); | ||||
147 | task->nevents = 0; | ||||
148 | task->quantum = quantum; | ||||
149 | task->flags = 0; | ||||
150 | task->now = 0; | ||||
151 | memset(task->name, 0, sizeof(task->name)); | ||||
152 | task->tag = NULL((void *)0); | ||||
153 | INIT_LINK(task, link)do { (task)->link.prev = (void *)(-1); (task)->link.next = (void *)(-1); } while (0); | ||||
154 | INIT_LINK(task, ready_link)do { (task)->ready_link.prev = (void *)(-1); (task)->ready_link .next = (void *)(-1); } while (0); | ||||
155 | INIT_LINK(task, ready_priority_link)do { (task)->ready_priority_link.prev = (void *)(-1); (task )->ready_priority_link.next = (void *)(-1); } while (0); | ||||
156 | |||||
157 | exiting = 0; | ||||
158 | if (!manager->exiting) { | ||||
159 | if (task->quantum == 0) | ||||
160 | task->quantum = manager->default_quantum; | ||||
161 | APPEND(manager->tasks, task, link)do { do { if ((manager->tasks).tail != ((void *)0)) (manager ->tasks).tail->link.next = (task); else (manager->tasks ).head = (task); (task)->link.prev = (manager->tasks).tail ; (task)->link.next = ((void *)0); (manager->tasks).tail = (task); } while (0); } while (0); | ||||
162 | } else | ||||
163 | exiting = 1; | ||||
164 | |||||
165 | if (exiting) { | ||||
166 | free(task); | ||||
167 | return (ISC_R_SHUTTINGDOWN22); | ||||
168 | } | ||||
169 | |||||
170 | *taskp = (isc_task_t *)task; | ||||
171 | return (ISC_R_SUCCESS0); | ||||
172 | } | ||||
173 | |||||
174 | void | ||||
175 | isc_task_attach(isc_task_t *source0, isc_task_t **targetp) { | ||||
176 | isc_task_t *source = (isc_task_t *)source0; | ||||
177 | |||||
178 | /* | ||||
179 | * Attach *targetp to source. | ||||
180 | */ | ||||
181 | |||||
182 | REQUIRE(targetp != NULL && *targetp == NULL)((void) ((targetp != ((void *)0) && *targetp == ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 182, isc_assertiontype_require, "targetp != ((void *)0) && *targetp == ((void *)0)" ), 0))); | ||||
183 | |||||
184 | source->references++; | ||||
185 | |||||
186 | *targetp = (isc_task_t *)source; | ||||
187 | } | ||||
188 | |||||
189 | static inline int | ||||
190 | task_shutdown(isc_task_t *task) { | ||||
191 | int was_idle = 0; | ||||
192 | isc_event_t *event, *prev; | ||||
193 | |||||
194 | /* | ||||
195 | * Caller must be holding the task's lock. | ||||
196 | */ | ||||
197 | |||||
198 | if (! TASK_SHUTTINGDOWN(task)(((task)->flags & 0x01) != 0)) { | ||||
199 | task->flags |= TASK_F_SHUTTINGDOWN0x01; | ||||
200 | if (task->state == task_state_idle) { | ||||
201 | INSIST(EMPTY(task->events))((void) ((((task->events).head == ((void *)0))) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 201, isc_assertiontype_insist , "((task->events).head == ((void *)0))"), 0))); | ||||
202 | task->state = task_state_ready; | ||||
203 | was_idle = 1; | ||||
204 | } | ||||
205 | INSIST(task->state == task_state_ready ||((void) ((task->state == task_state_ready || task->state == task_state_running) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 206, isc_assertiontype_insist, "task->state == task_state_ready || task->state == task_state_running" ), 0))) | ||||
206 | task->state == task_state_running)((void) ((task->state == task_state_ready || task->state == task_state_running) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 206, isc_assertiontype_insist, "task->state == task_state_ready || task->state == task_state_running" ), 0))); | ||||
207 | |||||
208 | /* | ||||
209 | * Note that we post shutdown events LIFO. | ||||
210 | */ | ||||
211 | for (event = TAIL(task->on_shutdown)((task->on_shutdown).tail); | ||||
212 | event != NULL((void *)0); | ||||
213 | event = prev) { | ||||
214 | prev = PREV(event, ev_link)((event)->ev_link.prev); | ||||
215 | DEQUEUE(task->on_shutdown, event, ev_link)do { do { if ((event)->ev_link.next != ((void *)0)) (event )->ev_link.next->ev_link.prev = (event)->ev_link.prev ; else { ((void) (((task->on_shutdown).tail == (event)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 215, isc_assertiontype_insist, "(task->on_shutdown).tail == (event)" ), 0))); (task->on_shutdown).tail = (event)->ev_link.prev ; } if ((event)->ev_link.prev != ((void *)0)) (event)-> ev_link.prev->ev_link.next = (event)->ev_link.next; else { ((void) (((task->on_shutdown).head == (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 215, isc_assertiontype_insist , "(task->on_shutdown).head == (event)"), 0))); (task-> on_shutdown).head = (event)->ev_link.next; } (event)->ev_link .prev = (void *)(-1); (event)->ev_link.next = (void *)(-1) ; ((void) (((task->on_shutdown).head != (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 215, isc_assertiontype_insist , "(task->on_shutdown).head != (event)"), 0))); ((void) (( (task->on_shutdown).tail != (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 215, isc_assertiontype_insist , "(task->on_shutdown).tail != (event)"), 0))); } while (0 ); } while (0); | ||||
216 | ENQUEUE(task->events, event, ev_link)do { do { if ((task->events).tail != ((void *)0)) (task-> events).tail->ev_link.next = (event); else (task->events ).head = (event); (event)->ev_link.prev = (task->events ).tail; (event)->ev_link.next = ((void *)0); (task->events ).tail = (event); } while (0); } while (0); | ||||
217 | task->nevents++; | ||||
218 | } | ||||
219 | } | ||||
220 | |||||
221 | return (was_idle); | ||||
222 | } | ||||
223 | |||||
224 | /* | ||||
225 | * Moves a task onto the appropriate run queue. | ||||
226 | * | ||||
227 | * Caller must NOT hold manager lock. | ||||
228 | */ | ||||
229 | static inline void | ||||
230 | task_ready(isc_task_t *task) { | ||||
231 | isc_taskmgr_t *manager = task->manager; | ||||
232 | |||||
233 | REQUIRE(task->state == task_state_ready)((void) ((task->state == task_state_ready) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 233, isc_assertiontype_require , "task->state == task_state_ready"), 0))); | ||||
234 | |||||
235 | push_readyq(manager, task); | ||||
236 | } | ||||
237 | |||||
238 | static inline int | ||||
239 | task_detach(isc_task_t *task) { | ||||
240 | |||||
241 | /* | ||||
242 | * Caller must be holding the task lock. | ||||
243 | */ | ||||
244 | |||||
245 | REQUIRE(task->references > 0)((void) ((task->references > 0) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 245, isc_assertiontype_require , "task->references > 0"), 0))); | ||||
246 | |||||
247 | task->references--; | ||||
248 | if (task->references == 0 && task->state == task_state_idle) { | ||||
249 | INSIST(EMPTY(task->events))((void) ((((task->events).head == ((void *)0))) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 249, isc_assertiontype_insist , "((task->events).head == ((void *)0))"), 0))); | ||||
250 | /* | ||||
251 | * There are no references to this task, and no | ||||
252 | * pending events. We could try to optimize and | ||||
253 | * either initiate shutdown or clean up the task, | ||||
254 | * depending on its state, but it's easier to just | ||||
255 | * make the task ready and allow run() or the event | ||||
256 | * loop to deal with shutting down and termination. | ||||
257 | */ | ||||
258 | task->state = task_state_ready; | ||||
259 | return (1); | ||||
260 | } | ||||
261 | |||||
262 | return (0); | ||||
263 | } | ||||
264 | |||||
265 | void | ||||
266 | isc_task_detach(isc_task_t **taskp) { | ||||
267 | isc_task_t *task; | ||||
268 | int was_idle; | ||||
269 | |||||
270 | /* | ||||
271 | * Detach *taskp from its task. | ||||
272 | */ | ||||
273 | |||||
274 | REQUIRE(taskp != NULL)((void) ((taskp != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 274, isc_assertiontype_require, "taskp != ((void *)0)"), 0) )); | ||||
275 | task = (isc_task_t *)*taskp; | ||||
276 | |||||
277 | was_idle = task_detach(task); | ||||
278 | |||||
279 | if (was_idle) | ||||
280 | task_ready(task); | ||||
281 | |||||
282 | *taskp = NULL((void *)0); | ||||
283 | } | ||||
284 | |||||
285 | static inline int | ||||
286 | task_send(isc_task_t *task, isc_event_t **eventp) { | ||||
287 | int was_idle = 0; | ||||
288 | isc_event_t *event; | ||||
289 | |||||
290 | /* | ||||
291 | * Caller must be holding the task lock. | ||||
292 | */ | ||||
293 | |||||
294 | REQUIRE(eventp != NULL)((void) ((eventp != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 294, isc_assertiontype_require, "eventp != ((void *)0)"), 0 ))); | ||||
295 | event = *eventp; | ||||
296 | REQUIRE(event != NULL)((void) ((event != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 296, isc_assertiontype_require, "event != ((void *)0)"), 0) )); | ||||
297 | REQUIRE(event->ev_type > 0)((void) ((event->ev_type > 0) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 297, isc_assertiontype_require , "event->ev_type > 0"), 0))); | ||||
298 | REQUIRE(task->state != task_state_done)((void) ((task->state != task_state_done) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 298, isc_assertiontype_require , "task->state != task_state_done"), 0))); | ||||
299 | REQUIRE(!ISC_LINK_LINKED(event, ev_ratelink))((void) ((!((void *)((event)->ev_ratelink.prev) != (void * )(-1))) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 299, isc_assertiontype_require, "!((void *)((event)->ev_ratelink.prev) != (void *)(-1))" ), 0))); | ||||
300 | |||||
301 | if (task->state == task_state_idle) { | ||||
302 | was_idle = 1; | ||||
303 | INSIST(EMPTY(task->events))((void) ((((task->events).head == ((void *)0))) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 303, isc_assertiontype_insist , "((task->events).head == ((void *)0))"), 0))); | ||||
304 | task->state = task_state_ready; | ||||
305 | } | ||||
306 | INSIST(task->state == task_state_ready ||((void) ((task->state == task_state_ready || task->state == task_state_running) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 307, isc_assertiontype_insist, "task->state == task_state_ready || task->state == task_state_running" ), 0))) | ||||
307 | task->state == task_state_running)((void) ((task->state == task_state_ready || task->state == task_state_running) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 307, isc_assertiontype_insist, "task->state == task_state_ready || task->state == task_state_running" ), 0))); | ||||
308 | ENQUEUE(task->events, event, ev_link)do { do { if ((task->events).tail != ((void *)0)) (task-> events).tail->ev_link.next = (event); else (task->events ).head = (event); (event)->ev_link.prev = (task->events ).tail; (event)->ev_link.next = ((void *)0); (task->events ).tail = (event); } while (0); } while (0); | ||||
309 | task->nevents++; | ||||
310 | *eventp = NULL((void *)0); | ||||
311 | |||||
312 | return (was_idle); | ||||
313 | } | ||||
314 | |||||
315 | void | ||||
316 | isc_task_send(isc_task_t *task, isc_event_t **eventp) { | ||||
317 | int was_idle; | ||||
318 | |||||
319 | /* | ||||
320 | * Send '*event' to 'task'. | ||||
321 | */ | ||||
322 | |||||
323 | /* | ||||
324 | * We're trying hard to hold locks for as short a time as possible. | ||||
325 | * We're also trying to hold as few locks as possible. This is why | ||||
326 | * some processing is deferred until after the lock is released. | ||||
327 | */ | ||||
328 | was_idle = task_send(task, eventp); | ||||
329 | |||||
330 | if (was_idle) { | ||||
331 | /* | ||||
332 | * We need to add this task to the ready queue. | ||||
333 | * | ||||
334 | * We've waited until now to do it because making a task | ||||
335 | * ready requires locking the manager. If we tried to do | ||||
336 | * this while holding the task lock, we could deadlock. | ||||
337 | * | ||||
338 | * We've changed the state to ready, so no one else will | ||||
339 | * be trying to add this task to the ready queue. The | ||||
340 | * only way to leave the ready state is by executing the | ||||
341 | * task. It thus doesn't matter if events are added, | ||||
342 | * removed, or a shutdown is started in the interval | ||||
343 | * between the time we released the task lock, and the time | ||||
344 | * we add the task to the ready queue. | ||||
345 | */ | ||||
346 | task_ready(task); | ||||
347 | } | ||||
348 | } | ||||
349 | |||||
350 | void | ||||
351 | isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { | ||||
352 | int idle1, idle2; | ||||
353 | isc_task_t *task; | ||||
354 | |||||
355 | /* | ||||
356 | * Send '*event' to '*taskp' and then detach '*taskp' from its | ||||
357 | * task. | ||||
358 | */ | ||||
359 | |||||
360 | REQUIRE(taskp != NULL)((void) ((taskp != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 360, isc_assertiontype_require, "taskp != ((void *)0)"), 0) )); | ||||
361 | task = (isc_task_t *)*taskp; | ||||
362 | |||||
363 | idle1 = task_send(task, eventp); | ||||
364 | idle2 = task_detach(task); | ||||
365 | |||||
366 | /* | ||||
367 | * If idle1, then idle2 shouldn't be true as well since we're holding | ||||
368 | * the task lock, and thus the task cannot switch from ready back to | ||||
369 | * idle. | ||||
370 | */ | ||||
371 | INSIST(!(idle1 && idle2))((void) ((!(idle1 && idle2)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 371, isc_assertiontype_insist , "!(idle1 && idle2)"), 0))); | ||||
372 | |||||
373 | if (idle1 || idle2) | ||||
374 | task_ready(task); | ||||
375 | |||||
376 | *taskp = NULL((void *)0); | ||||
377 | } | ||||
378 | |||||
379 | #define PURGE_OK(event)(((event)->ev_attributes & 0x00000001) == 0) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE0x00000001) == 0) | ||||
380 | |||||
381 | static unsigned int | ||||
382 | dequeue_events(isc_task_t *task, void *sender, isc_eventtype_t first, | ||||
383 | isc_eventtype_t last, void *tag, | ||||
384 | isc_eventlist_t *events, int purging) | ||||
385 | { | ||||
386 | isc_event_t *event, *next_event; | ||||
387 | unsigned int count = 0; | ||||
388 | |||||
389 | REQUIRE(last >= first)((void) ((last >= first) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 389, isc_assertiontype_require, "last >= first"), 0))); | ||||
390 | |||||
391 | /* | ||||
392 | * Events matching 'sender', whose type is >= first and <= last, and | ||||
393 | * whose tag is 'tag' will be dequeued. If 'purging', matching events | ||||
394 | * which are marked as unpurgable will not be dequeued. | ||||
395 | * | ||||
396 | * sender == NULL means "any sender", and tag == NULL means "any tag". | ||||
397 | */ | ||||
398 | |||||
399 | for (event = HEAD(task->events)((task->events).head); event != NULL((void *)0); event = next_event) { | ||||
400 | next_event = NEXT(event, ev_link)((event)->ev_link.next); | ||||
401 | if (event->ev_type >= first && event->ev_type <= last && | ||||
402 | (sender == NULL((void *)0) || event->ev_sender == sender) && | ||||
403 | (tag == NULL((void *)0) || event->ev_tag == tag) && | ||||
404 | (!purging || PURGE_OK(event)(((event)->ev_attributes & 0x00000001) == 0))) { | ||||
405 | DEQUEUE(task->events, event, ev_link)do { do { if ((event)->ev_link.next != ((void *)0)) (event )->ev_link.next->ev_link.prev = (event)->ev_link.prev ; else { ((void) (((task->events).tail == (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 405, isc_assertiontype_insist , "(task->events).tail == (event)"), 0))); (task->events ).tail = (event)->ev_link.prev; } if ((event)->ev_link. prev != ((void *)0)) (event)->ev_link.prev->ev_link.next = (event)->ev_link.next; else { ((void) (((task->events ).head == (event)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 405, isc_assertiontype_insist, "(task->events).head == (event)" ), 0))); (task->events).head = (event)->ev_link.next; } (event)->ev_link.prev = (void *)(-1); (event)->ev_link .next = (void *)(-1); ((void) (((task->events).head != (event )) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 405, isc_assertiontype_insist, "(task->events).head != (event)" ), 0))); ((void) (((task->events).tail != (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 405, isc_assertiontype_insist , "(task->events).tail != (event)"), 0))); } while (0); } while (0); | ||||
406 | task->nevents--; | ||||
407 | ENQUEUE(*events, event, ev_link)do { do { if ((*events).tail != ((void *)0)) (*events).tail-> ev_link.next = (event); else (*events).head = (event); (event )->ev_link.prev = (*events).tail; (event)->ev_link.next = ((void *)0); (*events).tail = (event); } while (0); } while (0); | ||||
408 | count++; | ||||
409 | } | ||||
410 | } | ||||
411 | |||||
412 | return (count); | ||||
413 | } | ||||
414 | |||||
415 | unsigned int | ||||
416 | isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first, | ||||
417 | isc_eventtype_t last, void *tag) | ||||
418 | { | ||||
419 | unsigned int count; | ||||
420 | isc_eventlist_t events; | ||||
421 | isc_event_t *event, *next_event; | ||||
422 | |||||
423 | /* | ||||
424 | * Purge events from a task's event queue. | ||||
425 | */ | ||||
426 | |||||
427 | ISC_LIST_INIT(events)do { (events).head = ((void *)0); (events).tail = ((void *)0) ; } while (0); | ||||
428 | |||||
429 | count = dequeue_events(task, sender, first, last, tag, &events, | ||||
430 | 1); | ||||
431 | |||||
432 | for (event = HEAD(events)((events).head); event != NULL((void *)0); event = next_event) { | ||||
433 | next_event = NEXT(event, ev_link)((event)->ev_link.next); | ||||
434 | ISC_LIST_UNLINK(events, event, ev_link)do { do { if ((event)->ev_link.next != ((void *)0)) (event )->ev_link.next->ev_link.prev = (event)->ev_link.prev ; else { ((void) (((events).tail == (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 434, isc_assertiontype_insist , "(events).tail == (event)"), 0))); (events).tail = (event)-> ev_link.prev; } if ((event)->ev_link.prev != ((void *)0)) ( event)->ev_link.prev->ev_link.next = (event)->ev_link .next; else { ((void) (((events).head == (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 434, isc_assertiontype_insist , "(events).head == (event)"), 0))); (events).head = (event)-> ev_link.next; } (event)->ev_link.prev = (void *)(-1); (event )->ev_link.next = (void *)(-1); ((void) (((events).head != (event)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 434, isc_assertiontype_insist, "(events).head != (event)"), 0))); ((void) (((events).tail != (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 434, isc_assertiontype_insist , "(events).tail != (event)"), 0))); } while (0); } while (0); | ||||
435 | isc_event_free(&event); | ||||
436 | } | ||||
437 | |||||
438 | /* | ||||
439 | * Note that purging never changes the state of the task. | ||||
440 | */ | ||||
441 | |||||
442 | return (count); | ||||
443 | } | ||||
444 | |||||
445 | void | ||||
446 | isc_task_setname(isc_task_t *task, const char *name, void *tag) { | ||||
447 | /* | ||||
448 | * Name 'task'. | ||||
449 | */ | ||||
450 | |||||
451 | strlcpy(task->name, name, sizeof(task->name)); | ||||
452 | task->tag = tag; | ||||
453 | } | ||||
454 | |||||
455 | /*** | ||||
456 | *** Task Manager. | ||||
457 | ***/ | ||||
458 | |||||
459 | /* | ||||
460 | * Return 1 if the current ready list for the manager, which is | ||||
461 | * either ready_tasks or the ready_priority_tasks, depending on whether | ||||
462 | * the manager is currently in normal or privileged execution mode. | ||||
463 | * | ||||
464 | * Caller must hold the task manager lock. | ||||
465 | */ | ||||
466 | static inline int | ||||
467 | empty_readyq(isc_taskmgr_t *manager) { | ||||
468 | isc_tasklist_t queue; | ||||
469 | |||||
470 | if (manager->mode == isc_taskmgrmode_normal) | ||||
471 | queue = manager->ready_tasks; | ||||
472 | else | ||||
473 | queue = manager->ready_priority_tasks; | ||||
474 | |||||
475 | return (EMPTY(queue)((queue).head == ((void *)0))); | ||||
476 | } | ||||
477 | |||||
478 | /* | ||||
479 | * Dequeue and return a pointer to the first task on the current ready | ||||
480 | * list for the manager. | ||||
481 | * If the task is privileged, dequeue it from the other ready list | ||||
482 | * as well. | ||||
483 | * | ||||
484 | * Caller must hold the task manager lock. | ||||
485 | */ | ||||
486 | static inline isc_task_t * | ||||
487 | pop_readyq(isc_taskmgr_t *manager) { | ||||
488 | isc_task_t *task; | ||||
489 | |||||
490 | if (manager->mode
| ||||
491 | task = HEAD(manager->ready_tasks)((manager->ready_tasks).head); | ||||
492 | else | ||||
493 | task = HEAD(manager->ready_priority_tasks)((manager->ready_priority_tasks).head); | ||||
494 | |||||
495 | if (task
| ||||
496 | DEQUEUE(manager->ready_tasks, task, ready_link)do { do { if ((task)->ready_link.next != ((void *)0)) (task )->ready_link.next->ready_link.prev = (task)->ready_link .prev; else { ((void) (((manager->ready_tasks).tail == (task )) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 496, isc_assertiontype_insist, "(manager->ready_tasks).tail == (task)" ), 0))); (manager->ready_tasks).tail = (task)->ready_link .prev; } if ((task)->ready_link.prev != ((void *)0)) (task )->ready_link.prev->ready_link.next = (task)->ready_link .next; else { ((void) (((manager->ready_tasks).head == (task )) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 496, isc_assertiontype_insist, "(manager->ready_tasks).head == (task)" ), 0))); (manager->ready_tasks).head = (task)->ready_link .next; } (task)->ready_link.prev = (void *)(-1); (task)-> ready_link.next = (void *)(-1); ((void) (((manager->ready_tasks ).head != (task)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 496, isc_assertiontype_insist, "(manager->ready_tasks).head != (task)" ), 0))); ((void) (((manager->ready_tasks).tail != (task)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 496, isc_assertiontype_insist, "(manager->ready_tasks).tail != (task)" ), 0))); } while (0); } while (0); | ||||
| |||||
497 | if (ISC_LINK_LINKED(task, ready_priority_link)((void *)((task)->ready_priority_link.prev) != (void *)(-1 ))) | ||||
498 | DEQUEUE(manager->ready_priority_tasks, task,do { do { if ((task)->ready_priority_link.next != ((void * )0)) (task)->ready_priority_link.next->ready_priority_link .prev = (task)->ready_priority_link.prev; else { ((void) ( ((manager->ready_priority_tasks).tail == (task)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 499, isc_assertiontype_insist , "(manager->ready_priority_tasks).tail == (task)"), 0))); (manager->ready_priority_tasks).tail = (task)->ready_priority_link .prev; } if ((task)->ready_priority_link.prev != ((void *) 0)) (task)->ready_priority_link.prev->ready_priority_link .next = (task)->ready_priority_link.next; else { ((void) ( ((manager->ready_priority_tasks).head == (task)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 499, isc_assertiontype_insist , "(manager->ready_priority_tasks).head == (task)"), 0))); (manager->ready_priority_tasks).head = (task)->ready_priority_link .next; } (task)->ready_priority_link.prev = (void *)(-1); ( task)->ready_priority_link.next = (void *)(-1); ((void) (( (manager->ready_priority_tasks).head != (task)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 499, isc_assertiontype_insist , "(manager->ready_priority_tasks).head != (task)"), 0))); ((void) (((manager->ready_priority_tasks).tail != (task)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 499, isc_assertiontype_insist, "(manager->ready_priority_tasks).tail != (task)" ), 0))); } while (0); } while (0) | ||||
499 | ready_priority_link)do { do { if ((task)->ready_priority_link.next != ((void * )0)) (task)->ready_priority_link.next->ready_priority_link .prev = (task)->ready_priority_link.prev; else { ((void) ( ((manager->ready_priority_tasks).tail == (task)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 499, isc_assertiontype_insist , "(manager->ready_priority_tasks).tail == (task)"), 0))); (manager->ready_priority_tasks).tail = (task)->ready_priority_link .prev; } if ((task)->ready_priority_link.prev != ((void *) 0)) (task)->ready_priority_link.prev->ready_priority_link .next = (task)->ready_priority_link.next; else { ((void) ( ((manager->ready_priority_tasks).head == (task)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 499, isc_assertiontype_insist , "(manager->ready_priority_tasks).head == (task)"), 0))); (manager->ready_priority_tasks).head = (task)->ready_priority_link .next; } (task)->ready_priority_link.prev = (void *)(-1); ( task)->ready_priority_link.next = (void *)(-1); ((void) (( (manager->ready_priority_tasks).head != (task)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 499, isc_assertiontype_insist , "(manager->ready_priority_tasks).head != (task)"), 0))); ((void) (((manager->ready_priority_tasks).tail != (task)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 499, isc_assertiontype_insist, "(manager->ready_priority_tasks).tail != (task)" ), 0))); } while (0); } while (0); | ||||
500 | } | ||||
501 | |||||
502 | return (task); | ||||
503 | } | ||||
504 | |||||
505 | /* | ||||
506 | * Push 'task' onto the ready_tasks queue. If 'task' has the privilege | ||||
507 | * flag set, then also push it onto the ready_priority_tasks queue. | ||||
508 | * | ||||
509 | * Caller must hold the task manager lock. | ||||
510 | */ | ||||
511 | static inline void | ||||
512 | push_readyq(isc_taskmgr_t *manager, isc_task_t *task) { | ||||
513 | ENQUEUE(manager->ready_tasks, task, ready_link)do { do { if ((manager->ready_tasks).tail != ((void *)0)) ( manager->ready_tasks).tail->ready_link.next = (task); else (manager->ready_tasks).head = (task); (task)->ready_link .prev = (manager->ready_tasks).tail; (task)->ready_link .next = ((void *)0); (manager->ready_tasks).tail = (task); } while (0); } while (0); | ||||
514 | if ((task->flags & TASK_F_PRIVILEGED0x02) != 0) | ||||
515 | ENQUEUE(manager->ready_priority_tasks, task,do { do { if ((manager->ready_priority_tasks).tail != ((void *)0)) (manager->ready_priority_tasks).tail->ready_priority_link .next = (task); else (manager->ready_priority_tasks).head = (task); (task)->ready_priority_link.prev = (manager->ready_priority_tasks ).tail; (task)->ready_priority_link.next = ((void *)0); (manager ->ready_priority_tasks).tail = (task); } while (0); } while (0) | ||||
516 | ready_priority_link)do { do { if ((manager->ready_priority_tasks).tail != ((void *)0)) (manager->ready_priority_tasks).tail->ready_priority_link .next = (task); else (manager->ready_priority_tasks).head = (task); (task)->ready_priority_link.prev = (manager->ready_priority_tasks ).tail; (task)->ready_priority_link.next = ((void *)0); (manager ->ready_priority_tasks).tail = (task); } while (0); } while (0); | ||||
517 | manager->tasks_ready++; | ||||
518 | } | ||||
519 | |||||
520 | static void | ||||
521 | dispatch(isc_taskmgr_t *manager) { | ||||
522 | isc_task_t *task; | ||||
523 | unsigned int total_dispatch_count = 0; | ||||
524 | isc_tasklist_t new_ready_tasks; | ||||
525 | isc_tasklist_t new_priority_tasks; | ||||
526 | unsigned int tasks_ready = 0; | ||||
527 | |||||
528 | ISC_LIST_INIT(new_ready_tasks)do { (new_ready_tasks).head = ((void *)0); (new_ready_tasks). tail = ((void *)0); } while (0); | ||||
| |||||
529 | ISC_LIST_INIT(new_priority_tasks)do { (new_priority_tasks).head = ((void *)0); (new_priority_tasks ).tail = ((void *)0); } while (0); | ||||
530 | |||||
531 | while (!FINISHED(manager)((manager)->exiting && (((manager)->tasks).head == ((void *)0)))) { | ||||
532 | if (total_dispatch_count
| ||||
533 | empty_readyq(manager)) | ||||
534 | break; | ||||
535 | |||||
536 | task = pop_readyq(manager); | ||||
537 | if (task
| ||||
538 | unsigned int dispatch_count = 0; | ||||
539 | int done = 0; | ||||
540 | int requeue = 0; | ||||
541 | int finished = 0; | ||||
542 | isc_event_t *event; | ||||
543 | |||||
544 | /* | ||||
545 | * Note we only unlock the manager lock if we actually | ||||
546 | * have a task to do. We must reacquire the manager | ||||
547 | * lock before exiting the 'if (task != NULL)' block. | ||||
548 | */ | ||||
549 | manager->tasks_ready--; | ||||
550 | manager->tasks_running++; | ||||
551 | |||||
552 | INSIST(task->state == task_state_ready)((void) ((task->state == task_state_ready) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 552, isc_assertiontype_insist , "task->state == task_state_ready"), 0))); | ||||
553 | task->state = task_state_running; | ||||
554 | time(&task->now); | ||||
555 | do { | ||||
556 | if (!EMPTY(task->events)((task->events).head == ((void *)0))) { | ||||
557 | event = HEAD(task->events)((task->events).head); | ||||
558 | DEQUEUE(task->events, event, ev_link)do { do { if ((event)->ev_link.next != ((void *)0)) (event )->ev_link.next->ev_link.prev = (event)->ev_link.prev ; else { ((void) (((task->events).tail == (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 558, isc_assertiontype_insist , "(task->events).tail == (event)"), 0))); (task->events ).tail = (event)->ev_link.prev; } if ((event)->ev_link. prev != ((void *)0)) (event)->ev_link.prev->ev_link.next = (event)->ev_link.next; else { ((void) (((task->events ).head == (event)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 558, isc_assertiontype_insist, "(task->events).head == (event)" ), 0))); (task->events).head = (event)->ev_link.next; } (event)->ev_link.prev = (void *)(-1); (event)->ev_link .next = (void *)(-1); ((void) (((task->events).head != (event )) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 558, isc_assertiontype_insist, "(task->events).head != (event)" ), 0))); ((void) (((task->events).tail != (event)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 558, isc_assertiontype_insist , "(task->events).tail != (event)"), 0))); } while (0); } while (0); | ||||
559 | task->nevents--; | ||||
560 | |||||
561 | /* | ||||
562 | * Execute the event action. | ||||
563 | */ | ||||
564 | if (event->ev_action != NULL((void *)0)) { | ||||
565 | (event->ev_action)( | ||||
566 | (isc_task_t *)task, | ||||
567 | event); | ||||
568 | } | ||||
569 | dispatch_count++; | ||||
570 | total_dispatch_count++; | ||||
571 | } | ||||
572 | |||||
573 | if (task->references == 0 && | ||||
574 | EMPTY(task->events)((task->events).head == ((void *)0)) && | ||||
575 | !TASK_SHUTTINGDOWN(task)(((task)->flags & 0x01) != 0)) { | ||||
576 | int was_idle; | ||||
577 | |||||
578 | /* | ||||
579 | * There are no references and no | ||||
580 | * pending events for this task, | ||||
581 | * which means it will not become | ||||
582 | * runnable again via an external | ||||
583 | * action (such as sending an event | ||||
584 | * or detaching). | ||||
585 | * | ||||
586 | * We initiate shutdown to prevent | ||||
587 | * it from becoming a zombie. | ||||
588 | * | ||||
589 | * We do this here instead of in | ||||
590 | * the "if EMPTY(task->events)" block | ||||
591 | * below because: | ||||
592 | * | ||||
593 | * If we post no shutdown events, | ||||
594 | * we want the task to finish. | ||||
595 | * | ||||
596 | * If we did post shutdown events, | ||||
597 | * will still want the task's | ||||
598 | * quantum to be applied. | ||||
599 | */ | ||||
600 | was_idle = task_shutdown(task); | ||||
601 | INSIST(!was_idle)((void) ((!was_idle) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 601, isc_assertiontype_insist, "!was_idle"), 0))); | ||||
602 | } | ||||
603 | |||||
604 | if (EMPTY(task->events)((task->events).head == ((void *)0))) { | ||||
605 | /* | ||||
606 | * Nothing else to do for this task | ||||
607 | * right now. | ||||
608 | */ | ||||
609 | if (task->references
| ||||
610 | TASK_SHUTTINGDOWN(task)(((task)->flags & 0x01) != 0)) { | ||||
611 | /* | ||||
612 | * The task is done. | ||||
613 | */ | ||||
614 | finished = 1; | ||||
615 | task->state = task_state_done; | ||||
616 | } else | ||||
617 | task->state = task_state_idle; | ||||
618 | done = 1; | ||||
619 | } else if (dispatch_count >= task->quantum) { | ||||
620 | /* | ||||
621 | * Our quantum has expired, but | ||||
622 | * there is more work to be done. | ||||
623 | * We'll requeue it to the ready | ||||
624 | * queue later. | ||||
625 | * | ||||
626 | * We don't check quantum until | ||||
627 | * dispatching at least one event, | ||||
628 | * so the minimum quantum is one. | ||||
629 | */ | ||||
630 | task->state = task_state_ready; | ||||
631 | requeue = 1; | ||||
632 | done = 1; | ||||
633 | } | ||||
634 | } while (!done); | ||||
635 | |||||
636 | if (finished
| ||||
637 | task_finished(task); | ||||
638 | |||||
639 | manager->tasks_running--; | ||||
640 | if (requeue
| ||||
641 | /* | ||||
642 | * We know we're awake, so we don't have | ||||
643 | * to wakeup any sleeping threads if the | ||||
644 | * ready queue is empty before we requeue. | ||||
645 | * | ||||
646 | * A possible optimization if the queue is | ||||
647 | * empty is to 'goto' the 'if (task != NULL)' | ||||
648 | * block, avoiding the ENQUEUE of the task | ||||
649 | * and the subsequent immediate DEQUEUE | ||||
650 | * (since it is the only executable task). | ||||
651 | * We don't do this because then we'd be | ||||
652 | * skipping the exit_requested check. The | ||||
653 | * cost of ENQUEUE is low anyway, especially | ||||
654 | * when you consider that we'd have to do | ||||
655 | * an extra EMPTY check to see if we could | ||||
656 | * do the optimization. If the ready queue | ||||
657 | * were usually nonempty, the 'optimization' | ||||
658 | * might even hurt rather than help. | ||||
659 | */ | ||||
660 | ENQUEUE(new_ready_tasks, task, ready_link)do { do { if ((new_ready_tasks).tail != ((void *)0)) (new_ready_tasks ).tail->ready_link.next = (task); else (new_ready_tasks).head = (task); (task)->ready_link.prev = (new_ready_tasks).tail ; (task)->ready_link.next = ((void *)0); (new_ready_tasks) .tail = (task); } while (0); } while (0); | ||||
661 | if ((task->flags & TASK_F_PRIVILEGED0x02) != 0) | ||||
662 | ENQUEUE(new_priority_tasks, task,do { do { if ((new_priority_tasks).tail != ((void *)0)) (new_priority_tasks ).tail->ready_priority_link.next = (task); else (new_priority_tasks ).head = (task); (task)->ready_priority_link.prev = (new_priority_tasks ).tail; (task)->ready_priority_link.next = ((void *)0); (new_priority_tasks ).tail = (task); } while (0); } while (0) | ||||
663 | ready_priority_link)do { do { if ((new_priority_tasks).tail != ((void *)0)) (new_priority_tasks ).tail->ready_priority_link.next = (task); else (new_priority_tasks ).head = (task); (task)->ready_priority_link.prev = (new_priority_tasks ).tail; (task)->ready_priority_link.next = ((void *)0); (new_priority_tasks ).tail = (task); } while (0); } while (0); | ||||
664 | tasks_ready++; | ||||
665 | } | ||||
666 | } | ||||
667 | |||||
668 | } | ||||
669 | |||||
670 | ISC_LIST_APPENDLIST(manager->ready_tasks, new_ready_tasks, ready_link)do { if (((manager->ready_tasks).head == ((void *)0))) (manager ->ready_tasks) = (new_ready_tasks); else if (!((new_ready_tasks ).head == ((void *)0))) { (manager->ready_tasks).tail-> ready_link.next = (new_ready_tasks).head; (new_ready_tasks).head ->ready_link.prev = (manager->ready_tasks).tail; (manager ->ready_tasks).tail = (new_ready_tasks).tail; } (new_ready_tasks ).head = ((void *)0); (new_ready_tasks).tail = ((void *)0); } while (0); | ||||
671 | ISC_LIST_APPENDLIST(manager->ready_priority_tasks, new_priority_tasks,do { if (((manager->ready_priority_tasks).head == ((void * )0))) (manager->ready_priority_tasks) = (new_priority_tasks ); else if (!((new_priority_tasks).head == ((void *)0))) { (manager ->ready_priority_tasks).tail->ready_priority_link.next = (new_priority_tasks).head; (new_priority_tasks).head->ready_priority_link .prev = (manager->ready_priority_tasks).tail; (manager-> ready_priority_tasks).tail = (new_priority_tasks).tail; } (new_priority_tasks ).head = ((void *)0); (new_priority_tasks).tail = ((void *)0) ; } while (0) | ||||
672 | ready_priority_link)do { if (((manager->ready_priority_tasks).head == ((void * )0))) (manager->ready_priority_tasks) = (new_priority_tasks ); else if (!((new_priority_tasks).head == ((void *)0))) { (manager ->ready_priority_tasks).tail->ready_priority_link.next = (new_priority_tasks).head; (new_priority_tasks).head->ready_priority_link .prev = (manager->ready_priority_tasks).tail; (manager-> ready_priority_tasks).tail = (new_priority_tasks).tail; } (new_priority_tasks ).head = ((void *)0); (new_priority_tasks).tail = ((void *)0) ; } while (0); | ||||
673 | manager->tasks_ready += tasks_ready; | ||||
674 | if (empty_readyq(manager)) | ||||
675 | manager->mode = isc_taskmgrmode_normal; | ||||
676 | |||||
677 | } | ||||
678 | |||||
679 | static void | ||||
680 | manager_free(isc_taskmgr_t *manager) { | ||||
681 | free(manager); | ||||
682 | taskmgr = NULL((void *)0); | ||||
683 | } | ||||
684 | |||||
685 | isc_result_t | ||||
686 | isc_taskmgr_create(unsigned int workers, | ||||
687 | unsigned int default_quantum, isc_taskmgr_t **managerp) | ||||
688 | { | ||||
689 | unsigned int i, started = 0; | ||||
690 | isc_taskmgr_t *manager; | ||||
691 | |||||
692 | /* | ||||
693 | * Create a new task manager. | ||||
694 | */ | ||||
695 | |||||
696 | REQUIRE(workers > 0)((void) ((workers > 0) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 696, isc_assertiontype_require, "workers > 0"), 0))); | ||||
697 | REQUIRE(managerp != NULL && *managerp == NULL)((void) ((managerp != ((void *)0) && *managerp == ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 697, isc_assertiontype_require, "managerp != ((void *)0) && *managerp == ((void *)0)" ), 0))); | ||||
698 | |||||
699 | UNUSED(i)(void)(i); | ||||
700 | UNUSED(started)(void)(started); | ||||
701 | |||||
702 | if (taskmgr != NULL((void *)0)) { | ||||
703 | if (taskmgr->refs == 0) | ||||
704 | return (ISC_R_SHUTTINGDOWN22); | ||||
705 | taskmgr->refs++; | ||||
706 | *managerp = (isc_taskmgr_t *)taskmgr; | ||||
707 | return (ISC_R_SUCCESS0); | ||||
708 | } | ||||
709 | |||||
710 | manager = malloc(sizeof(*manager)); | ||||
711 | if (manager == NULL((void *)0)) | ||||
712 | return (ISC_R_NOMEMORY1); | ||||
713 | manager->mode = isc_taskmgrmode_normal; | ||||
714 | |||||
715 | if (default_quantum == 0) | ||||
716 | default_quantum = DEFAULT_DEFAULT_QUANTUM5; | ||||
717 | manager->default_quantum = default_quantum; | ||||
718 | INIT_LIST(manager->tasks)do { (manager->tasks).head = ((void *)0); (manager->tasks ).tail = ((void *)0); } while (0); | ||||
719 | INIT_LIST(manager->ready_tasks)do { (manager->ready_tasks).head = ((void *)0); (manager-> ready_tasks).tail = ((void *)0); } while (0); | ||||
720 | INIT_LIST(manager->ready_priority_tasks)do { (manager->ready_priority_tasks).head = ((void *)0); ( manager->ready_priority_tasks).tail = ((void *)0); } while (0); | ||||
721 | manager->tasks_running = 0; | ||||
722 | manager->tasks_ready = 0; | ||||
723 | manager->exclusive_requested = 0; | ||||
724 | manager->pause_requested = 0; | ||||
725 | manager->exiting = 0; | ||||
726 | manager->excl = NULL((void *)0); | ||||
727 | |||||
728 | manager->refs = 1; | ||||
729 | taskmgr = manager; | ||||
730 | |||||
731 | *managerp = (isc_taskmgr_t *)manager; | ||||
732 | |||||
733 | return (ISC_R_SUCCESS0); | ||||
734 | } | ||||
735 | |||||
736 | void | ||||
737 | isc_taskmgr_destroy(isc_taskmgr_t **managerp) { | ||||
738 | isc_taskmgr_t *manager; | ||||
739 | isc_task_t *task; | ||||
740 | unsigned int i; | ||||
741 | |||||
742 | /* | ||||
743 | * Destroy '*managerp'. | ||||
744 | */ | ||||
745 | |||||
746 | REQUIRE(managerp != NULL)((void) ((managerp != ((void *)0)) || ((isc_assertion_failed) ("/usr/src/usr.bin/dig/lib/isc/task.c", 746, isc_assertiontype_require , "managerp != ((void *)0)"), 0))); | ||||
747 | manager = (isc_taskmgr_t *)*managerp; | ||||
748 | |||||
749 | UNUSED(i)(void)(i); | ||||
750 | |||||
751 | manager->refs--; | ||||
752 | if (manager->refs > 0) { | ||||
753 | *managerp = NULL((void *)0); | ||||
754 | return; | ||||
755 | } | ||||
756 | |||||
757 | /* | ||||
758 | * Only one non-worker thread may ever call this routine. | ||||
759 | * If a worker thread wants to initiate shutdown of the | ||||
760 | * task manager, it should ask some non-worker thread to call | ||||
761 | * isc_taskmgr_destroy(), e.g. by signalling a condition variable | ||||
762 | * that the startup thread is sleeping on. | ||||
763 | */ | ||||
764 | |||||
765 | /* | ||||
766 | * Detach the exclusive task before acquiring the manager lock | ||||
767 | */ | ||||
768 | if (manager->excl != NULL((void *)0)) | ||||
769 | isc_task_detach((isc_task_t **) &manager->excl); | ||||
770 | |||||
771 | /* | ||||
772 | * Make sure we only get called once. | ||||
773 | */ | ||||
774 | INSIST(!manager->exiting)((void) ((!manager->exiting) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/task.c" , 774, isc_assertiontype_insist, "!manager->exiting"), 0)) ); | ||||
775 | manager->exiting = 1; | ||||
776 | |||||
777 | /* | ||||
778 | * If privileged mode was on, turn it off. | ||||
779 | */ | ||||
780 | manager->mode = isc_taskmgrmode_normal; | ||||
781 | |||||
782 | /* | ||||
783 | * Post shutdown event(s) to every task (if they haven't already been | ||||
784 | * posted). | ||||
785 | */ | ||||
786 | for (task = HEAD(manager->tasks)((manager->tasks).head); | ||||
787 | task != NULL((void *)0); | ||||
788 | task = NEXT(task, link)((task)->link.next)) { | ||||
789 | if (task_shutdown(task)) | ||||
790 | push_readyq(manager, task); | ||||
791 | } | ||||
792 | /* | ||||
793 | * Dispatch the shutdown events. | ||||
794 | */ | ||||
795 | while (isc_taskmgr_ready((isc_taskmgr_t *)manager)) | ||||
796 | (void)isc_taskmgr_dispatch((isc_taskmgr_t *)manager); | ||||
797 | INSIST(ISC_LIST_EMPTY(manager->tasks))((void) ((((manager->tasks).head == ((void *)0))) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/task.c", 797, isc_assertiontype_insist , "((manager->tasks).head == ((void *)0))"), 0))); | ||||
798 | taskmgr = NULL((void *)0); | ||||
799 | |||||
800 | manager_free(manager); | ||||
801 | |||||
802 | *managerp = NULL((void *)0); | ||||
803 | } | ||||
804 | |||||
805 | int | ||||
806 | isc_taskmgr_ready(isc_taskmgr_t *manager) { | ||||
807 | int is_ready; | ||||
808 | |||||
809 | if (manager == NULL((void *)0)) | ||||
810 | manager = taskmgr; | ||||
811 | if (manager == NULL((void *)0)) | ||||
812 | return (0); | ||||
813 | |||||
814 | is_ready = !empty_readyq(manager); | ||||
815 | |||||
816 | return (is_ready); | ||||
817 | } | ||||
818 | |||||
819 | isc_result_t | ||||
820 | isc_taskmgr_dispatch(isc_taskmgr_t *manager) { | ||||
821 | if (manager == NULL((void *)0)) | ||||
822 | manager = taskmgr; | ||||
823 | if (manager == NULL((void *)0)) | ||||
824 | return (ISC_R_NOTFOUND23); | ||||
825 | |||||
826 | dispatch(manager); | ||||
827 | |||||
828 | return (ISC_R_SUCCESS0); | ||||
829 | } |