Minor edits to silence the compiler.
1 | /* |
2 | * The contents of this file are subject to the AOLserver Public License |
3 | * Version 1.1 (the "License"); you may not use this file except in |
4 | * compliance with the License. You may obtain a copy of the License at |
5 | * http://aolserver.com/. |
6 | * |
7 | * Software distributed under the License is distributed on an "AS IS" |
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
9 | * the License for the specific language governing rights and limitations |
10 | * under the License. |
11 | * |
12 | * The Original Code is AOLserver Code and related documentation |
13 | * distributed by AOL. |
14 | * |
15 | * The Initial Developer of the Original Code is America Online, |
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, |
17 | * Inc. All Rights Reserved. |
18 | * |
19 | * Alternatively, the contents of this file may be used under the terms |
20 | * of the GNU General Public License (the "GPL"), in which case the |
21 | * provisions of GPL are applicable instead of those above. If you wish |
22 | * to allow use of your version of this file only under the terms of the |
23 | * GPL and not to allow others to use your version of this file under the |
24 | * License, indicate your decision by deleting the provisions above and |
25 | * replace them with the notice and other provisions required by the GPL. |
26 | * If you do not delete the provisions above, a recipient may use your |
27 | * version of this file under either the License or the GPL. |
28 | */ |
29 | |
30 | /* |
31 | * task.c -- |
32 | * |
33 | * Support for I/O tasks. |
34 | */ |
35 | |
36 | static const char *RCSID = "@(#) $Header: /cvsroot-fuse/aolserver/aolserver/nsd/task.c,v 1.4 2005/08/01 20:29:24 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__; |
37 | |
38 | #include "nsd.h" |
39 | |
40 | /* |
41 | * The following defines a task queue. |
42 | */ |
43 | |
44 | #define NAME_SIZE 31 |
45 | |
46 | typedef struct <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> { |
47 | struct <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *nextPtr; /* Next in list of all queues. */ |
48 | struct Task *firstSignalPtr; /* First in list of task signals. */ |
49 | Ns_Thread tid; /* Thread id. */ |
50 | Ns_Mutex lock; /* <a href="/cvs/aolserver/aolserver/nsd/sockcallback.c#A_Queue">Queue</a> list and signal lock. */ |
51 | Ns_Cond cond; /* Task and queue signal condition. */ |
52 | int shutdown; /* Shutdown flag. */ |
53 | int stopped; /* Stop flag. */ |
54 | SOCKET trigger[2]; /* Trigger pipe. */ |
55 | char name[NAME_SIZE+1]; /* String name. */ |
56 | } <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a>; |
57 | |
58 | /* |
59 | * The following bits are used to send signals to a task queue |
60 | * and manage the state tasks. |
61 | */ |
62 | |
63 | #define TASK_INIT 0x01 |
64 | #define TASK_CANCEL 0x02 |
65 | #define TASK_WAIT 0x04 |
66 | #define TASK_TIMEOUT 0x08 |
67 | #define TASK_DONE 0x10 |
68 | #define TASK_PENDING 0x20 |
69 | |
70 | /* |
71 | * The following defines a task. |
72 | */ |
73 | |
74 | typedef struct Task { |
75 | struct <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr; /* Monitoring queue. */ |
76 | struct Task *nextWaitPtr; /* Next on wait queue. */ |
77 | struct Task *nextSignalPtr; /* Next on signal queue. */ |
78 | SOCKET sock; /* Underlying socket. */ |
79 | Ns_TaskProc *proc; /* <a href="/cvs/aolserver/aolserver/nsd/sockcallback.c#A_Queue">Queue</a> callback. */ |
80 | void *arg; /* Callback data. */ |
81 | int idx; /* <a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll">Poll</a> index. */ |
82 | int events; /* <a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll">Poll</a> events. */ |
83 | Ns_Time timeout; /* Non-null timeout data. */ |
84 | int signal; /* Signal bits sent to/from queue thread. */ |
85 | int flags; /* Flags private to queue. */ |
86 | } Task; |
87 | |
88 | /* |
89 | * Local functions defined in this file |
90 | */ |
91 | |
92 | static void <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TriggerQueue">TriggerQueue</a>(<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr); |
93 | static void <a href="/cvs/aolserver/aolserver/nsd/task.c#A_JoinQueue">JoinQueue</a>(<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr); |
94 | static void <a href="/cvs/aolserver/aolserver/nsd/task.c#A_StopQueue">StopQueue</a>(<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr); |
95 | static int <a href="/cvs/aolserver/aolserver/nsd/task.c#A_SignalQueue">SignalQueue</a>(Task *taskPtr, int bit); |
96 | static Ns_ThreadProc <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskThread">TaskThread</a>; |
97 | static void <a href="/cvs/aolserver/aolserver/nsd/task.c#A_RunTask">RunTask</a>(Task *taskPtr, int revents, Ns_Time *nowPtr); |
98 | #define Call(tp,w) ((*((tp)->proc))((Ns_Task *)(tp),(tp)->sock,(tp)->arg,(w))) |
99 | |
100 | /* |
101 | * Static variables defined in this file |
102 | */ |
103 | |
104 | static <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *firstQueuePtr; /* List of all queues. */ |
105 | static Ns_Mutex lock; /* Lock for queue list. */ |
106 | |
107 | /* |
108 | * The following maps AOLserver sock "when" bits to <a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll"><a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll">Poll</a></a> event bits. |
109 | * The order is significant and determines the order of callbacks |
110 | * when multiple events are ready. |
111 | */ |
112 | |
113 | static struct { |
114 | int when; /* AOLserver when bit. */ |
115 | int event; /* <a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll">Poll</a> event bit. */ |
116 | } map[] = { |
117 | {NS_SOCK_EXCEPTION, POLLPRI}, |
118 | {NS_SOCK_WRITE, POLLOUT}, |
119 | {NS_SOCK_READ, POLLIN} |
120 | }; |
121 | |
122 | |
123 | /* |
124 | *---------------------------------------------------------------------- |
125 | * |
126 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_CreateTaskQueue">Ns_CreateTaskQueue</a> -- |
127 | * |
128 | * Create a new task queue. |
129 | * |
130 | * Results: |
131 | * Handle to task queue.. |
132 | * |
133 | * Side effects: |
134 | * None. |
135 | * |
136 | *---------------------------------------------------------------------- |
137 | */ |
138 | |
139 | Ns_TaskQueue * |
140 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_CreateTaskQueue">Ns_CreateTaskQueue</a>(char *name) |
141 | { |
142 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr; |
143 | |
144 | queuePtr = ns_calloc(1, sizeof(<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a>)); |
145 | strncpy(queuePtr->name, name ? name : "", NAME_SIZE); |
146 | if (<a href="/cvs/aolserver/aolserver/nsd/fd.c#A_ns_sockpair">ns_sockpair</a>(queuePtr->trigger) != 0) { |
147 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Fatal">Ns_Fatal</a>("queue: <a href="/cvs/aolserver/aolserver/nsd/fd.c#A_ns_sockpair">ns_sockpair</a>() failed: %s", |
148 | ns_sockstrerror(ns_sockerrno)); |
149 | } |
150 | Ns_MutexLock(&lock); |
151 | queuePtr->nextPtr = firstQueuePtr; |
152 | firstQueuePtr = queuePtr; |
153 | Ns_ThreadCreate(<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskThread">TaskThread</a>, queuePtr, 0, &queuePtr->tid); |
154 | Ns_MutexUnlock(&lock); |
155 | return (Ns_TaskQueue *) queuePtr; |
156 | } |
157 | |
158 | |
159 | /* |
160 | *---------------------------------------------------------------------- |
161 | * |
162 | * Ns_DestoryTaskQueue -- |
163 | * |
164 | * Stop and join a task queue. |
165 | * |
166 | * Results: |
167 | * None. |
168 | * |
169 | * Side effects: |
170 | * Pending tasks callbacks, if any, are cancelled. |
171 | * |
172 | *---------------------------------------------------------------------- |
173 | */ |
174 | |
175 | void |
176 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_DestroyTaskQueue">Ns_DestroyTaskQueue</a>(Ns_TaskQueue *queue) |
177 | { |
178 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr = (<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *) queue; |
179 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> **nextPtrPtr; |
180 | |
181 | /* |
182 | * Remove queue from list of all queues. |
183 | */ |
184 | |
185 | Ns_MutexLock(&lock); |
186 | nextPtrPtr = &firstQueuePtr; |
187 | while (*nextPtrPtr != queuePtr) { |
188 | nextPtrPtr = &(*nextPtrPtr)->nextPtr; |
189 | } |
190 | *nextPtrPtr = queuePtr->nextPtr; |
191 | Ns_MutexUnlock(&lock); |
192 | |
193 | /* |
194 | * Signal stop and wait for join. |
195 | */ |
196 | |
197 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_StopQueue">StopQueue</a>(queuePtr); |
198 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_JoinQueue">JoinQueue</a>(queuePtr); |
199 | } |
200 | |
201 | |
202 | /* |
203 | *---------------------------------------------------------------------- |
204 | * |
205 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCreate">Ns_TaskCreate</a> -- |
206 | * |
207 | * Create a new task. |
208 | * |
209 | * Results: |
210 | * Handle to task. |
211 | * |
212 | * Side effects: |
213 | * None |
214 | * |
215 | *---------------------------------------------------------------------- |
216 | */ |
217 | |
218 | Ns_Task * |
219 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCreate">Ns_TaskCreate</a>(SOCKET sock, Ns_TaskProc *proc, void *arg) |
220 | { |
221 | Task *taskPtr; |
222 | |
223 | taskPtr = ns_calloc(1, sizeof(Task)); |
224 | taskPtr->sock = sock; |
225 | taskPtr->proc = proc; |
226 | taskPtr->arg = arg; |
227 | return (Ns_Task *) taskPtr; |
228 | } |
229 | |
230 | |
231 | /* |
232 | *---------------------------------------------------------------------- |
233 | * |
234 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskEnqueue">Ns_TaskEnqueue</a> -- |
235 | * |
236 | * Add a task to a queue. |
237 | * |
238 | * Results: |
239 | * NS_OK if task sent, NS_ERROR otherwise. |
240 | * |
241 | * Side effects: |
242 | * <a href="/cvs/aolserver/aolserver/nsd/sockcallback.c#A_Queue">Queue</a> will begin running the task. |
243 | * |
244 | *---------------------------------------------------------------------- |
245 | */ |
246 | |
247 | int |
248 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskEnqueue">Ns_TaskEnqueue</a>(Ns_Task *task, Ns_TaskQueue *queue) |
249 | { |
250 | Task *taskPtr = (Task *) task; |
251 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr = (<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *) queue; |
252 | |
253 | taskPtr->queuePtr = queuePtr; |
254 | if (!<a href="/cvs/aolserver/aolserver/nsd/task.c#A_SignalQueue">SignalQueue</a>(taskPtr, TASK_INIT)) { |
255 | return NS_ERROR; |
256 | } |
257 | return NS_OK; |
258 | } |
259 | |
260 | |
261 | /* |
262 | *---------------------------------------------------------------------- |
263 | * |
264 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskRun">Ns_TaskRun</a> -- |
265 | * |
266 | * Run a task directly, waiting for completion. |
267 | * |
268 | * Results: |
269 | * None. |
270 | * |
271 | * Side effects: |
272 | * Depends on task callback. |
273 | * |
274 | *---------------------------------------------------------------------- |
275 | */ |
276 | |
277 | void |
278 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskRun">Ns_TaskRun</a>(Ns_Task *task) |
279 | { |
280 | Task *taskPtr = (Task *) task; |
281 | struct pollfd pfd; |
282 | Ns_Time now, *timeoutPtr; |
283 | |
284 | pfd.fd = taskPtr->sock; |
285 | Call(taskPtr, NS_SOCK_INIT); |
286 | while (!(taskPtr->flags & TASK_DONE)) { |
287 | if (taskPtr->flags & TASK_TIMEOUT) { |
288 | timeoutPtr = &taskPtr->timeout; |
289 | } else { |
290 | timeoutPtr = NULL; |
291 | } |
292 | pfd.revents = 0; |
293 | pfd.events = taskPtr->events; |
294 | if (<a href="/cvs/aolserver/aolserver/nsd/sock.c#A_NsPoll">NsPoll</a>(&pfd, 1, timeoutPtr) != 1) { |
295 | break; |
296 | } |
297 | Ns_GetTime(&now); |
298 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_RunTask">RunTask</a>(taskPtr, pfd.revents, &now); |
299 | } |
300 | taskPtr->signal |= TASK_DONE; |
301 | } |
302 | |
303 | |
304 | /* |
305 | *---------------------------------------------------------------------- |
306 | * |
307 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCancel">Ns_TaskCancel</a> -- |
308 | * |
309 | * Signal a task queue to stop running a task. |
310 | * |
311 | * Results: |
312 | * NS_OK if cancel sent, NS_ERROR otherwise. |
313 | * |
314 | * Side effects: |
315 | * Task callback will be invoke with NS_SOCK_CANCEL and is |
316 | * expected to call <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskDone">Ns_TaskDone</a> to indicate completion. |
317 | * |
318 | *---------------------------------------------------------------------- |
319 | */ |
320 | |
321 | int |
322 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCancel">Ns_TaskCancel</a>(Ns_Task *task) |
323 | { |
324 | Task *taskPtr = (Task *) task; |
325 | |
326 | if (taskPtr->queuePtr == NULL) { |
327 | taskPtr->signal |= TASK_CANCEL; |
328 | } else if (!<a href="/cvs/aolserver/aolserver/nsd/task.c#A_SignalQueue">SignalQueue</a>(taskPtr, TASK_CANCEL)) { |
329 | return NS_ERROR; |
330 | } |
331 | return NS_OK; |
332 | } |
333 | |
334 | |
335 | /* |
336 | *---------------------------------------------------------------------- |
337 | * |
338 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskWait">Ns_TaskWait</a> -- |
339 | * |
340 | * Wait for a task to complete. Infinite wait is indicated |
341 | * by a NULL timeoutPtr. |
342 | * |
343 | * Results: |
344 | * NS_TIMEOUT if task did not complete by absolute time, |
345 | * NS_OK otherwise. |
346 | * |
347 | * Side effects: |
348 | * May wait up to specified timeout. |
349 | * |
350 | *---------------------------------------------------------------------- |
351 | */ |
352 | |
353 | int |
354 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskWait">Ns_TaskWait</a>(Ns_Task *task, Ns_Time *timeoutPtr) |
355 | { |
356 | Task *taskPtr = (Task *) task; |
357 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr = taskPtr->queuePtr; |
358 | int status = NS_OK; |
359 | |
360 | if (queuePtr == NULL) { |
361 | if (!(taskPtr->signal & TASK_DONE)) { |
362 | status = NS_TIMEOUT; |
363 | } |
364 | } else { |
365 | Ns_MutexLock(&queuePtr->lock); |
366 | while (status == NS_OK && !(taskPtr->signal & TASK_DONE)) { |
367 | status = Ns_CondTimedWait(&queuePtr->cond, &queuePtr->lock, |
368 | timeoutPtr); |
369 | } |
370 | Ns_MutexUnlock(&queuePtr->lock); |
371 | if (status == NS_OK) { |
372 | taskPtr->queuePtr = NULL; |
373 | } |
374 | } |
375 | return status; |
376 | } |
377 | |
378 | |
379 | /* |
380 | *---------------------------------------------------------------------- |
381 | * |
382 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCallback">Ns_TaskCallback</a> -- |
383 | * |
384 | * Update pending conditions and timeout for a task. This |
385 | * routine is expected to be called from within the task |
386 | * callback proc including to set the initial wait conditions |
387 | * from within the NS_SOCK_INIT callback. |
388 | * |
389 | * Results: |
390 | * None. |
391 | * |
392 | * Side effects: |
393 | * Task callback will be invoked when ready or on timeout. |
394 | * |
395 | *---------------------------------------------------------------------- |
396 | */ |
397 | |
398 | void |
399 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCallback">Ns_TaskCallback</a>(Ns_Task *task, int when, Ns_Time *timeoutPtr) |
400 | { |
401 | Task *taskPtr = (Task *) task; |
402 | int i; |
403 | |
404 | /* |
405 | * Map from AOLserver when bits to <a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll"><a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll">Poll</a></a> event bits. |
406 | */ |
407 | |
408 | taskPtr->events = 0; |
409 | for (i = 0; i < 3; ++i) { |
410 | if (when & map[i].when) { |
411 | taskPtr->events |= map[i].event; |
412 | } |
413 | } |
414 | |
415 | /* |
416 | * Copy timeout, if any. |
417 | */ |
418 | |
419 | if (timeoutPtr == NULL) { |
420 | taskPtr->flags &= ~TASK_TIMEOUT; |
421 | } else { |
422 | taskPtr->flags |= TASK_TIMEOUT; |
423 | taskPtr->timeout = *timeoutPtr; |
424 | } |
425 | |
426 | /* |
427 | * Mark as waiting if there are events or a timeout. |
428 | */ |
429 | |
430 | if (taskPtr->events || timeoutPtr) { |
431 | taskPtr->flags |= TASK_WAIT; |
432 | } else { |
433 | taskPtr->flags &= ~TASK_WAIT; |
434 | } |
435 | } |
436 | |
437 | |
438 | /* |
439 | *---------------------------------------------------------------------- |
440 | * |
441 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskDone">Ns_TaskDone</a> -- |
442 | * |
443 | * Mark a task as done. This routine should be called from |
444 | * within the task callback. The task queue thread will signal |
445 | * other waiting threads, if any, on next spin. |
446 | * |
447 | * Results: |
448 | * None. |
449 | * |
450 | * Side effects: |
451 | * Task queue will signal this task is done on next spin. |
452 | * |
453 | *---------------------------------------------------------------------- |
454 | */ |
455 | |
456 | void |
457 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskDone">Ns_TaskDone</a>(Ns_Task *event) |
458 | { |
459 | Task *taskPtr = (Task *) event; |
460 | |
461 | taskPtr->flags |= TASK_DONE; |
462 | } |
463 | |
464 | |
465 | /* |
466 | *---------------------------------------------------------------------- |
467 | * |
468 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskFree">Ns_TaskFree</a> -- |
469 | * |
470 | * Free task structure. The caller is responsible for |
471 | * ensuring the task is no longer being run or monitored |
472 | * a task queue. |
473 | * |
474 | * Results: |
475 | * The task SOCKET which the caller is responsible for closing |
476 | * or reusing. |
477 | * |
478 | * Side effects: |
479 | * None. |
480 | * |
481 | *---------------------------------------------------------------------- |
482 | */ |
483 | |
484 | SOCKET |
485 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskFree">Ns_TaskFree</a>(Ns_Task *task) |
486 | { |
487 | Task *taskPtr = (Task *) task; |
488 | SOCKET sock = taskPtr->sock; |
489 | |
490 | ns_free(taskPtr); |
491 | return sock; |
492 | } |
493 | |
494 | |
495 | /* |
496 | *---------------------------------------------------------------------- |
497 | * |
498 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_NsStartQueueShutdown">NsStartQueueShutdown</a> -- |
499 | * |
500 | * Trigger all task queues to begin shutdown. |
501 | * |
502 | * Results: |
503 | * None. |
504 | * |
505 | * Side effects: |
506 | * None. |
507 | * |
508 | *---------------------------------------------------------------------- |
509 | */ |
510 | |
511 | void |
512 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_NsStartQueueShutdown">NsStartQueueShutdown</a>(void) |
513 | { |
514 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr; |
515 | |
516 | /* |
517 | * Trigger all queues to shutdown. |
518 | */ |
519 | |
520 | Ns_MutexLock(&lock); |
521 | queuePtr = firstQueuePtr; |
522 | while (queuePtr != NULL) { |
523 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_StopQueue">StopQueue</a>(queuePtr); |
524 | queuePtr = queuePtr->nextPtr; |
525 | } |
526 | Ns_MutexUnlock(&lock); |
527 | } |
528 | |
529 | |
530 | /* |
531 | *---------------------------------------------------------------------- |
532 | * |
533 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_NsWaitQueueShutdown">NsWaitQueueShutdown</a> -- |
534 | * |
535 | * Wait for all task queues to shutdown. |
536 | * |
537 | * Results: |
538 | * None. |
539 | * |
540 | * Side effects: |
541 | * May timeout waiting for shutdown. |
542 | * |
543 | *---------------------------------------------------------------------- |
544 | */ |
545 | |
546 | void |
547 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_NsWaitQueueShutdown">NsWaitQueueShutdown</a>(Ns_Time *toPtr) |
548 | { |
549 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr, *nextPtr; |
550 | int status; |
551 | |
552 | /* |
553 | * Clear out list of any remaining task queues. |
554 | */ |
555 | |
556 | Ns_MutexLock(&lock); |
557 | queuePtr = firstQueuePtr; |
558 | firstQueuePtr = NULL; |
559 | Ns_MutexUnlock(&lock); |
560 | |
561 | /* |
562 | * Join all queues possible within total allowed time. |
563 | */ |
564 | |
565 | status = NS_OK; |
566 | while (status == NS_OK && queuePtr != NULL) { |
567 | nextPtr = queuePtr->nextPtr; |
568 | Ns_MutexLock(&queuePtr->lock); |
569 | while (status == NS_OK && !queuePtr->stopped) { |
570 | status = Ns_CondTimedWait(&queuePtr->cond, &queuePtr->lock, toPtr); |
571 | } |
572 | Ns_MutexUnlock(&queuePtr->lock); |
573 | if (status == NS_OK) { |
574 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_JoinQueue">JoinQueue</a>(queuePtr); |
575 | } |
576 | queuePtr = nextPtr; |
577 | } |
578 | if (status != NS_OK) { |
579 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Warning, "timeout waiting for event queue shutdown"); |
580 | } |
581 | } |
582 | |
583 | |
584 | /* |
585 | *---------------------------------------------------------------------- |
586 | * |
587 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_RunTask">RunTask</a> -- |
588 | * |
589 | * Run a single task from either a task queue or a directly via |
590 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskRun">Ns_TaskRun</a>. |
591 | * |
592 | * Results: |
593 | * None. |
594 | * |
595 | * Side effects: |
596 | * Depends on callbacks of given task. |
597 | * |
598 | *---------------------------------------------------------------------- |
599 | */ |
600 | |
601 | static void |
602 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_RunTask">RunTask</a>(Task *taskPtr, int revents, Ns_Time *nowPtr) |
603 | { |
604 | int i; |
605 | |
606 | /* |
607 | * NB: Treat POLLHUP as POLLIN on systems which return it. |
608 | */ |
609 | |
610 | if (revents & POLLHUP) { |
611 | revents |= POLLIN; |
612 | } |
613 | if (revents) { |
614 | for (i = 0; i < 3; ++i) { |
615 | if (revents & map[i].event) { |
616 | Call(taskPtr, map[i].when); |
617 | } |
618 | } |
619 | } else if ((taskPtr->flags & TASK_TIMEOUT) |
620 | && Ns_DiffTime(&taskPtr->timeout, nowPtr, NULL) < 0) { |
621 | taskPtr->flags &= ~ TASK_WAIT; |
622 | Call(taskPtr, NS_SOCK_TIMEOUT); |
623 | } |
624 | } |
625 | |
626 | |
627 | /* |
628 | *---------------------------------------------------------------------- |
629 | * |
630 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_SignalQueue">SignalQueue</a> -- |
631 | * |
632 | * Send a signal for a task to a task queue. |
633 | * |
634 | * Results: |
635 | * None. |
636 | * |
637 | * Side effects: |
638 | * Task queue will process signal on next spin. |
639 | * |
640 | *---------------------------------------------------------------------- |
641 | */ |
642 | |
643 | static int |
644 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_SignalQueue">SignalQueue</a>(Task *taskPtr, int bit) |
645 | { |
646 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr = taskPtr->queuePtr; |
647 | int pending = 0, shutdown; |
648 | |
649 | Ns_MutexLock(&queuePtr->lock); |
650 | shutdown = queuePtr->shutdown; |
651 | if (!shutdown) { |
652 | |
653 | /* |
654 | * Mark the signal and add event to signal list if not |
655 | * already there. |
656 | */ |
657 | |
658 | taskPtr->signal |= bit; |
659 | pending = (taskPtr->signal & TASK_PENDING); |
660 | if (!pending) { |
661 | taskPtr->signal |= TASK_PENDING; |
662 | taskPtr->nextSignalPtr = queuePtr->firstSignalPtr; |
663 | queuePtr->firstSignalPtr = taskPtr; |
664 | } |
665 | } |
666 | Ns_MutexUnlock(&queuePtr->lock); |
667 | if (shutdown) { |
668 | return 0; |
669 | } |
670 | if (!pending) { |
671 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TriggerQueue">TriggerQueue</a>(queuePtr); |
672 | } |
673 | return 1; |
674 | } |
675 | |
676 | |
677 | /* |
678 | *---------------------------------------------------------------------- |
679 | * |
680 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TriggerQueue">TriggerQueue</a> -- |
681 | * |
682 | * Wakeup a task queue. |
683 | * |
684 | * Results: |
685 | * None. |
686 | * |
687 | * Side effects: |
688 | * None. |
689 | * |
690 | *---------------------------------------------------------------------- |
691 | */ |
692 | |
693 | static void |
694 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TriggerQueue">TriggerQueue</a>(<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr) |
695 | { |
696 | if (send(queuePtr->trigger[1], "", 1, 0) != 1) { |
697 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Fatal">Ns_Fatal</a>("queue: trigger send() failed: %s", |
698 | ns_sockstrerror(ns_sockerrno)); |
699 | } |
700 | } |
701 | |
702 | |
703 | /* |
704 | *---------------------------------------------------------------------- |
705 | * |
706 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_StopQueue">StopQueue</a> -- |
707 | * |
708 | * Signal a task queue to shutdown. |
709 | * |
710 | * Results: |
711 | * None. |
712 | * |
713 | * Side effects: |
714 | * <a href="/cvs/aolserver/aolserver/nsd/sockcallback.c#A_Queue">Queue</a> will exit on next spin and call remaining tasks |
715 | * with NS_SOCK_EXIT. |
716 | * |
717 | *---------------------------------------------------------------------- |
718 | */ |
719 | |
720 | static void |
721 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_StopQueue">StopQueue</a>(<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr) |
722 | { |
723 | Ns_MutexLock(&queuePtr->lock); |
724 | queuePtr->shutdown = 1; |
725 | Ns_MutexUnlock(&queuePtr->lock); |
726 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TriggerQueue">TriggerQueue</a>(queuePtr); |
727 | } |
728 | |
729 | |
730 | /* |
731 | *---------------------------------------------------------------------- |
732 | * |
733 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_JoinQueue">JoinQueue</a> -- |
734 | * |
735 | * Cleanup resources of a task queue. |
736 | * |
737 | * Results: |
738 | * None. |
739 | * |
740 | * Side effects: |
741 | * None. |
742 | * |
743 | *---------------------------------------------------------------------- |
744 | */ |
745 | |
746 | static void |
747 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_JoinQueue">JoinQueue</a>(<a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr) |
748 | { |
749 | Ns_ThreadJoin(&queuePtr->tid, NULL); |
750 | ns_sockclose(queuePtr->trigger[0]); |
751 | ns_sockclose(queuePtr->trigger[1]); |
752 | Ns_MutexDestroy(&queuePtr->lock); |
753 | ns_free(queuePtr); |
754 | } |
755 | |
756 | |
757 | /* |
758 | *---------------------------------------------------------------------- |
759 | * |
760 | * <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskThread">TaskThread</a> -- |
761 | * |
762 | * Run an task queue. |
763 | * |
764 | * Results: |
765 | * None. |
766 | * |
767 | * Side effects: |
768 | * Depends on callbacks of given tasks. |
769 | * |
770 | *---------------------------------------------------------------------- |
771 | */ |
772 | |
773 | static void |
774 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskThread">TaskThread</a>(void *arg) |
775 | { |
776 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_TaskQueue">TaskQueue</a> *queuePtr = arg; |
777 | char c; |
778 | int n, broadcast, max, nfds, shutdown; |
779 | Task *taskPtr, *nextPtr, *firstWaitPtr; |
780 | struct pollfd *pfds; |
781 | Ns_Time now, *timeoutPtr; |
782 | char name[NAME_SIZE+10]; |
783 | |
784 | sprintf(name, "task:%s", queuePtr->name); |
785 | Ns_ThreadSetName(name); |
786 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "starting"); |
787 | |
788 | max = 100; |
789 | pfds = ns_malloc(sizeof(struct pollfd) * max); |
790 | firstWaitPtr = NULL; |
791 | |
792 | while (1) { |
793 | |
794 | /* |
795 | * Get the shutdown flag and process any incoming signals. |
796 | */ |
797 | |
798 | Ns_MutexLock(&queuePtr->lock); |
799 | shutdown = queuePtr->shutdown; |
800 | while ((taskPtr = queuePtr->firstSignalPtr) != NULL) { |
801 | queuePtr->firstSignalPtr = taskPtr->nextSignalPtr; |
802 | taskPtr->nextSignalPtr = NULL; |
803 | if (!(taskPtr->flags & TASK_WAIT)) { |
804 | taskPtr->flags |= TASK_WAIT; |
805 | taskPtr->nextWaitPtr = firstWaitPtr; |
806 | firstWaitPtr = taskPtr; |
807 | } |
808 | if (taskPtr->signal & TASK_INIT) { |
809 | taskPtr->signal &= ~TASK_INIT; |
810 | taskPtr->flags |= TASK_INIT; |
811 | } |
812 | if (taskPtr->signal & TASK_CANCEL) { |
813 | taskPtr->signal &= ~TASK_CANCEL; |
814 | taskPtr->flags |= TASK_CANCEL; |
815 | } |
816 | taskPtr->signal &= ~TASK_PENDING; |
817 | } |
818 | Ns_MutexUnlock(&queuePtr->lock); |
819 | |
820 | /* |
821 | * Invoke pre-<a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll"><a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll">Poll</a></a> callbacks, determine minimum timeout, and set |
822 | * the pollfd structs for all waiting tasks. |
823 | */ |
824 | |
825 | pfds[0].fd = queuePtr->trigger[0]; |
826 | pfds[0].events = POLLIN; |
827 | pfds[0].revents = 0; |
828 | nfds = 1; |
829 | timeoutPtr = NULL; |
830 | taskPtr = firstWaitPtr; |
831 | firstWaitPtr = NULL; |
832 | broadcast = 0; |
833 | while (taskPtr != NULL) { |
834 | nextPtr = taskPtr->nextWaitPtr; |
835 | |
836 | /* |
837 | * Call init and/or cancel and signal done if necessary. |
838 | * Note that a task can go from init to done immediately |
839 | * so all required callbacks are invoked before determining |
840 | * if a wait is required. |
841 | */ |
842 | |
843 | if (taskPtr->flags & TASK_INIT) { |
844 | taskPtr->flags &= ~TASK_INIT; |
845 | Call(taskPtr, NS_SOCK_INIT); |
846 | } |
847 | if (taskPtr->flags & TASK_CANCEL) { |
848 | taskPtr->flags &= ~(TASK_CANCEL|TASK_WAIT); |
849 | taskPtr->flags |= TASK_DONE; |
850 | Call(taskPtr, NS_SOCK_CANCEL); |
851 | } |
852 | if (taskPtr->flags & TASK_DONE) { |
853 | taskPtr->flags &= ~(TASK_DONE|TASK_WAIT); |
854 | Ns_MutexLock(&queuePtr->lock); |
855 | taskPtr->signal |= TASK_DONE; |
856 | Ns_MutexUnlock(&queuePtr->lock); |
857 | broadcast = 1; |
858 | } |
859 | if (taskPtr->flags & TASK_WAIT) { |
860 | if (max <= nfds) { |
861 | max = nfds + 100; |
862 | pfds = ns_realloc(pfds, (size_t) max); |
863 | } |
864 | taskPtr->idx = nfds; |
865 | pfds[nfds].fd = taskPtr->sock; |
866 | pfds[nfds].events = taskPtr->events; |
867 | pfds[nfds].revents = 0; |
868 | if ((taskPtr->flags & TASK_TIMEOUT) && (timeoutPtr == NULL |
869 | || Ns_DiffTime(&taskPtr->timeout, |
870 | timeoutPtr, NULL) < 0)) { |
871 | timeoutPtr = &taskPtr->timeout; |
872 | } |
873 | taskPtr->nextWaitPtr = firstWaitPtr; |
874 | firstWaitPtr = taskPtr; |
875 | ++nfds; |
876 | } |
877 | taskPtr = nextPtr; |
878 | } |
879 | |
880 | /* |
881 | * Signal other threads which may be waiting on tasks to complete. |
882 | */ |
883 | |
884 | if (broadcast) { |
885 | Ns_CondBroadcast(&queuePtr->cond); |
886 | } |
887 | |
888 | /* |
889 | * Break now if shutting down now that all signals have been processed. |
890 | */ |
891 | |
892 | if (shutdown) { |
893 | break; |
894 | } |
895 | |
896 | /* |
897 | * <a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Poll">Poll</a> sockets and drain the trigger pipe if necessary. |
898 | */ |
899 | |
900 | n = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_NsPoll">NsPoll</a>(pfds, nfds, timeoutPtr); |
901 | if ((pfds[0].revents & POLLIN) && recv(pfds[0].fd, &c, 1, 0) != 1) { |
902 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Fatal">Ns_Fatal</a>("queue: trigger read() failed: %s", |
903 | ns_sockstrerror(ns_sockerrno)); |
904 | } |
905 | |
906 | /* |
907 | * Execute any ready events or timeouts for waiting tasks. |
908 | */ |
909 | |
910 | Ns_GetTime(&now); |
911 | taskPtr = firstWaitPtr; |
912 | while (taskPtr != NULL) { |
913 | <a href="/cvs/aolserver/aolserver/nsd/task.c#A_RunTask">RunTask</a>(taskPtr, pfds[taskPtr->idx].revents, &now); |
914 | taskPtr = taskPtr->nextWaitPtr; |
915 | } |
916 | } |
917 | |
918 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "shutdown pending"); |
919 | |
920 | /* |
921 | * Call exit for all remaining tasks. |
922 | */ |
923 | |
924 | taskPtr = firstWaitPtr; |
925 | while (taskPtr != NULL) { |
926 | Call(taskPtr, NS_SOCK_EXIT); |
927 | taskPtr = taskPtr->nextWaitPtr; |
928 | } |
929 | |
930 | /* |
931 | * Signal all tasks done and shutdown complete. |
932 | */ |
933 | |
934 | Ns_MutexLock(&queuePtr->lock); |
935 | while ((taskPtr = firstWaitPtr) != NULL) { |
936 | firstWaitPtr = taskPtr->nextWaitPtr; |
937 | taskPtr->signal |= TASK_DONE; |
938 | } |
939 | queuePtr->stopped = 1; |
940 | Ns_MutexUnlock(&queuePtr->lock); |
941 | Ns_CondBroadcast(&queuePtr->cond); |
942 | |
943 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "shutdown complete"); |
944 | } |
Copyright © 2010 Geeknet, Inc. All rights reserved. Terms of Use