Bug Summary

File:src/usr.bin/dig/lib/isc/task.c
Warning:line 496, column 3
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name task.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/dig/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/dig -I /usr/src/usr.bin/dig/obj -I /usr/src/usr.bin/dig/bin/dig/include -I /usr/src/usr.bin/dig/lib/dns/include -I /usr/src/usr.bin/dig/lib/isc/include -I /usr/src/usr.bin/dig/lib/isccfg/include -I /usr/src/usr.bin/dig/lib/lwres/include -D VERSION="9.10.8-P1" -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/dig/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/dig/lib/isc/task.c
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
40typedef enum {
41 task_state_idle, task_state_ready, task_state_running,
42 task_state_done
43} task_state_t;
44
45struct 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
71typedef ISC_LIST(isc_task_t)struct { isc_task_t *head, *tail; } isc_tasklist_t;
72
73struct 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
100static isc_taskmgr_t *taskmgr = NULL((void *)0);
101
102static inline int
103empty_readyq(isc_taskmgr_t *manager);
104
105static inline isc_task_t *
106pop_readyq(isc_taskmgr_t *manager);
107
108static inline void
109push_readyq(isc_taskmgr_t *manager, isc_task_t *task);
110
111/***
112 *** Tasks.
113 ***/
114
115static void
116task_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
)))
;
32
Assuming field 'nevents' is equal to 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)))
;
33
Assuming field 'head' is equal to null
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)
;
34
Assuming field 'next' is not equal to null
35
Taking true branch
36
Assuming field 'prev' is not equal to null
37
Taking true branch
38
Assuming 'task' is not equal to field 'head'
39
Assuming 'task' is not equal to field 'tail'
40
Loop condition is false. Exiting loop
41
Loop condition is false. Exiting loop
126
127 free(task);
42
Memory is released
128}
129
130isc_result_t
131isc_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
174void
175isc_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
189static inline int
190task_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 */
229static inline void
230task_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
238static inline int
239task_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
265void
266isc_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
285static inline int
286task_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
315void
316isc_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
350void
351isc_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
381static unsigned int
382dequeue_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
415unsigned int
416isc_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
445void
446isc_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 */
466static inline int
467empty_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 */
486static inline isc_task_t *
487pop_readyq(isc_taskmgr_t *manager) {
488 isc_task_t *task;
489
490 if (manager->mode
6.1
Field 'mode' is not equal to isc_taskmgrmode_normal
47.1
Field 'mode' is not equal to isc_taskmgrmode_normal
== isc_taskmgrmode_normal)
7
Taking false branch
48
Taking false branch
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
7.1
'task' is not equal to NULL
48.1
'task' is not equal to NULL
!= NULL((void *)0)) {
8
Taking true branch
49
Taking true branch
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)
;
9
Assuming field 'next' is equal to null
10
Taking false branch
11
Assuming 'task' is equal to field 'tail'
12
Assuming field 'prev' is equal to null
13
Taking false branch
14
Assuming 'task' is equal to field 'head'
15
Loop condition is false. Exiting loop
16
Loop condition is false. Exiting loop
50
Use of memory after it is freed
497 if (ISC_LINK_LINKED(task, ready_priority_link)((void *)((task)->ready_priority_link.prev) != (void *)(-1
))
)
17
Assuming the condition is false
18
Taking false branch
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 */
511static inline void
512push_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
520static void
521dispatch(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)
;
1
Loop condition is false. Exiting loop
529 ISC_LIST_INIT(new_priority_tasks)do { (new_priority_tasks).head = ((void *)0); (new_priority_tasks
).tail = ((void *)0); } while (0)
;
2
Loop condition is false. Exiting loop
530
531 while (!FINISHED(manager)((manager)->exiting && (((manager)->tasks).head
== ((void *)0)))
) {
3
Assuming field 'exiting' is 0
4
Loop condition is true. Entering loop body
45
Loop condition is true. Entering loop body
532 if (total_dispatch_count
4.1
'total_dispatch_count' is < DEFAULT_TASKMGR_QUANTUM
45.1
'total_dispatch_count' is < DEFAULT_TASKMGR_QUANTUM
>= DEFAULT_TASKMGR_QUANTUM10 ||
5
Taking false branch
46
Taking false branch
533 empty_readyq(manager))
534 break;
535
536 task = pop_readyq(manager);
6
Calling 'pop_readyq'
19
Returning from 'pop_readyq'
47
Calling 'pop_readyq'
537 if (task
19.1
'task' is not equal to NULL
!= NULL((void *)0)) {
20
Taking true branch
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)))
;
21
Assuming field 'state' is equal to task_state_ready
553 task->state = task_state_running;
554 time(&task->now);
555 do {
29
Loop condition is false. Exiting loop
556 if (!EMPTY(task->events)((task->events).head == ((void *)0))) {
22
Assuming field 'head' is equal to null
23
Taking false branch
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 &&
24
Assuming field 'references' is equal to 0
26
Taking false branch
574 EMPTY(task->events)((task->events).head == ((void *)0)) &&
575 !TASK_SHUTTINGDOWN(task)(((task)->flags & 0x01) != 0)) {
25
Assuming the condition is true
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))) {
27
Taking true branch
605 /*
606 * Nothing else to do for this task
607 * right now.
608 */
609 if (task->references
27.1
Field 'references' is equal to 0
== 0 &&
28
Taking true branch
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
29.1
'finished' is 1
)
30
Taking true branch
637 task_finished(task);
31
Calling 'task_finished'
43
Returning; memory was released via 1st parameter
638
639 manager->tasks_running--;
640 if (requeue
43.1
'requeue' is 0
) {
44
Taking false branch
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
679static void
680manager_free(isc_taskmgr_t *manager) {
681 free(manager);
682 taskmgr = NULL((void *)0);
683}
684
685isc_result_t
686isc_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
736void
737isc_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
805int
806isc_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
819isc_result_t
820isc_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}