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