Annotation of libaitsched/src/hooks.c, revision 1.10.2.7
1.1 misho 1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.10.2.7! misho 6: * $Id: hooks.c,v 1.10.2.6 2012/08/01 16:47:06 misho Exp $
1.1 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.5 misho 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
1.1 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47: #include "hooks.h"
48:
49:
50: /*
51: * sched_hook_init() - Default INIT hook
1.5 misho 52: *
1.1 misho 53: * @root = root task
1.6 misho 54: * @arg = unused
1.1 misho 55: * return: <0 errors and 0 ok
56: */
57: void *
1.6 misho 58: sched_hook_init(void *root, void *arg __unused)
1.1 misho 59: {
60: sched_root_task_t *r = root;
61:
1.6 misho 62: if (!r)
1.1 misho 63: return (void*) -1;
64:
65: r->root_kq = kqueue();
66: if (r->root_kq == -1) {
67: LOGERR;
68: return (void*) -1;
69: }
70:
71: return NULL;
72: }
73:
74: /*
75: * sched_hook_fini() - Default FINI hook
1.5 misho 76: *
1.1 misho 77: * @root = root task
78: * @arg = unused
79: * return: <0 errors and 0 ok
80: */
81: void *
82: sched_hook_fini(void *root, void *arg __unused)
83: {
84: sched_root_task_t *r = root;
85:
86: if (!r)
87: return (void*) -1;
88:
89: if (r->root_kq > 2) {
90: close(r->root_kq);
91: r->root_kq = 0;
92: }
93:
94: return NULL;
95: }
96:
97: /*
98: * sched_hook_cancel() - Default CANCEL hook
1.5 misho 99: *
1.1 misho 100: * @task = current task
101: * @arg = unused
102: * return: <0 errors and 0 ok
103: */
104: void *
105: sched_hook_cancel(void *task, void *arg __unused)
106: {
107: sched_task_t *t = task;
108: struct kevent chg[1];
1.2 misho 109: struct timespec timeout = { 0, 0 };
1.10.2.3 misho 110: #ifdef EVFILT_AIO
111: struct aiocb *acb;
112: #endif
1.1 misho 113:
1.6 misho 114: if (!t || !TASK_ROOT(t))
1.1 misho 115: return (void*) -1;
116:
1.4 misho 117: switch (TASK_TYPE(t)) {
1.1 misho 118: case taskREAD:
1.2 misho 119: #ifdef __NetBSD__
120: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
121: #else
122: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (void*) TASK_FD(t));
123: #endif
1.1 misho 124: break;
125: case taskWRITE:
1.2 misho 126: #ifdef __NetBSD__
127: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
128: #else
129: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
130: #endif
1.1 misho 131: break;
1.7 misho 132: case taskALARM:
133: #ifdef __NetBSD__
134: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE,
135: 0, 0, (intptr_t) TASK_DATA(t));
136: #else
137: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE,
138: 0, 0, (void*) TASK_DATA(t));
139: #endif
1.8 misho 140: break;
141: case taskNODE:
142: #ifdef __NetBSD__
143: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
144: #else
145: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
146: #endif
147: break;
148: case taskPROC:
149: #ifdef __NetBSD__
150: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
151: #else
152: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
153: #endif
154: break;
155: case taskSIGNAL:
156: #ifdef __NetBSD__
157: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
158: #else
159: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
160: #endif
161: break;
1.10.2.1 misho 162: #ifdef EVFILT_AIO
163: case taskAIO:
164: #ifdef __NetBSD__
165: EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
166: #else
167: EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
168: #endif
1.10.2.3 misho 169: acb = (struct aiocb*) TASK_VAL(t);
170: if (acb) {
1.10.2.6 misho 171: if (aio_cancel(acb->aio_fildes, acb) == AIO_CANCELED)
172: aio_return(acb);
1.10.2.3 misho 173: free(acb);
1.10.2.2 misho 174: TASK_VAL(t) = 0;
175: }
1.10.2.1 misho 176: break;
177: #endif
1.8 misho 178: #ifdef EVFILT_USER
179: case taskUSER:
180: #ifdef __NetBSD__
181: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
182: #else
183: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
184: #endif
1.10 misho 185: break;
1.8 misho 186: #endif
1.1 misho 187: default:
1.8 misho 188: return NULL;
1.1 misho 189: }
190:
1.8 misho 191: kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout);
1.1 misho 192: return NULL;
193: }
194:
195: /*
196: * sched_hook_read() - Default READ hook
1.5 misho 197: *
1.1 misho 198: * @task = current task
199: * @arg = unused
200: * return: <0 errors and 0 ok
201: */
202: void *
203: sched_hook_read(void *task, void *arg __unused)
204: {
205: sched_task_t *t = task;
206: struct kevent chg[1];
1.2 misho 207: struct timespec timeout = { 0, 0 };
1.1 misho 208:
1.6 misho 209: if (!t || !TASK_ROOT(t))
1.1 misho 210: return (void*) -1;
211:
1.2 misho 212: #ifdef __NetBSD__
1.8 misho 213: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
1.2 misho 214: #else
1.8 misho 215: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
1.2 misho 216: #endif
1.4 misho 217: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
218: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
219: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1.3 misho 220: else
221: LOGERR;
1.1 misho 222: return (void*) -1;
223: }
224:
225: return NULL;
226: }
227:
228: /*
229: * sched_hook_write() - Default WRITE hook
1.5 misho 230: *
1.1 misho 231: * @task = current task
232: * @arg = unused
233: * return: <0 errors and 0 ok
234: */
235: void *
236: sched_hook_write(void *task, void *arg __unused)
237: {
238: sched_task_t *t = task;
239: struct kevent chg[1];
1.2 misho 240: struct timespec timeout = { 0, 0 };
1.1 misho 241:
1.6 misho 242: if (!t || !TASK_ROOT(t))
1.1 misho 243: return (void*) -1;
244:
1.2 misho 245: #ifdef __NetBSD__
1.8 misho 246: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
1.2 misho 247: #else
1.8 misho 248: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
1.2 misho 249: #endif
1.4 misho 250: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
251: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
252: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1.3 misho 253: else
254: LOGERR;
1.1 misho 255: return (void*) -1;
256: }
257:
258: return NULL;
259: }
260:
261: /*
1.7 misho 262: * sched_hook_alarm() - Default ALARM hook
263: *
264: * @task = current task
265: * @arg = unused
266: * return: <0 errors and 0 ok
267: */
268: void *
269: sched_hook_alarm(void *task, void *arg __unused)
270: {
271: sched_task_t *t = task;
272: struct kevent chg[1];
273: struct timespec timeout = { 0, 0 };
274:
275: if (!t || !TASK_ROOT(t))
276: return (void*) -1;
277:
278: #ifdef __NetBSD__
279: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0,
280: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
281: (intptr_t) TASK_DATA(t));
282: #else
283: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0,
284: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
285: (void*) TASK_DATA(t));
286: #endif
287: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
288: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
289: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
290: else
291: LOGERR;
292: return (void*) -1;
293: }
294:
295: return NULL;
296: }
297:
298: /*
1.8 misho 299: * sched_hook_node() - Default NODE hook
300: *
301: * @task = current task
302: * @arg = unused
303: * return: <0 errors and 0 ok
304: */
305: void *
306: sched_hook_node(void *task, void *arg __unused)
307: {
308: sched_task_t *t = task;
309: struct kevent chg[1];
310: struct timespec timeout = { 0, 0 };
311:
312: if (!t || !TASK_ROOT(t))
313: return (void*) -1;
314:
315: #ifdef __NetBSD__
316: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
317: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
318: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (intptr_t) TASK_FD(t));
319: #else
320: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
321: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
322: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (void*) TASK_FD(t));
323: #endif
324: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
325: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
326: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
327: else
328: LOGERR;
329: return (void*) -1;
330: }
331:
332: return NULL;
333: }
334:
335: /*
336: * sched_hook_proc() - Default PROC hook
337: *
338: * @task = current task
339: * @arg = unused
340: * return: <0 errors and 0 ok
341: */
342: void *
343: sched_hook_proc(void *task, void *arg __unused)
344: {
345: sched_task_t *t = task;
346: struct kevent chg[1];
347: struct timespec timeout = { 0, 0 };
348:
349: if (!t || !TASK_ROOT(t))
350: return (void*) -1;
351:
352: #ifdef __NetBSD__
353: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
354: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (intptr_t) TASK_VAL(t));
355: #else
356: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
357: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (void*) TASK_VAL(t));
358: #endif
359: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
360: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
361: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
362: else
363: LOGERR;
364: return (void*) -1;
365: }
366:
367: return NULL;
368: }
369:
370: /*
371: * sched_hook_signal() - Default SIGNAL hook
372: *
373: * @task = current task
374: * @arg = unused
375: * return: <0 errors and 0 ok
376: */
377: void *
378: sched_hook_signal(void *task, void *arg __unused)
379: {
380: sched_task_t *t = task;
381: struct kevent chg[1];
382: struct timespec timeout = { 0, 0 };
383:
384: if (!t || !TASK_ROOT(t))
385: return (void*) -1;
386:
387: #ifdef __NetBSD__
388: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD, 0, 0, (intptr_t) TASK_VAL(t));
389: #else
390: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD, 0, 0, (void*) TASK_VAL(t));
391: #endif
392: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
393: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
394: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
395: else
396: LOGERR;
397: return (void*) -1;
398: }
399:
400: return NULL;
401: }
402:
403: /*
404: * sched_hook_user() - Default USER hook
405: *
406: * @task = current task
407: * @arg = unused
408: * return: <0 errors and 0 ok
409: */
410: #ifdef EVFILT_USER
411: void *
412: sched_hook_user(void *task, void *arg __unused)
413: {
414: sched_task_t *t = task;
415: struct kevent chg[1];
416: struct timespec timeout = { 0, 0 };
417:
418: if (!t || !TASK_ROOT(t))
419: return (void*) -1;
420:
421: #ifdef __NetBSD__
422: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
423: 0, (intptr_t) TASK_VAL(t));
424: #else
425: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
426: 0, (void*) TASK_VAL(t));
427: #endif
428: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
429: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
430: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
431: else
432: LOGERR;
433: return (void*) -1;
434: }
435:
436: return NULL;
437: }
438: #endif
439:
440: /*
1.1 misho 441: * sched_hook_fetch() - Default FETCH hook
1.5 misho 442: *
1.1 misho 443: * @root = root task
444: * @arg = unused
445: * return: NULL error or !=NULL fetched task
446: */
447: void *
448: sched_hook_fetch(void *root, void *arg __unused)
449: {
450: sched_root_task_t *r = root;
1.6 misho 451: sched_task_t *task, *tmp;
1.4 misho 452: struct timespec now, m, mtmp;
453: struct timespec *timeout;
1.1 misho 454: struct kevent evt[1], res[KQ_EVENTS];
1.9 misho 455: register int i, flg;
1.1 misho 456: int en;
1.10.2.2 misho 457: #ifdef EVFILT_AIO
1.10.2.5 misho 458: int len, fd;
1.10.2.2 misho 459: struct aiocb *acb;
1.10.2.7! misho 460: #ifdef EVFILT_LIO
! 461: int l;
! 462: register int j;
! 463: off_t off;
! 464: struct aiocb **acbs;
! 465: #endif /* EVFILT_LIO */
! 466: #endif /* EVFILT_AIO */
1.1 misho 467:
1.6 misho 468: if (!r)
1.1 misho 469: return NULL;
470:
471: /* get new task by queue priority */
472: while ((task = TAILQ_FIRST(&r->root_event))) {
1.4 misho 473: #ifdef HAVE_LIBPTHREAD
474: pthread_mutex_lock(&r->root_mtx[taskEVENT]);
475: #endif
1.1 misho 476: TAILQ_REMOVE(&r->root_event, task, task_node);
1.4 misho 477: #ifdef HAVE_LIBPTHREAD
478: pthread_mutex_unlock(&r->root_mtx[taskEVENT]);
479: #endif
1.1 misho 480: task->task_type = taskUNUSE;
1.4 misho 481: #ifdef HAVE_LIBPTHREAD
482: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
483: #endif
1.1 misho 484: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 485: #ifdef HAVE_LIBPTHREAD
486: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
487: #endif
1.1 misho 488: return task;
489: }
490: while ((task = TAILQ_FIRST(&r->root_ready))) {
1.4 misho 491: #ifdef HAVE_LIBPTHREAD
492: pthread_mutex_lock(&r->root_mtx[taskREADY]);
493: #endif
1.1 misho 494: TAILQ_REMOVE(&r->root_ready, task, task_node);
1.4 misho 495: #ifdef HAVE_LIBPTHREAD
496: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
497: #endif
1.1 misho 498: task->task_type = taskUNUSE;
1.4 misho 499: #ifdef HAVE_LIBPTHREAD
500: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
501: #endif
1.1 misho 502: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 503: #ifdef HAVE_LIBPTHREAD
504: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
505: #endif
1.1 misho 506: return task;
507: }
508:
509: #ifdef TIMER_WITHOUT_SORT
1.4 misho 510: clock_gettime(CLOCK_MONOTONIC, &now);
1.1 misho 511:
1.4 misho 512: sched_timespecclear(&r->root_wait);
1.1 misho 513: TAILQ_FOREACH(task, &r->root_timer, task_node) {
1.4 misho 514: if (!sched_timespecisset(&r->root_wait))
515: r->root_wait = TASK_TS(task);
516: else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
517: r->root_wait = TASK_TS(task);
1.1 misho 518: }
519:
520: if (TAILQ_FIRST(&r->root_timer)) {
521: m = r->root_wait;
1.4 misho 522: sched_timespecsub(&m, &now, &mtmp);
1.1 misho 523: r->root_wait = mtmp;
524: } else {
525: /* set wait INFTIM */
1.4 misho 526: sched_timespecinf(&r->root_wait);
1.1 misho 527: }
528: #else
529: if (!TAILQ_FIRST(&r->root_eventlo) && (task = TAILQ_FIRST(&r->root_timer))) {
1.4 misho 530: clock_gettime(CLOCK_MONOTONIC, &now);
1.1 misho 531:
1.4 misho 532: m = TASK_TS(task);
533: sched_timespecsub(&m, &now, &mtmp);
1.1 misho 534: r->root_wait = mtmp;
535: } else {
536: /* set wait INFTIM */
1.4 misho 537: sched_timespecinf(&r->root_wait);
1.1 misho 538: }
539: #endif
540: /* if present member of eventLo, set NOWAIT */
541: if (TAILQ_FIRST(&r->root_eventlo))
1.4 misho 542: sched_timespecclear(&r->root_wait);
1.1 misho 543:
1.4 misho 544: if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1)
545: timeout = &r->root_wait;
546: else if (sched_timespecisinf(&r->root_poll))
1.1 misho 547: timeout = NULL;
1.4 misho 548: else
549: timeout = &r->root_poll;
1.1 misho 550: if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
1.3 misho 551: if (r->root_hooks.hook_exec.exception) {
552: if (r->root_hooks.hook_exec.exception(r, NULL))
553: return NULL;
1.6 misho 554: } else if (errno != EINTR)
1.3 misho 555: LOGERR;
1.2 misho 556: return NULL;
1.1 misho 557: }
558:
1.4 misho 559: now.tv_sec = now.tv_nsec = 0;
1.1 misho 560: /* Go and catch the cat into pipes ... */
561: for (i = 0; i < en; i++) {
562: memcpy(evt, &res[i], sizeof evt);
563: evt->flags = EV_DELETE;
564: /* Put read/write task to ready queue */
565: switch (res[i].filter) {
566: case EVFILT_READ:
1.9 misho 567: flg = 0;
1.6 misho 568: TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) {
1.3 misho 569: if (TASK_FD(task) != ((intptr_t) res[i].udata))
1.1 misho 570: continue;
1.9 misho 571: else
572: flg++;
1.1 misho 573: /* remove read handle */
1.4 misho 574: #ifdef HAVE_LIBPTHREAD
575: pthread_mutex_lock(&r->root_mtx[taskREAD]);
576: #endif
1.1 misho 577: TAILQ_REMOVE(&r->root_read, task, task_node);
1.4 misho 578: #ifdef HAVE_LIBPTHREAD
579: pthread_mutex_unlock(&r->root_mtx[taskREAD]);
580: #endif
1.3 misho 581: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
582: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
583: task->task_type = taskUNUSE;
1.4 misho 584: #ifdef HAVE_LIBPTHREAD
585: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
586: #endif
1.3 misho 587: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 588: #ifdef HAVE_LIBPTHREAD
589: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
590: #endif
1.3 misho 591: } else {
592: task->task_type = taskREADY;
1.4 misho 593: #ifdef HAVE_LIBPTHREAD
594: pthread_mutex_lock(&r->root_mtx[taskREADY]);
595: #endif
1.3 misho 596: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 597: #ifdef HAVE_LIBPTHREAD
598: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
599: #endif
1.3 misho 600: }
601: } else {
1.2 misho 602: task->task_type = taskREADY;
1.4 misho 603: #ifdef HAVE_LIBPTHREAD
604: pthread_mutex_lock(&r->root_mtx[taskREADY]);
605: #endif
1.2 misho 606: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 607: #ifdef HAVE_LIBPTHREAD
608: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
609: #endif
1.3 misho 610: }
1.1 misho 611: }
1.9 misho 612: /* if match at least 2, don't remove resouce of event */
613: if (flg > 1)
614: evt->flags ^= evt->flags;
1.1 misho 615: break;
616: case EVFILT_WRITE:
1.9 misho 617: flg = 0;
1.6 misho 618: TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) {
1.3 misho 619: if (TASK_FD(task) != ((intptr_t) res[i].udata))
1.1 misho 620: continue;
1.9 misho 621: else
622: flg++;
1.1 misho 623: /* remove write handle */
1.4 misho 624: #ifdef HAVE_LIBPTHREAD
625: pthread_mutex_lock(&r->root_mtx[taskWRITE]);
626: #endif
1.1 misho 627: TAILQ_REMOVE(&r->root_write, task, task_node);
1.4 misho 628: #ifdef HAVE_LIBPTHREAD
629: pthread_mutex_unlock(&r->root_mtx[taskWRITE]);
630: #endif
1.3 misho 631: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
632: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
633: task->task_type = taskUNUSE;
1.4 misho 634: #ifdef HAVE_LIBPTHREAD
635: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
636: #endif
1.3 misho 637: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 638: #ifdef HAVE_LIBPTHREAD
639: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
640: #endif
1.3 misho 641: } else {
642: task->task_type = taskREADY;
1.4 misho 643: #ifdef HAVE_LIBPTHREAD
644: pthread_mutex_lock(&r->root_mtx[taskREADY]);
645: #endif
1.3 misho 646: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 647: #ifdef HAVE_LIBPTHREAD
648: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
649: #endif
1.3 misho 650: }
651: } else {
1.2 misho 652: task->task_type = taskREADY;
1.4 misho 653: #ifdef HAVE_LIBPTHREAD
654: pthread_mutex_lock(&r->root_mtx[taskREADY]);
655: #endif
1.2 misho 656: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 657: #ifdef HAVE_LIBPTHREAD
658: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
659: #endif
1.3 misho 660: }
1.1 misho 661: }
1.9 misho 662: /* if match at least 2, don't remove resouce of event */
663: if (flg > 1)
664: evt->flags ^= evt->flags;
1.1 misho 665: break;
1.7 misho 666: case EVFILT_TIMER:
1.9 misho 667: flg = 0;
1.7 misho 668: TAILQ_FOREACH_SAFE(task, &r->root_alarm, task_node, tmp) {
669: if ((uintptr_t) TASK_DATA(task) != ((uintptr_t) res[i].udata))
670: continue;
1.9 misho 671: else
672: flg++;
1.7 misho 673: /* remove alarm handle */
674: #ifdef HAVE_LIBPTHREAD
675: pthread_mutex_lock(&r->root_mtx[taskALARM]);
676: #endif
677: TAILQ_REMOVE(&r->root_alarm, task, task_node);
678: #ifdef HAVE_LIBPTHREAD
679: pthread_mutex_unlock(&r->root_mtx[taskALARM]);
680: #endif
681: task->task_type = taskREADY;
682: #ifdef HAVE_LIBPTHREAD
683: pthread_mutex_lock(&r->root_mtx[taskREADY]);
684: #endif
685: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
686: #ifdef HAVE_LIBPTHREAD
687: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
688: #endif
689: }
1.9 misho 690: /* if match at least 2, don't remove resouce of event */
691: if (flg > 1)
692: evt->flags ^= evt->flags;
1.7 misho 693: break;
1.8 misho 694: case EVFILT_VNODE:
1.9 misho 695: flg = 0;
1.8 misho 696: TAILQ_FOREACH_SAFE(task, &r->root_node, task_node, tmp) {
697: if (TASK_FD(task) != ((intptr_t) res[i].udata))
698: continue;
699: else {
1.9 misho 700: flg++;
1.8 misho 701: TASK_DATA(task) = (void*) (uintptr_t) res[i].data;
702: TASK_DATLEN(task) = res[i].fflags;
703: }
704: /* remove node handle */
705: #ifdef HAVE_LIBPTHREAD
706: pthread_mutex_lock(&r->root_mtx[taskNODE]);
707: #endif
708: TAILQ_REMOVE(&r->root_node, task, task_node);
709: #ifdef HAVE_LIBPTHREAD
710: pthread_mutex_unlock(&r->root_mtx[taskNODE]);
711: #endif
712: task->task_type = taskREADY;
713: #ifdef HAVE_LIBPTHREAD
714: pthread_mutex_lock(&r->root_mtx[taskREADY]);
715: #endif
716: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
717: #ifdef HAVE_LIBPTHREAD
718: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
719: #endif
720: }
1.9 misho 721: /* if match at least 2, don't remove resouce of event */
722: if (flg > 1)
723: evt->flags ^= evt->flags;
1.8 misho 724: break;
725: case EVFILT_PROC:
1.9 misho 726: flg = 0;
1.8 misho 727: TAILQ_FOREACH_SAFE(task, &r->root_proc, task_node, tmp) {
728: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
729: continue;
730: else {
1.9 misho 731: flg++;
1.8 misho 732: TASK_DATA(task) = (void*) (uintptr_t) res[i].data;
733: TASK_DATLEN(task) = res[i].fflags;
734: }
735: /* remove proc handle */
736: #ifdef HAVE_LIBPTHREAD
737: pthread_mutex_lock(&r->root_mtx[taskPROC]);
738: #endif
739: TAILQ_REMOVE(&r->root_proc, task, task_node);
740: #ifdef HAVE_LIBPTHREAD
741: pthread_mutex_unlock(&r->root_mtx[taskPROC]);
742: #endif
743: task->task_type = taskREADY;
744: #ifdef HAVE_LIBPTHREAD
745: pthread_mutex_lock(&r->root_mtx[taskREADY]);
746: #endif
747: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
748: #ifdef HAVE_LIBPTHREAD
749: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
750: #endif
751: }
1.9 misho 752: /* if match at least 2, don't remove resouce of event */
753: if (flg > 1)
754: evt->flags ^= evt->flags;
1.8 misho 755: break;
756: case EVFILT_SIGNAL:
1.9 misho 757: flg = 0;
1.8 misho 758: TAILQ_FOREACH_SAFE(task, &r->root_signal, task_node, tmp) {
759: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
760: continue;
1.9 misho 761: else
762: flg++;
1.8 misho 763: /* remove signal handle */
764: #ifdef HAVE_LIBPTHREAD
765: pthread_mutex_lock(&r->root_mtx[taskSIGNAL]);
766: #endif
767: TAILQ_REMOVE(&r->root_signal, task, task_node);
768: #ifdef HAVE_LIBPTHREAD
769: pthread_mutex_unlock(&r->root_mtx[taskSIGNAL]);
770: #endif
771: task->task_type = taskREADY;
772: #ifdef HAVE_LIBPTHREAD
773: pthread_mutex_lock(&r->root_mtx[taskREADY]);
774: #endif
775: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
776: #ifdef HAVE_LIBPTHREAD
777: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
778: #endif
779: }
1.9 misho 780: /* if match at least 2, don't remove resouce of event */
781: if (flg > 1)
782: evt->flags ^= evt->flags;
1.8 misho 783: break;
1.10.2.2 misho 784: #ifdef EVFILT_AIO
785: case EVFILT_AIO:
1.10.2.7! misho 786: #ifdef EVFILT_LIO
! 787: case EVFILT_LIO:
! 788: #endif /* EVFILT_LIO */
1.10.2.2 misho 789: flg = 0;
790: TAILQ_FOREACH_SAFE(task, &r->root_aio, task_node, tmp) {
1.10.2.4 misho 791: acb = (struct aiocb*) TASK_VAL(task);
1.10.2.6 misho 792: if (acb != ((struct aiocb*) res[i].udata))
1.10.2.2 misho 793: continue;
794: else
795: flg++;
796: /* remove user handle */
797: #ifdef HAVE_LIBPTHREAD
798: pthread_mutex_lock(&r->root_mtx[taskAIO]);
799: #endif
800: TAILQ_REMOVE(&r->root_aio, task, task_node);
801: #ifdef HAVE_LIBPTHREAD
802: pthread_mutex_unlock(&r->root_mtx[taskAIO]);
803: #endif
804: task->task_type = taskREADY;
805: #ifdef HAVE_LIBPTHREAD
806: pthread_mutex_lock(&r->root_mtx[taskREADY]);
807: #endif
808: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
809: #ifdef HAVE_LIBPTHREAD
810: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
811: #endif
1.10.2.7! misho 812: #ifdef EVFILT_LIO
! 813: if (res[i].filter == EVFILT_LIO) {
! 814: acbs = (struct aiocb**) TASK_VAL(task);
! 815: fd = acbs[0]->aio_fildes;
! 816: off = acbs[0]->aio_offset;
! 817: for (j = len = 0; i < TASK_DATLEN(task); len += l, i++) {
! 818: if ((l = aio_return(acbs[i])) == -1)
! 819: l = 0;
! 820: free(acbs[i]);
! 821: }
! 822: free(acbs);
! 823: if (lseek(fd, off + len, SEEK_CUR) == -1)
1.10.2.4 misho 824: LOGERR;
825: } else
1.10.2.7! misho 826: #endif /* EVFILT_LIO */
! 827: {
! 828: fd = acb->aio_fildes;
! 829: if ((len = aio_return(acb)) != -1) {
! 830: if (lseek(fd, acb->aio_offset + len, SEEK_CUR) == -1)
! 831: LOGERR;
! 832: } else
! 833: LOGERR;
1.10.2.4 misho 834:
1.10.2.7! misho 835: free(acb);
! 836: }
1.10.2.5 misho 837: TASK_DATLEN(task) = (u_long) len;
1.10.2.7! misho 838: TASK_FD(task) = fd;
1.10.2.2 misho 839: }
840: /* if match at least 2, don't remove resouce of event */
841: if (flg > 1)
842: evt->flags ^= evt->flags;
843: break;
844: #endif /* EVFILT_AIO */
1.8 misho 845: #ifdef EVFILT_USER
846: case EVFILT_USER:
1.9 misho 847: flg = 0;
1.8 misho 848: TAILQ_FOREACH_SAFE(task, &r->root_user, task_node, tmp) {
849: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
850: continue;
851: else {
1.9 misho 852: flg++;
1.8 misho 853: TASK_DATA(task) = (void*) res[i].data;
854: TASK_DATLEN(task) = res[i].fflags;
855: }
856: /* remove user handle */
857: #ifdef HAVE_LIBPTHREAD
858: pthread_mutex_lock(&r->root_mtx[taskUSER]);
859: #endif
860: TAILQ_REMOVE(&r->root_user, task, task_node);
861: #ifdef HAVE_LIBPTHREAD
862: pthread_mutex_unlock(&r->root_mtx[taskUSER]);
863: #endif
864: task->task_type = taskREADY;
865: #ifdef HAVE_LIBPTHREAD
866: pthread_mutex_lock(&r->root_mtx[taskREADY]);
867: #endif
868: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
869: #ifdef HAVE_LIBPTHREAD
870: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
871: #endif
872: }
1.9 misho 873: /* if match at least 2, don't remove resouce of event */
874: if (flg > 1)
875: evt->flags ^= evt->flags;
1.8 misho 876: break;
1.10.2.2 misho 877: #endif /* EVFILT_USER */
1.1 misho 878: }
1.4 misho 879: if (kevent(r->root_kq, evt, 1, NULL, 0, &now) == -1) {
1.3 misho 880: if (r->root_hooks.hook_exec.exception) {
881: if (r->root_hooks.hook_exec.exception(r, NULL))
882: return NULL;
883: } else
884: LOGERR;
885: }
1.1 misho 886: }
887:
1.2 misho 888: /* timer update & put in ready queue */
1.4 misho 889: clock_gettime(CLOCK_MONOTONIC, &now);
1.1 misho 890:
1.6 misho 891: TAILQ_FOREACH_SAFE(task, &r->root_timer, task_node, tmp)
1.4 misho 892: if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0) {
893: #ifdef HAVE_LIBPTHREAD
894: pthread_mutex_lock(&r->root_mtx[taskTIMER]);
895: #endif
1.1 misho 896: TAILQ_REMOVE(&r->root_timer, task, task_node);
1.4 misho 897: #ifdef HAVE_LIBPTHREAD
898: pthread_mutex_unlock(&r->root_mtx[taskTIMER]);
899: #endif
1.1 misho 900: task->task_type = taskREADY;
1.4 misho 901: #ifdef HAVE_LIBPTHREAD
902: pthread_mutex_lock(&r->root_mtx[taskREADY]);
903: #endif
1.1 misho 904: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 905: #ifdef HAVE_LIBPTHREAD
906: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
907: #endif
1.1 misho 908: }
909:
910: /* put eventlo priority task to ready queue, if there is no ready task or
911: reach max missed fetch-rotate */
912: if ((task = TAILQ_FIRST(&r->root_eventlo))) {
913: if (!TAILQ_FIRST(&r->root_ready) || r->root_eventlo_miss > MAX_EVENTLO_MISS) {
914: r->root_eventlo_miss = 0;
915:
1.4 misho 916: #ifdef HAVE_LIBPTHREAD
917: pthread_mutex_lock(&r->root_mtx[taskEVENTLO]);
918: #endif
1.1 misho 919: TAILQ_REMOVE(&r->root_eventlo, task, task_node);
1.4 misho 920: #ifdef HAVE_LIBPTHREAD
921: pthread_mutex_unlock(&r->root_mtx[taskEVENTLO]);
922: #endif
1.1 misho 923: task->task_type = taskREADY;
1.4 misho 924: #ifdef HAVE_LIBPTHREAD
925: pthread_mutex_lock(&r->root_mtx[taskREADY]);
926: #endif
1.1 misho 927: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 928: #ifdef HAVE_LIBPTHREAD
929: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
930: #endif
1.1 misho 931: } else
932: r->root_eventlo_miss++;
933: } else
934: r->root_eventlo_miss = 0;
935:
936: /* OK, lets get ready task !!! */
1.6 misho 937: task = TAILQ_FIRST(&r->root_ready);
938: if (!(task))
939: return NULL;
940:
1.4 misho 941: #ifdef HAVE_LIBPTHREAD
942: pthread_mutex_lock(&r->root_mtx[taskREADY]);
943: #endif
1.1 misho 944: TAILQ_REMOVE(&r->root_ready, task, task_node);
1.4 misho 945: #ifdef HAVE_LIBPTHREAD
946: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
947: #endif
1.1 misho 948: task->task_type = taskUNUSE;
1.4 misho 949: #ifdef HAVE_LIBPTHREAD
950: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
951: #endif
1.1 misho 952: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 953: #ifdef HAVE_LIBPTHREAD
954: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
955: #endif
1.1 misho 956: return task;
957: }
1.3 misho 958:
959: /*
960: * sched_hook_exception() - Default EXCEPTION hook
1.5 misho 961: *
1.3 misho 962: * @root = root task
963: * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
964: * return: <0 errors and 0 ok
965: */
966: void *
967: sched_hook_exception(void *root, void *arg)
968: {
969: sched_root_task_t *r = root;
970:
1.6 misho 971: if (!r)
1.3 misho 972: return NULL;
973:
974: /* custom exception handling ... */
975: if (arg) {
976: if (arg == (void*) EV_EOF)
977: return NULL;
978: return (void*) -1; /* raise scheduler error!!! */
979: }
980:
981: /* if error hook exists */
982: if (r->root_hooks.hook_root.error)
983: return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
984:
985: /* default case! */
986: LOGERR;
987: return NULL;
988: }
1.5 misho 989:
990: /*
991: * sched_hook_condition() - Default CONDITION hook
992: *
993: * @root = root task
994: * @arg = killState from schedRun()
995: * return: NULL kill scheduler loop or !=NULL ok
996: */
997: void *
998: sched_hook_condition(void *root, void *arg)
999: {
1000: sched_root_task_t *r = root;
1001:
1.6 misho 1002: if (!r)
1.5 misho 1003: return NULL;
1004:
1005: return (void*) (r->root_cond - *(intptr_t*) arg);
1006: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>