1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: hooks.c,v 1.27 2014/04/27 16:20:37 misho Exp $
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:
15: Copyright 2004 - 2014
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
52: *
53: * @root = root task
54: * @arg = unused
55: * return: <0 errors and 0 ok
56: */
57: void *
58: sched_hook_init(void *root, void *arg __unused)
59: {
60: sched_root_task_t *r = root;
61:
62: if (!r)
63: return (void*) -1;
64:
65: #ifndef KQ_DISABLE
66: r->root_kq = kqueue();
67: if (r->root_kq == -1) {
68: LOGERR;
69: return (void*) -1;
70: }
71: #else
72: r->root_kq ^= r->root_kq;
73: FD_ZERO(&r->root_fds[0]);
74: FD_ZERO(&r->root_fds[1]);
75: #endif
76:
77: return NULL;
78: }
79:
80: /*
81: * sched_hook_fini() - Default FINI hook
82: *
83: * @root = root task
84: * @arg = unused
85: * return: <0 errors and 0 ok
86: */
87: void *
88: sched_hook_fini(void *root, void *arg __unused)
89: {
90: sched_root_task_t *r = root;
91:
92: if (!r)
93: return (void*) -1;
94:
95: #ifndef KQ_DISABLE
96: if (r->root_kq > 2) {
97: close(r->root_kq);
98: r->root_kq = 0;
99: }
100: #else
101: FD_ZERO(&r->root_fds[1]);
102: FD_ZERO(&r->root_fds[0]);
103: r->root_kq ^= r->root_kq;
104: #endif
105:
106: return NULL;
107: }
108:
109: /*
110: * sched_hook_cancel() - Default CANCEL hook
111: *
112: * @task = current task
113: * @arg = unused
114: * return: <0 errors and 0 ok
115: */
116: void *
117: sched_hook_cancel(void *task, void *arg __unused)
118: {
119: sched_task_t *t = task;
120: #ifndef KQ_DISABLE
121: struct kevent chg[1];
122: struct timespec timeout = { 0, 0 };
123: #else
124: sched_root_task_t *r = NULL;
125: register int i;
126: #endif
127: #ifdef AIO_SUPPORT
128: struct aiocb *acb;
129: #ifdef EVFILT_LIO
130: register int i = 0;
131: struct aiocb **acbs;
132: #endif /* EVFILT_LIO */
133: #endif /* AIO_SUPPORT */
134:
135: if (!t || !TASK_ROOT(t))
136: return (void*) -1;
137: #ifdef KQ_DISABLE
138: r = TASK_ROOT(t);
139: #endif
140:
141: switch (TASK_TYPE(t)) {
142: case taskREAD:
143: #ifndef KQ_DISABLE
144: #ifdef __NetBSD__
145: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
146: #else
147: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (void*) TASK_FD(t));
148: #endif
149: #else
150: FD_CLR(TASK_FD(t), &r->root_fds[0]);
151:
152: /* optimize select */
153: for (i = r->root_kq - 1; i > 2; i--)
154: if (FD_ISSET(i, &r->root_fds[0]) || FD_ISSET(i, &r->root_fds[1]))
155: break;
156: if (i > 2)
157: r->root_kq = i + 1;
158: #endif
159: break;
160: case taskWRITE:
161: #ifndef KQ_DISABLE
162: #ifdef __NetBSD__
163: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
164: #else
165: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
166: #endif
167: #else
168: FD_CLR(TASK_FD(t), &r->root_fds[1]);
169:
170: /* optimize select */
171: for (i = r->root_kq - 1; i > 2; i--)
172: if (FD_ISSET(i, &r->root_fds[0]) || FD_ISSET(i, &r->root_fds[1]))
173: break;
174: if (i > 2)
175: r->root_kq = i + 1;
176: #endif
177: break;
178: case taskALARM:
179: #ifndef KQ_DISABLE
180: #ifdef __NetBSD__
181: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE,
182: 0, 0, (intptr_t) TASK_DATA(t));
183: #else
184: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE,
185: 0, 0, (void*) TASK_DATA(t));
186: #endif
187: #endif
188: break;
189: case taskNODE:
190: #ifndef KQ_DISABLE
191: #ifdef __NetBSD__
192: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
193: #else
194: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
195: #endif
196: #endif
197: break;
198: case taskPROC:
199: #ifndef KQ_DISABLE
200: #ifdef __NetBSD__
201: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
202: #else
203: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
204: #endif
205: #endif
206: break;
207: case taskSIGNAL:
208: #ifndef KQ_DISABLE
209: #ifdef __NetBSD__
210: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
211: #else
212: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
213: #endif
214: /* restore signal */
215: signal(TASK_VAL(t), SIG_DFL);
216: #endif
217: break;
218: #ifdef AIO_SUPPORT
219: case taskAIO:
220: #ifndef KQ_DISABLE
221: #ifdef __NetBSD__
222: EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
223: #else
224: EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
225: #endif
226: acb = (struct aiocb*) TASK_VAL(t);
227: if (acb) {
228: if (aio_cancel(acb->aio_fildes, acb) == AIO_CANCELED)
229: aio_return(acb);
230: free(acb);
231: TASK_VAL(t) = 0;
232: }
233: #endif
234: break;
235: #ifdef EVFILT_LIO
236: case taskLIO:
237: #ifndef KQ_DISABLE
238: #ifdef __NetBSD__
239: EV_SET(&chg[0], TASK_VAL(t), EVFILT_LIO, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
240: #else
241: EV_SET(&chg[0], TASK_VAL(t), EVFILT_LIO, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
242: #endif
243: acbs = (struct aiocb**) TASK_VAL(t);
244: if (acbs) {
245: for (i = 0; i < TASK_DATLEN(t); i++) {
246: if (aio_cancel(acbs[i]->aio_fildes, acbs[i]) == AIO_CANCELED)
247: aio_return(acbs[i]);
248: free(acbs[i]);
249: }
250: free(acbs);
251: TASK_VAL(t) = 0;
252: }
253: #endif
254: break;
255: #endif /* EVFILT_LIO */
256: #endif /* AIO_SUPPORT */
257: #ifdef EVFILT_USER
258: case taskUSER:
259: #ifndef KQ_DISABLE
260: #ifdef __NetBSD__
261: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
262: #else
263: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
264: #endif
265: #endif
266: break;
267: #endif /* EVFILT_USER */
268: case taskTHREAD:
269: #ifdef HAVE_LIBPTHREAD
270: pthread_cancel((pthread_t) TASK_VAL(t));
271: #endif
272: return NULL;
273: #if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
274: case taskRTC:
275: timer_delete((timer_t) TASK_FLAG(t));
276: schedCancel((sched_task_t*) TASK_RET(t));
277: return NULL;
278: #endif /* HAVE_TIMER_CREATE */
279: default:
280: return NULL;
281: }
282:
283: #ifndef KQ_DISABLE
284: kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout);
285: #endif
286: return NULL;
287: }
288:
289: #ifdef HAVE_LIBPTHREAD
290: /*
291: * sched_hook_thread() - Default THREAD hook
292: *
293: * @task = current task
294: * @arg = pthread attributes
295: * return: <0 errors and 0 ok
296: */
297: void *
298: sched_hook_thread(void *task, void *arg)
299: {
300: sched_task_t *t = task;
301: pthread_t tid;
302: sigset_t s, o;
303:
304: if (!t || !TASK_ROOT(t))
305: return (void*) -1;
306:
307: sigfillset(&s);
308: pthread_sigmask(SIG_BLOCK, &s, &o);
309: if ((errno = pthread_create(&tid, (pthread_attr_t*) arg,
310: (void *(*)(void*)) _sched_threadWrapper, t))) {
311: LOGERR;
312: pthread_sigmask(SIG_SETMASK, &o, NULL);
313: return (void*) -1;
314: } else
315: TASK_VAL(t) = (u_long) tid;
316:
317: if (!TASK_ISLOCKED(t))
318: TASK_LOCK(t);
319:
320: pthread_sigmask(SIG_SETMASK, &o, NULL);
321: return NULL;
322: }
323: #endif
324:
325: /*
326: * sched_hook_read() - Default READ hook
327: *
328: * @task = current task
329: * @arg = unused
330: * return: <0 errors and 0 ok
331: */
332: void *
333: sched_hook_read(void *task, void *arg __unused)
334: {
335: sched_task_t *t = task;
336: #ifndef KQ_DISABLE
337: struct kevent chg[1];
338: struct timespec timeout = { 0, 0 };
339: #else
340: sched_root_task_t *r = NULL;
341: #endif
342:
343: if (!t || !TASK_ROOT(t))
344: return (void*) -1;
345: #ifdef KQ_DISABLE
346: r = TASK_ROOT(t);
347: #endif
348:
349: #ifndef KQ_DISABLE
350: #ifdef __NetBSD__
351: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
352: #else
353: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
354: #endif
355: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
356: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
357: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
358: else
359: LOGERR;
360: return (void*) -1;
361: }
362: #else
363: FD_SET(TASK_FD(t), &r->root_fds[0]);
364: if (TASK_FD(t) >= r->root_kq)
365: r->root_kq = TASK_FD(t) + 1;
366: #endif
367:
368: return NULL;
369: }
370:
371: /*
372: * sched_hook_write() - Default WRITE hook
373: *
374: * @task = current task
375: * @arg = unused
376: * return: <0 errors and 0 ok
377: */
378: void *
379: sched_hook_write(void *task, void *arg __unused)
380: {
381: sched_task_t *t = task;
382: #ifndef KQ_DISABLE
383: struct kevent chg[1];
384: struct timespec timeout = { 0, 0 };
385: #else
386: sched_root_task_t *r = NULL;
387: #endif
388:
389: if (!t || !TASK_ROOT(t))
390: return (void*) -1;
391: #ifdef KQ_DISABLE
392: r = TASK_ROOT(t);
393: #endif
394:
395: #ifndef KQ_DISABLE
396: #ifdef __NetBSD__
397: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
398: #else
399: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
400: #endif
401: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
402: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
403: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
404: else
405: LOGERR;
406: return (void*) -1;
407: }
408: #else
409: FD_SET(TASK_FD(t), &r->root_fds[1]);
410: if (TASK_FD(t) >= r->root_kq)
411: r->root_kq = TASK_FD(t) + 1;
412: #endif
413:
414: return NULL;
415: }
416:
417: /*
418: * sched_hook_alarm() - Default ALARM hook
419: *
420: * @task = current task
421: * @arg = unused
422: * return: <0 errors and 0 ok
423: */
424: void *
425: sched_hook_alarm(void *task, void *arg __unused)
426: {
427: #ifndef KQ_DISABLE
428: sched_task_t *t = task;
429: struct kevent chg[1];
430: struct timespec timeout = { 0, 0 };
431:
432: if (!t || !TASK_ROOT(t))
433: return (void*) -1;
434:
435: #ifdef __NetBSD__
436: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_CLEAR, 0,
437: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
438: (intptr_t) TASK_DATA(t));
439: #else
440: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_CLEAR, 0,
441: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
442: (void*) TASK_DATA(t));
443: #endif
444: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
445: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
446: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
447: else
448: LOGERR;
449: return (void*) -1;
450: }
451:
452: #endif
453: return NULL;
454: }
455:
456: /*
457: * sched_hook_node() - Default NODE hook
458: *
459: * @task = current task
460: * @arg = unused
461: * return: <0 errors and 0 ok
462: */
463: void *
464: sched_hook_node(void *task, void *arg __unused)
465: {
466: #ifndef KQ_DISABLE
467: sched_task_t *t = task;
468: struct kevent chg[1];
469: struct timespec timeout = { 0, 0 };
470:
471: if (!t || !TASK_ROOT(t))
472: return (void*) -1;
473:
474: #ifdef __NetBSD__
475: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
476: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
477: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (intptr_t) TASK_FD(t));
478: #else
479: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
480: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
481: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (void*) TASK_FD(t));
482: #endif
483: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
484: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
485: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
486: else
487: LOGERR;
488: return (void*) -1;
489: }
490:
491: #endif
492: return NULL;
493: }
494:
495: /*
496: * sched_hook_proc() - Default PROC hook
497: *
498: * @task = current task
499: * @arg = unused
500: * return: <0 errors and 0 ok
501: */
502: void *
503: sched_hook_proc(void *task, void *arg __unused)
504: {
505: #ifndef KQ_DISABLE
506: sched_task_t *t = task;
507: struct kevent chg[1];
508: struct timespec timeout = { 0, 0 };
509:
510: if (!t || !TASK_ROOT(t))
511: return (void*) -1;
512:
513: #ifdef __NetBSD__
514: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
515: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (intptr_t) TASK_VAL(t));
516: #else
517: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
518: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (void*) TASK_VAL(t));
519: #endif
520: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
521: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
522: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
523: else
524: LOGERR;
525: return (void*) -1;
526: }
527:
528: #endif
529: return NULL;
530: }
531:
532: /*
533: * sched_hook_signal() - Default SIGNAL hook
534: *
535: * @task = current task
536: * @arg = unused
537: * return: <0 errors and 0 ok
538: */
539: void *
540: sched_hook_signal(void *task, void *arg __unused)
541: {
542: #ifndef KQ_DISABLE
543: sched_task_t *t = task;
544: struct kevent chg[1];
545: struct timespec timeout = { 0, 0 };
546:
547: if (!t || !TASK_ROOT(t))
548: return (void*) -1;
549:
550: /* ignore signal */
551: signal(TASK_VAL(t), SIG_IGN);
552:
553: #ifdef __NetBSD__
554: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_VAL(t));
555: #else
556: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_VAL(t));
557: #endif
558: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
559: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
560: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
561: else
562: LOGERR;
563: return (void*) -1;
564: }
565: #else
566: #if 0
567: sched_task_t *t = task;
568: struct sigaction sa;
569:
570: memset(&sa, 0, sizeof sa);
571: sigemptyset(&sa.sa_mask);
572: sa.sa_handler = _sched_sigHandler;
573: sa.sa_flags = SA_RESETHAND | SA_RESTART;
574:
575: if (sigaction(TASK_VAL(t), &sa, NULL) == -1) {
576: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
577: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
578: else
579: LOGERR;
580: return (void*) -1;
581: }
582: #endif /* 0 */
583: #endif
584: return NULL;
585: }
586:
587: /*
588: * sched_hook_user() - Default USER hook
589: *
590: * @task = current task
591: * @arg = unused
592: * return: <0 errors and 0 ok
593: */
594: #ifdef EVFILT_USER
595: void *
596: sched_hook_user(void *task, void *arg __unused)
597: {
598: #ifndef KQ_DISABLE
599: sched_task_t *t = task;
600: struct kevent chg[1];
601: struct timespec timeout = { 0, 0 };
602:
603: if (!t || !TASK_ROOT(t))
604: return (void*) -1;
605:
606: #ifdef __NetBSD__
607: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
608: 0, (intptr_t) TASK_VAL(t));
609: #else
610: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
611: 0, (void*) TASK_VAL(t));
612: #endif
613: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
614: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
615: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
616: else
617: LOGERR;
618: return (void*) -1;
619: }
620:
621: #endif
622: return NULL;
623: }
624: #endif
625:
626: /*
627: * sched_hook_fetch() - Default FETCH hook
628: *
629: * @root = root task
630: * @arg = unused
631: * return: NULL error or !=NULL fetched task
632: */
633: void *
634: sched_hook_fetch(void *root, void *arg __unused)
635: {
636: sched_root_task_t *r = root;
637: sched_task_t *task, *tmp;
638: struct timespec now, m, mtmp;
639: #ifndef KQ_DISABLE
640: struct kevent evt[1], res[KQ_EVENTS];
641: struct timespec *timeout;
642: #else
643: struct timeval *timeout, tv;
644: fd_set rfd, wfd, xfd;
645: #endif
646: register int i, flg;
647: int en;
648: #ifdef AIO_SUPPORT
649: int len, fd;
650: struct aiocb *acb;
651: #ifdef EVFILT_LIO
652: int l;
653: register int j;
654: off_t off;
655: struct aiocb **acbs;
656: struct iovec *iv;
657: #endif /* EVFILT_LIO */
658: #endif /* AIO_SUPPORT */
659:
660: if (!r)
661: return NULL;
662:
663: /* get new task by queue priority */
664: while ((task = TAILQ_FIRST(&r->root_event))) {
665: #ifdef HAVE_LIBPTHREAD
666: pthread_mutex_lock(&r->root_mtx[taskEVENT]);
667: #endif
668: TAILQ_REMOVE(&r->root_event, task, task_node);
669: #ifdef HAVE_LIBPTHREAD
670: pthread_mutex_unlock(&r->root_mtx[taskEVENT]);
671: #endif
672: task->task_type = taskUNUSE;
673: #ifdef HAVE_LIBPTHREAD
674: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
675: #endif
676: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
677: #ifdef HAVE_LIBPTHREAD
678: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
679: #endif
680: return task;
681: }
682: while ((task = TAILQ_FIRST(&r->root_ready))) {
683: #ifdef HAVE_LIBPTHREAD
684: pthread_mutex_lock(&r->root_mtx[taskREADY]);
685: #endif
686: TAILQ_REMOVE(&r->root_ready, task, task_node);
687: #ifdef HAVE_LIBPTHREAD
688: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
689: #endif
690: task->task_type = taskUNUSE;
691: #ifdef HAVE_LIBPTHREAD
692: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
693: #endif
694: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
695: #ifdef HAVE_LIBPTHREAD
696: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
697: #endif
698: return task;
699: }
700:
701: #ifdef TIMER_WITHOUT_SORT
702: clock_gettime(CLOCK_MONOTONIC, &now);
703:
704: sched_timespecclear(&r->root_wait);
705: TAILQ_FOREACH(task, &r->root_timer, task_node) {
706: if (!sched_timespecisset(&r->root_wait))
707: r->root_wait = TASK_TS(task);
708: else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
709: r->root_wait = TASK_TS(task);
710: }
711:
712: if (TAILQ_FIRST(&r->root_timer)) {
713: m = r->root_wait;
714: sched_timespecsub(&m, &now, &mtmp);
715: r->root_wait = mtmp;
716: } else {
717: /* set wait INFTIM */
718: sched_timespecinf(&r->root_wait);
719: }
720: #else /* ! TIMER_WITHOUT_SORT */
721: if (!TAILQ_FIRST(&r->root_task) && (task = TAILQ_FIRST(&r->root_timer))) {
722: clock_gettime(CLOCK_MONOTONIC, &now);
723:
724: m = TASK_TS(task);
725: sched_timespecsub(&m, &now, &mtmp);
726: r->root_wait = mtmp;
727: } else {
728: /* set wait INFTIM */
729: sched_timespecinf(&r->root_wait);
730: }
731: #endif /* TIMER_WITHOUT_SORT */
732: /* if present member of task, set NOWAIT */
733: if (TAILQ_FIRST(&r->root_task))
734: sched_timespecclear(&r->root_wait);
735:
736: if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1) {
737: #ifndef KQ_DISABLE
738: timeout = &r->root_wait;
739: #else
740: sched_timespec2val(&r->root_wait, &tv);
741: timeout = &tv;
742: #endif /* KQ_DISABLE */
743: } else if (sched_timespecisinf(&r->root_poll))
744: timeout = NULL;
745: else {
746: #ifndef KQ_DISABLE
747: timeout = &r->root_poll;
748: #else
749: sched_timespec2val(&r->root_poll, &tv);
750: timeout = &tv;
751: #endif /* KQ_DISABLE */
752: }
753:
754: #ifndef KQ_DISABLE
755: if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
756: #else
757: rfd = xfd = r->root_fds[0];
758: wfd = r->root_fds[1];
759: if ((en = select(r->root_kq, &rfd, &wfd, &xfd, timeout)) == -1) {
760: #endif /* KQ_DISABLE */
761: if (r->root_hooks.hook_exec.exception) {
762: if (r->root_hooks.hook_exec.exception(r, NULL))
763: return NULL;
764: } else if (errno != EINTR)
765: LOGERR;
766: goto skip_event;
767: }
768:
769: /* kevent dispatcher */
770: now.tv_sec = now.tv_nsec = 0;
771: /* Go and catch the cat into pipes ... */
772: #ifndef KQ_DISABLE
773: for (i = 0; i < en; i++) {
774: memcpy(evt, &res[i], sizeof evt);
775: evt->flags = EV_DELETE;
776: /* Put read/write task to ready queue */
777: switch (res[i].filter) {
778: case EVFILT_READ:
779: flg = 0;
780: TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) {
781: if (TASK_FD(task) != ((intptr_t) res[i].udata))
782: continue;
783: else {
784: flg++;
785: TASK_RET(task) = res[i].data;
786: TASK_FLAG(task) = (u_long) res[i].fflags;
787: }
788: /* remove read handle */
789: #ifdef HAVE_LIBPTHREAD
790: pthread_mutex_lock(&r->root_mtx[taskREAD]);
791: #endif
792: TAILQ_REMOVE(&r->root_read, task, task_node);
793: #ifdef HAVE_LIBPTHREAD
794: pthread_mutex_unlock(&r->root_mtx[taskREAD]);
795: #endif
796: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
797: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
798: task->task_type = taskUNUSE;
799: #ifdef HAVE_LIBPTHREAD
800: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
801: #endif
802: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
803: #ifdef HAVE_LIBPTHREAD
804: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
805: #endif
806: } else {
807: task->task_type = taskREADY;
808: #ifdef HAVE_LIBPTHREAD
809: pthread_mutex_lock(&r->root_mtx[taskREADY]);
810: #endif
811: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
812: #ifdef HAVE_LIBPTHREAD
813: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
814: #endif
815: }
816: } else {
817: task->task_type = taskREADY;
818: #ifdef HAVE_LIBPTHREAD
819: pthread_mutex_lock(&r->root_mtx[taskREADY]);
820: #endif
821: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
822: #ifdef HAVE_LIBPTHREAD
823: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
824: #endif
825: }
826: }
827: /* if match at least 2, don't remove resouce of event */
828: if (flg > 1)
829: evt->flags ^= evt->flags;
830: break;
831: case EVFILT_WRITE:
832: flg = 0;
833: TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) {
834: if (TASK_FD(task) != ((intptr_t) res[i].udata))
835: continue;
836: else {
837: flg++;
838: TASK_RET(task) = res[i].data;
839: TASK_FLAG(task) = (u_long) res[i].fflags;
840: }
841: /* remove write handle */
842: #ifdef HAVE_LIBPTHREAD
843: pthread_mutex_lock(&r->root_mtx[taskWRITE]);
844: #endif
845: TAILQ_REMOVE(&r->root_write, task, task_node);
846: #ifdef HAVE_LIBPTHREAD
847: pthread_mutex_unlock(&r->root_mtx[taskWRITE]);
848: #endif
849: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
850: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
851: task->task_type = taskUNUSE;
852: #ifdef HAVE_LIBPTHREAD
853: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
854: #endif
855: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
856: #ifdef HAVE_LIBPTHREAD
857: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
858: #endif
859: } else {
860: task->task_type = taskREADY;
861: #ifdef HAVE_LIBPTHREAD
862: pthread_mutex_lock(&r->root_mtx[taskREADY]);
863: #endif
864: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
865: #ifdef HAVE_LIBPTHREAD
866: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
867: #endif
868: }
869: } else {
870: task->task_type = taskREADY;
871: #ifdef HAVE_LIBPTHREAD
872: pthread_mutex_lock(&r->root_mtx[taskREADY]);
873: #endif
874: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
875: #ifdef HAVE_LIBPTHREAD
876: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
877: #endif
878: }
879: }
880: /* if match at least 2, don't remove resouce of event */
881: if (flg > 1)
882: evt->flags ^= evt->flags;
883: break;
884: case EVFILT_TIMER:
885: flg = 0;
886: TAILQ_FOREACH_SAFE(task, &r->root_alarm, task_node, tmp) {
887: if ((uintptr_t) TASK_DATA(task) != ((uintptr_t) res[i].udata))
888: continue;
889: else {
890: flg++;
891: TASK_RET(task) = res[i].data;
892: TASK_FLAG(task) = (u_long) res[i].fflags;
893: }
894: /* remove alarm handle */
895: #ifdef HAVE_LIBPTHREAD
896: pthread_mutex_lock(&r->root_mtx[taskALARM]);
897: #endif
898: TAILQ_REMOVE(&r->root_alarm, task, task_node);
899: #ifdef HAVE_LIBPTHREAD
900: pthread_mutex_unlock(&r->root_mtx[taskALARM]);
901: #endif
902: task->task_type = taskREADY;
903: #ifdef HAVE_LIBPTHREAD
904: pthread_mutex_lock(&r->root_mtx[taskREADY]);
905: #endif
906: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
907: #ifdef HAVE_LIBPTHREAD
908: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
909: #endif
910: }
911: /* if match at least 2, don't remove resouce of event */
912: if (flg > 1)
913: evt->flags ^= evt->flags;
914: break;
915: case EVFILT_VNODE:
916: flg = 0;
917: TAILQ_FOREACH_SAFE(task, &r->root_node, task_node, tmp) {
918: if (TASK_FD(task) != ((intptr_t) res[i].udata))
919: continue;
920: else {
921: flg++;
922: TASK_RET(task) = res[i].data;
923: TASK_FLAG(task) = (u_long) res[i].fflags;
924: }
925: /* remove node handle */
926: #ifdef HAVE_LIBPTHREAD
927: pthread_mutex_lock(&r->root_mtx[taskNODE]);
928: #endif
929: TAILQ_REMOVE(&r->root_node, task, task_node);
930: #ifdef HAVE_LIBPTHREAD
931: pthread_mutex_unlock(&r->root_mtx[taskNODE]);
932: #endif
933: task->task_type = taskREADY;
934: #ifdef HAVE_LIBPTHREAD
935: pthread_mutex_lock(&r->root_mtx[taskREADY]);
936: #endif
937: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
938: #ifdef HAVE_LIBPTHREAD
939: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
940: #endif
941: }
942: /* if match at least 2, don't remove resouce of event */
943: if (flg > 1)
944: evt->flags ^= evt->flags;
945: break;
946: case EVFILT_PROC:
947: flg = 0;
948: TAILQ_FOREACH_SAFE(task, &r->root_proc, task_node, tmp) {
949: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
950: continue;
951: else {
952: flg++;
953: TASK_RET(task) = res[i].data;
954: TASK_FLAG(task) = (u_long) res[i].fflags;
955: }
956: /* remove proc handle */
957: #ifdef HAVE_LIBPTHREAD
958: pthread_mutex_lock(&r->root_mtx[taskPROC]);
959: #endif
960: TAILQ_REMOVE(&r->root_proc, task, task_node);
961: #ifdef HAVE_LIBPTHREAD
962: pthread_mutex_unlock(&r->root_mtx[taskPROC]);
963: #endif
964: task->task_type = taskREADY;
965: #ifdef HAVE_LIBPTHREAD
966: pthread_mutex_lock(&r->root_mtx[taskREADY]);
967: #endif
968: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
969: #ifdef HAVE_LIBPTHREAD
970: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
971: #endif
972: }
973: /* if match at least 2, don't remove resouce of event */
974: if (flg > 1)
975: evt->flags ^= evt->flags;
976: break;
977: case EVFILT_SIGNAL:
978: flg = 0;
979: TAILQ_FOREACH_SAFE(task, &r->root_signal, task_node, tmp) {
980: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
981: continue;
982: else {
983: flg++;
984: TASK_RET(task) = res[i].data;
985: TASK_FLAG(task) = (u_long) res[i].fflags;
986: }
987: /* remove signal handle */
988: #ifdef HAVE_LIBPTHREAD
989: pthread_mutex_lock(&r->root_mtx[taskSIGNAL]);
990: #endif
991: TAILQ_REMOVE(&r->root_signal, task, task_node);
992: #ifdef HAVE_LIBPTHREAD
993: pthread_mutex_unlock(&r->root_mtx[taskSIGNAL]);
994: #endif
995: task->task_type = taskREADY;
996: #ifdef HAVE_LIBPTHREAD
997: pthread_mutex_lock(&r->root_mtx[taskREADY]);
998: #endif
999: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1000: #ifdef HAVE_LIBPTHREAD
1001: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1002: #endif
1003: }
1004: /* if match at least 2, don't remove resouce of event */
1005: if (flg > 1)
1006: evt->flags ^= evt->flags;
1007: break;
1008: #ifdef AIO_SUPPORT
1009: case EVFILT_AIO:
1010: flg = 0;
1011: TAILQ_FOREACH_SAFE(task, &r->root_aio, task_node, tmp) {
1012: acb = (struct aiocb*) TASK_VAL(task);
1013: if (acb != ((struct aiocb*) res[i].udata))
1014: continue;
1015: else {
1016: flg++;
1017: TASK_RET(task) = res[i].data;
1018: TASK_FLAG(task) = (u_long) res[i].fflags;
1019: }
1020: /* remove user handle */
1021: #ifdef HAVE_LIBPTHREAD
1022: pthread_mutex_lock(&r->root_mtx[taskAIO]);
1023: #endif
1024: TAILQ_REMOVE(&r->root_aio, task, task_node);
1025: #ifdef HAVE_LIBPTHREAD
1026: pthread_mutex_unlock(&r->root_mtx[taskAIO]);
1027: #endif
1028: task->task_type = taskREADY;
1029: #ifdef HAVE_LIBPTHREAD
1030: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1031: #endif
1032: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1033: #ifdef HAVE_LIBPTHREAD
1034: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1035: #endif
1036: fd = acb->aio_fildes;
1037: if ((len = aio_return(acb)) != -1) {
1038: if (lseek(fd, acb->aio_offset + len, SEEK_CUR) == -1)
1039: LOGERR;
1040: } else
1041: LOGERR;
1042: free(acb);
1043: TASK_DATLEN(task) = (u_long) len;
1044: TASK_FD(task) = fd;
1045: }
1046: /* if match at least 2, don't remove resouce of event */
1047: if (flg > 1)
1048: evt->flags ^= evt->flags;
1049: break;
1050: #ifdef EVFILT_LIO
1051: case EVFILT_LIO:
1052: flg = 0;
1053: TAILQ_FOREACH_SAFE(task, &r->root_lio, task_node, tmp) {
1054: acbs = (struct aiocb**) TASK_VAL(task);
1055: if (acbs != ((struct aiocb**) res[i].udata))
1056: continue;
1057: else {
1058: flg++;
1059: TASK_RET(task) = res[i].data;
1060: TASK_FLAG(task) = (u_long) res[i].fflags;
1061: }
1062: /* remove user handle */
1063: #ifdef HAVE_LIBPTHREAD
1064: pthread_mutex_lock(&r->root_mtx[taskLIO]);
1065: #endif
1066: TAILQ_REMOVE(&r->root_lio, task, task_node);
1067: #ifdef HAVE_LIBPTHREAD
1068: pthread_mutex_unlock(&r->root_mtx[taskLIO]);
1069: #endif
1070: task->task_type = taskREADY;
1071: #ifdef HAVE_LIBPTHREAD
1072: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1073: #endif
1074: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1075: #ifdef HAVE_LIBPTHREAD
1076: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1077: #endif
1078: iv = (struct iovec*) TASK_DATA(task);
1079: fd = acbs[0]->aio_fildes;
1080: off = acbs[0]->aio_offset;
1081: for (j = len = 0; i < TASK_DATLEN(task); len += l, i++) {
1082: if ((iv[i].iov_len = aio_return(acbs[i])) == -1)
1083: l = 0;
1084: else
1085: l = iv[i].iov_len;
1086: free(acbs[i]);
1087: }
1088: free(acbs);
1089: TASK_DATLEN(task) = (u_long) len;
1090: TASK_FD(task) = fd;
1091:
1092: if (lseek(fd, off + len, SEEK_CUR) == -1)
1093: LOGERR;
1094: }
1095: /* if match at least 2, don't remove resouce of event */
1096: if (flg > 1)
1097: evt->flags ^= evt->flags;
1098: break;
1099: #endif /* EVFILT_LIO */
1100: #endif /* AIO_SUPPORT */
1101: #ifdef EVFILT_USER
1102: case EVFILT_USER:
1103: flg = 0;
1104: TAILQ_FOREACH_SAFE(task, &r->root_user, task_node, tmp) {
1105: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
1106: continue;
1107: else {
1108: flg++;
1109: TASK_RET(task) = res[i].data;
1110: TASK_FLAG(task) = (u_long) res[i].fflags;
1111: }
1112: /* remove user handle */
1113: #ifdef HAVE_LIBPTHREAD
1114: pthread_mutex_lock(&r->root_mtx[taskUSER]);
1115: #endif
1116: TAILQ_REMOVE(&r->root_user, task, task_node);
1117: #ifdef HAVE_LIBPTHREAD
1118: pthread_mutex_unlock(&r->root_mtx[taskUSER]);
1119: #endif
1120: task->task_type = taskREADY;
1121: #ifdef HAVE_LIBPTHREAD
1122: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1123: #endif
1124: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1125: #ifdef HAVE_LIBPTHREAD
1126: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1127: #endif
1128: }
1129: /* if match at least 2, don't remove resouce of event */
1130: if (flg > 1)
1131: evt->flags ^= evt->flags;
1132: break;
1133: #endif /* EVFILT_USER */
1134: }
1135: if (kevent(r->root_kq, evt, 1, NULL, 0, &now) == -1) {
1136: if (r->root_hooks.hook_exec.exception) {
1137: if (r->root_hooks.hook_exec.exception(r, NULL))
1138: return NULL;
1139: } else
1140: LOGERR;
1141: }
1142: }
1143: #else /* end of kevent dispatcher */
1144: for (i = 0; i < r->root_kq; i++) {
1145: if (FD_ISSET(i, &rfd) || FD_ISSET(i, &xfd)) {
1146: flg = 0;
1147: TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) {
1148: if (TASK_FD(task) != i)
1149: continue;
1150: else {
1151: flg++;
1152: TASK_FLAG(task) = ioctl(TASK_FD(task),
1153: FIONREAD, &TASK_RET(task));
1154: }
1155: /* remove read handle */
1156: #ifdef HAVE_LIBPTHREAD
1157: pthread_mutex_lock(&r->root_mtx[taskREAD]);
1158: #endif
1159: TAILQ_REMOVE(&r->root_read, task, task_node);
1160: #ifdef HAVE_LIBPTHREAD
1161: pthread_mutex_unlock(&r->root_mtx[taskREAD]);
1162: #endif
1163: if (r->root_hooks.hook_exec.exception) {
1164: if (r->root_hooks.hook_exec.exception(r, NULL)) {
1165: task->task_type = taskUNUSE;
1166: #ifdef HAVE_LIBPTHREAD
1167: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
1168: #endif
1169: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1170: #ifdef HAVE_LIBPTHREAD
1171: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
1172: #endif
1173: } else {
1174: task->task_type = taskREADY;
1175: #ifdef HAVE_LIBPTHREAD
1176: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1177: #endif
1178: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1179: #ifdef HAVE_LIBPTHREAD
1180: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1181: #endif
1182: }
1183: } else {
1184: task->task_type = taskREADY;
1185: #ifdef HAVE_LIBPTHREAD
1186: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1187: #endif
1188: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1189: #ifdef HAVE_LIBPTHREAD
1190: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1191: #endif
1192: }
1193: }
1194: /* if match equal to 1, remove resouce */
1195: if (flg == 1)
1196: FD_CLR(i, &r->root_fds[0]);
1197: }
1198:
1199: if (FD_ISSET(i, &wfd)) {
1200: flg = 0;
1201: TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) {
1202: if (TASK_FD(task) != i)
1203: continue;
1204: else {
1205: flg++;
1206: TASK_FLAG(task) = ioctl(TASK_FD(task),
1207: FIONWRITE, &TASK_RET(task));
1208: }
1209: /* remove write handle */
1210: #ifdef HAVE_LIBPTHREAD
1211: pthread_mutex_lock(&r->root_mtx[taskWRITE]);
1212: #endif
1213: TAILQ_REMOVE(&r->root_write, task, task_node);
1214: #ifdef HAVE_LIBPTHREAD
1215: pthread_mutex_unlock(&r->root_mtx[taskWRITE]);
1216: #endif
1217: if (r->root_hooks.hook_exec.exception) {
1218: if (r->root_hooks.hook_exec.exception(r, NULL)) {
1219: task->task_type = taskUNUSE;
1220: #ifdef HAVE_LIBPTHREAD
1221: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
1222: #endif
1223: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1224: #ifdef HAVE_LIBPTHREAD
1225: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
1226: #endif
1227: } else {
1228: task->task_type = taskREADY;
1229: #ifdef HAVE_LIBPTHREAD
1230: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1231: #endif
1232: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1233: #ifdef HAVE_LIBPTHREAD
1234: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1235: #endif
1236: }
1237: } else {
1238: task->task_type = taskREADY;
1239: #ifdef HAVE_LIBPTHREAD
1240: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1241: #endif
1242: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1243: #ifdef HAVE_LIBPTHREAD
1244: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1245: #endif
1246: }
1247: }
1248: /* if match equal to 1, remove resouce */
1249: if (flg == 1)
1250: FD_CLR(i, &r->root_fds[1]);
1251: }
1252: }
1253:
1254: /* optimize select */
1255: for (i = r->root_kq - 1; i > 2; i--)
1256: if (FD_ISSET(i, &r->root_fds[0]) || FD_ISSET(i, &r->root_fds[1]))
1257: break;
1258: if (i > 2)
1259: r->root_kq = i + 1;
1260: #endif /* KQ_DISABLE */
1261:
1262: skip_event:
1263: /* timer update & put in ready queue */
1264: clock_gettime(CLOCK_MONOTONIC, &now);
1265:
1266: TAILQ_FOREACH_SAFE(task, &r->root_timer, task_node, tmp)
1267: if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0) {
1268: #ifdef HAVE_LIBPTHREAD
1269: pthread_mutex_lock(&r->root_mtx[taskTIMER]);
1270: #endif
1271: TAILQ_REMOVE(&r->root_timer, task, task_node);
1272: #ifdef HAVE_LIBPTHREAD
1273: pthread_mutex_unlock(&r->root_mtx[taskTIMER]);
1274: #endif
1275: task->task_type = taskREADY;
1276: #ifdef HAVE_LIBPTHREAD
1277: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1278: #endif
1279: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1280: #ifdef HAVE_LIBPTHREAD
1281: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1282: #endif
1283: }
1284:
1285: /* put regular task priority task to ready queue,
1286: if there is no ready task or reach max missing hit for regular task */
1287: if ((task = TAILQ_FIRST(&r->root_task))) {
1288: if (!TAILQ_FIRST(&r->root_ready) || r->root_miss >= TASK_VAL(task)) {
1289: r->root_miss ^= r->root_miss;
1290:
1291: #ifdef HAVE_LIBPTHREAD
1292: pthread_mutex_lock(&r->root_mtx[taskTASK]);
1293: #endif
1294: TAILQ_REMOVE(&r->root_task, task, task_node);
1295: #ifdef HAVE_LIBPTHREAD
1296: pthread_mutex_unlock(&r->root_mtx[taskTASK]);
1297: #endif
1298: task->task_type = taskREADY;
1299: #ifdef HAVE_LIBPTHREAD
1300: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1301: #endif
1302: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1303: #ifdef HAVE_LIBPTHREAD
1304: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1305: #endif
1306: } else
1307: r->root_miss++;
1308: } else
1309: r->root_miss ^= r->root_miss;
1310:
1311: /* OK, lets get ready task !!! */
1312: task = TAILQ_FIRST(&r->root_ready);
1313: if (!(task))
1314: return NULL;
1315:
1316: #ifdef HAVE_LIBPTHREAD
1317: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1318: #endif
1319: TAILQ_REMOVE(&r->root_ready, task, task_node);
1320: #ifdef HAVE_LIBPTHREAD
1321: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1322: #endif
1323: task->task_type = taskUNUSE;
1324: #ifdef HAVE_LIBPTHREAD
1325: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
1326: #endif
1327: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1328: #ifdef HAVE_LIBPTHREAD
1329: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
1330: #endif
1331: return task;
1332: }
1333:
1334: /*
1335: * sched_hook_exception() - Default EXCEPTION hook
1336: *
1337: * @root = root task
1338: * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
1339: * return: <0 errors and 0 ok
1340: */
1341: void *
1342: sched_hook_exception(void *root, void *arg)
1343: {
1344: sched_root_task_t *r = root;
1345:
1346: if (!r)
1347: return NULL;
1348:
1349: /* custom exception handling ... */
1350: if (arg) {
1351: if (arg == (void*) EV_EOF)
1352: return NULL;
1353: return (void*) -1; /* raise scheduler error!!! */
1354: }
1355:
1356: /* if error hook exists */
1357: if (r->root_hooks.hook_root.error)
1358: return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
1359:
1360: /* default case! */
1361: LOGERR;
1362: return NULL;
1363: }
1364:
1365: /*
1366: * sched_hook_condition() - Default CONDITION hook
1367: *
1368: * @root = root task
1369: * @arg = killState from schedRun()
1370: * return: NULL kill scheduler loop or !=NULL ok
1371: */
1372: void *
1373: sched_hook_condition(void *root, void *arg)
1374: {
1375: sched_root_task_t *r = root;
1376:
1377: if (!r)
1378: return NULL;
1379:
1380: return (void*) (r->root_cond - *(intptr_t*) arg);
1381: }
1382:
1383: /*
1384: * sched_hook_rtc() - Default RTC hook
1385: *
1386: * @task = current task
1387: * @arg = unused
1388: * return: <0 errors and 0 ok
1389: */
1390: #if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
1391: void *
1392: sched_hook_rtc(void *task, void *arg __unused)
1393: {
1394: sched_task_t *sigt = NULL, *t = task;
1395: struct itimerspec its;
1396: struct sigevent evt;
1397: timer_t tmr;
1398:
1399: if (!t || !TASK_ROOT(t))
1400: return (void*) -1;
1401:
1402: memset(&evt, 0, sizeof evt);
1403: evt.sigev_notify = SIGEV_SIGNAL;
1404: evt.sigev_signo = (intptr_t) TASK_DATA(t) + SIGRTMIN;
1405: evt.sigev_value.sival_ptr = TASK_DATA(t);
1406:
1407: if (timer_create(CLOCK_MONOTONIC, &evt, &tmr) == -1) {
1408: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1409: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1410: else
1411: LOGERR;
1412: return (void*) -1;
1413: } else
1414: TASK_FLAG(t) = (u_long) tmr;
1415:
1416: if (!(sigt = schedSignal(TASK_ROOT(t), _sched_rtcWrapper, TASK_ARG(t), evt.sigev_signo,
1417: t, (size_t) tmr))) {
1418: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1419: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1420: else
1421: LOGERR;
1422: timer_delete(tmr);
1423: return (void*) -1;
1424: } else
1425: TASK_RET(t) = (uintptr_t) sigt;
1426:
1427: memset(&its, 0, sizeof its);
1428: its.it_value.tv_sec = t->task_val.ts.tv_sec;
1429: its.it_value.tv_nsec = t->task_val.ts.tv_nsec;
1430:
1431: if (timer_settime(tmr, TIMER_RELTIME, &its, NULL) == -1) {
1432: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1433: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1434: else
1435: LOGERR;
1436: schedCancel(sigt);
1437: timer_delete(tmr);
1438: return (void*) -1;
1439: }
1440:
1441: return NULL;
1442: }
1443: #endif /* HAVE_TIMER_CREATE */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>