There are no available options for this view.

Parent Directory Parent Directory | Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a> Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a>

Revision 1.4 - (show annotations) (download) (as text)
Mon Aug 1 20:29:24 2005 UTC (12 years, 5 months ago) by jgdavidson
Branch: MAIN
CVS Tags: aolserver_v45_r0, aolserver_v45_r2_rc0, HEAD
Branch point for: aolserver_v45_r1, aolserver_v45_r2, aolserver_v45_bp
Changes since 1.3: +2 -2 lines
File MIME type: text/x-chdr
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 }