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