Annotation of libaitsched/src/hooks.c, revision 1.33
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.33 ! misho 6: * $Id: hooks.c,v 1.32.2.1 2017/09/07 12:36:47 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.32 misho 15: Copyright 2004 - 2017
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);
1.32 misho 248: ee.events ^= ee.events;
1.28 misho 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
1.32 misho 255: ee.events |= EPOLLIN | EPOLLPRI;
1.28 misho 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: }
1.25 misho 267: #endif
1.1 misho 268: break;
269: case taskWRITE:
1.28 misho 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
1.2 misho 278: #ifdef __NetBSD__
1.28 misho 279: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, flg < 2 ? EV_DELETE : 0,
280: 0, 0, (intptr_t) TASK_FD(t));
1.2 misho 281: #else
1.28 misho 282: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, flg < 2 ? EV_DELETE : 0,
283: 0, 0, (void*) TASK_FD(t));
1.2 misho 284: #endif
1.28 misho 285: #elif SUP_ENABLE == EP_SUPPORT
286: ee.data.fd = TASK_FD(t);
1.32 misho 287: ee.events ^= ee.events;
1.28 misho 288: if (FD_ISSET(TASK_FD(t), &r->root_fds[0]))
1.32 misho 289: ee.events = EPOLLIN | EPOLLPRI;
1.28 misho 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: }
1.25 misho 306: #endif
1.1 misho 307: break;
1.7 misho 308: case taskALARM:
1.28 misho 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++;
1.7 misho 317: #ifdef __NetBSD__
1.28 misho 318: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, flg < 2 ? EV_DELETE : 0,
1.7 misho 319: 0, 0, (intptr_t) TASK_DATA(t));
320: #else
1.28 misho 321: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, flg < 2 ? EV_DELETE : 0,
1.7 misho 322: 0, 0, (void*) TASK_DATA(t));
323: #endif
1.25 misho 324: #endif
1.8 misho 325: break;
326: case taskNODE:
1.28 misho 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++;
1.8 misho 335: #ifdef __NetBSD__
1.28 misho 336: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, flg < 2 ? EV_DELETE : 0,
337: 0, 0, (intptr_t) TASK_FD(t));
1.8 misho 338: #else
1.28 misho 339: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, flg < 2 ? EV_DELETE : 0,
340: 0, 0, (void*) TASK_FD(t));
1.8 misho 341: #endif
1.25 misho 342: #endif
1.8 misho 343: break;
344: case taskPROC:
1.28 misho 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++;
1.8 misho 353: #ifdef __NetBSD__
1.28 misho 354: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, flg < 2 ? EV_DELETE : 0,
355: 0, 0, (intptr_t) TASK_VAL(t));
1.8 misho 356: #else
1.28 misho 357: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, flg < 2 ? EV_DELETE : 0,
358: 0, 0, (void*) TASK_VAL(t));
1.8 misho 359: #endif
1.25 misho 360: #endif
1.8 misho 361: break;
362: case taskSIGNAL:
1.28 misho 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++;
1.8 misho 371: #ifdef __NetBSD__
1.28 misho 372: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, flg < 2 ? EV_DELETE : 0,
373: 0, 0, (intptr_t) TASK_VAL(t));
1.8 misho 374: #else
1.28 misho 375: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, flg < 2 ? EV_DELETE : 0,
376: 0, 0, (void*) TASK_VAL(t));
1.8 misho 377: #endif
1.18 misho 378: /* restore signal */
1.28 misho 379: if (flg < 2)
380: signal(TASK_VAL(t), SIG_DFL);
1.25 misho 381: #endif
1.8 misho 382: break;
1.11 misho 383: #ifdef AIO_SUPPORT
384: case taskAIO:
1.28 misho 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++;
1.11 misho 393: #ifdef __NetBSD__
1.28 misho 394: EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, flg < 2 ? EV_DELETE : 0,
395: 0, 0, (intptr_t) TASK_VAL(t));
1.11 misho 396: #else
1.28 misho 397: EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, flg < 2 ? EV_DELETE : 0,
398: 0, 0, (void*) TASK_VAL(t));
1.11 misho 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: }
1.25 misho 407: #endif
1.11 misho 408: break;
409: #ifdef EVFILT_LIO
410: case taskLIO:
1.28 misho 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++;
1.11 misho 419: #ifdef __NetBSD__
1.28 misho 420: EV_SET(&chg[0], TASK_VAL(t), EVFILT_LIO, flg < 2 ? EV_DELETE : 0,
421: 0, 0, (intptr_t) TASK_VAL(t));
1.11 misho 422: #else
1.28 misho 423: EV_SET(&chg[0], TASK_VAL(t), EVFILT_LIO, flg < 2 ? EV_DELETE : 0,
424: 0, 0, (void*) TASK_VAL(t));
1.11 misho 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: }
1.25 misho 436: #endif
1.11 misho 437: break;
438: #endif /* EVFILT_LIO */
439: #endif /* AIO_SUPPORT */
1.8 misho 440: #ifdef EVFILT_USER
441: case taskUSER:
1.28 misho 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++;
1.8 misho 450: #ifdef __NetBSD__
1.28 misho 451: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, flg < 2 ? EV_DELETE : 0,
452: 0, 0, (intptr_t) TASK_VAL(t));
1.8 misho 453: #else
1.28 misho 454: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, flg < 2 ? EV_DELETE : 0,
455: 0, 0, (void*) TASK_VAL(t));
1.8 misho 456: #endif
1.25 misho 457: #endif
1.10 misho 458: break;
1.19 misho 459: #endif /* EVFILT_USER */
1.14 misho 460: case taskTHREAD:
461: #ifdef HAVE_LIBPTHREAD
1.28 misho 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: }
1.14 misho 470: #endif
1.19 misho 471: return NULL;
1.29 misho 472: #if defined(HAVE_LIBRT) && defined(HAVE_TIMER_CREATE) && \
473: defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
1.19 misho 474: case taskRTC:
475: timer_delete((timer_t) TASK_FLAG(t));
1.28 misho 476: #if SUP_ENABLE == KQ_SUPPORT
1.19 misho 477: schedCancel((sched_task_t*) TASK_RET(t));
1.28 misho 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
1.19 misho 491: return NULL;
492: #endif /* HAVE_TIMER_CREATE */
1.1 misho 493: default:
1.8 misho 494: return NULL;
1.1 misho 495: }
496:
1.28 misho 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);
1.25 misho 501: #endif
1.1 misho 502: return NULL;
503: }
504:
1.14 misho 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;
1.15 misho 518: sigset_t s, o;
1.14 misho 519:
520: if (!t || !TASK_ROOT(t))
521: return (void*) -1;
522:
1.15 misho 523: sigfillset(&s);
524: pthread_sigmask(SIG_BLOCK, &s, &o);
1.28 misho 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) {
1.14 misho 530: LOGERR;
531: return (void*) -1;
1.15 misho 532: } else
533: TASK_VAL(t) = (u_long) tid;
1.14 misho 534:
535: if (!TASK_ISLOCKED(t))
536: TASK_LOCK(t);
537:
538: return NULL;
539: }
540: #endif
541:
1.1 misho 542: /*
543: * sched_hook_read() - Default READ hook
1.5 misho 544: *
1.1 misho 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;
1.28 misho 553: sched_root_task_t *r = NULL;
554: #if SUP_ENABLE == KQ_SUPPORT
1.1 misho 555: struct kevent chg[1];
1.2 misho 556: struct timespec timeout = { 0, 0 };
1.28 misho 557: #elif SUP_ENABLE == EP_SUPPORT
1.32 misho 558: struct epoll_event ee;
1.28 misho 559: int flg = 0;
1.25 misho 560: #endif
1.1 misho 561:
1.6 misho 562: if (!t || !TASK_ROOT(t))
1.1 misho 563: return (void*) -1;
1.28 misho 564: else
565: r = TASK_ROOT(t);
1.1 misho 566:
1.28 misho 567: #if SUP_ENABLE == KQ_SUPPORT
1.2 misho 568: #ifdef __NetBSD__
1.8 misho 569: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
1.2 misho 570: #else
1.8 misho 571: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
1.2 misho 572: #endif
1.28 misho 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);
1.3 misho 576: else
577: LOGERR;
1.1 misho 578: return (void*) -1;
579: }
1.28 misho 580: #elif SUP_ENABLE == EP_SUPPORT
1.32 misho 581: ee.data.fd = TASK_FD(t);
582: ee.events = EPOLLIN | EPOLLPRI;
1.28 misho 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]);
1.25 misho 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
1.1 misho 603:
604: return NULL;
605: }
606:
607: /*
608: * sched_hook_write() - Default WRITE hook
1.5 misho 609: *
1.1 misho 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;
1.28 misho 618: sched_root_task_t *r = NULL;
619: #if SUP_ENABLE == KQ_SUPPORT
1.1 misho 620: struct kevent chg[1];
1.2 misho 621: struct timespec timeout = { 0, 0 };
1.28 misho 622: #elif SUP_ENABLE == EP_SUPPORT
1.32 misho 623: struct epoll_event ee;
1.28 misho 624: int flg = 0;
1.25 misho 625: #endif
1.1 misho 626:
1.6 misho 627: if (!t || !TASK_ROOT(t))
1.1 misho 628: return (void*) -1;
1.28 misho 629: else
630: r = TASK_ROOT(t);
1.1 misho 631:
1.28 misho 632: #if SUP_ENABLE == KQ_SUPPORT
1.2 misho 633: #ifdef __NetBSD__
1.8 misho 634: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
1.2 misho 635: #else
1.8 misho 636: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
1.2 misho 637: #endif
1.28 misho 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);
1.3 misho 641: else
642: LOGERR;
1.1 misho 643: return (void*) -1;
644: }
1.28 misho 645: #elif SUP_ENABLE == EP_SUPPORT
1.32 misho 646: ee.data.fd = TASK_FD(t);
647: ee.events = EPOLLOUT;
648:
1.28 misho 649: if (FD_ISSET(TASK_FD(t), &r->root_fds[0])) {
650: flg |= 1;
1.32 misho 651: ee.events |= EPOLLIN | EPOLLPRI;
1.28 misho 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]);
1.25 misho 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
1.1 misho 669:
670: return NULL;
671: }
672:
673: /*
1.7 misho 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: {
1.28 misho 683: #if SUP_ENABLE == KQ_SUPPORT
1.7 misho 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__
1.19 misho 692: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_CLEAR, 0,
1.7 misho 693: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
694: (intptr_t) TASK_DATA(t));
695: #else
1.19 misho 696: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_CLEAR, 0,
1.7 misho 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:
1.25 misho 708: #endif
1.7 misho 709: return NULL;
710: }
711:
712: /*
1.8 misho 713: * sched_hook_node() - Default NODE hook
714: *
715: * @task = current task
716: * @arg = unused
717: * return: <0 errors and 0 ok
718: */
719: void *
720: sched_hook_node(void *task, void *arg __unused)
721: {
1.28 misho 722: #if SUP_ENABLE == KQ_SUPPORT
1.8 misho 723: sched_task_t *t = task;
724: struct kevent chg[1];
725: struct timespec timeout = { 0, 0 };
726:
727: if (!t || !TASK_ROOT(t))
728: return (void*) -1;
729:
730: #ifdef __NetBSD__
731: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
732: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
733: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (intptr_t) TASK_FD(t));
734: #else
735: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
736: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
737: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (void*) TASK_FD(t));
738: #endif
739: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
740: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
741: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
742: else
743: LOGERR;
744: return (void*) -1;
745: }
746:
1.25 misho 747: #endif
1.8 misho 748: return NULL;
749: }
750:
751: /*
752: * sched_hook_proc() - Default PROC hook
753: *
754: * @task = current task
755: * @arg = unused
756: * return: <0 errors and 0 ok
757: */
758: void *
759: sched_hook_proc(void *task, void *arg __unused)
760: {
1.28 misho 761: #if SUP_ENABLE == KQ_SUPPORT
1.8 misho 762: sched_task_t *t = task;
763: struct kevent chg[1];
764: struct timespec timeout = { 0, 0 };
765:
766: if (!t || !TASK_ROOT(t))
767: return (void*) -1;
768:
769: #ifdef __NetBSD__
770: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
771: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (intptr_t) TASK_VAL(t));
772: #else
773: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
774: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (void*) TASK_VAL(t));
775: #endif
776: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
777: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
778: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
779: else
780: LOGERR;
781: return (void*) -1;
782: }
783:
1.25 misho 784: #endif
1.8 misho 785: return NULL;
786: }
787:
788: /*
789: * sched_hook_signal() - Default SIGNAL hook
790: *
791: * @task = current task
792: * @arg = unused
793: * return: <0 errors and 0 ok
794: */
795: void *
796: sched_hook_signal(void *task, void *arg __unused)
797: {
1.28 misho 798: #if SUP_ENABLE == KQ_SUPPORT
1.8 misho 799: sched_task_t *t = task;
800: struct kevent chg[1];
801: struct timespec timeout = { 0, 0 };
802:
803: if (!t || !TASK_ROOT(t))
804: return (void*) -1;
805:
1.18 misho 806: /* ignore signal */
807: signal(TASK_VAL(t), SIG_IGN);
808:
1.8 misho 809: #ifdef __NetBSD__
1.19 misho 810: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_VAL(t));
1.8 misho 811: #else
1.19 misho 812: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_VAL(t));
1.8 misho 813: #endif
814: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
815: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
816: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
817: else
818: LOGERR;
819: return (void*) -1;
820: }
1.25 misho 821: #endif
1.8 misho 822: return NULL;
823: }
824:
825: /*
826: * sched_hook_user() - Default USER hook
827: *
828: * @task = current task
829: * @arg = unused
830: * return: <0 errors and 0 ok
831: */
832: #ifdef EVFILT_USER
833: void *
834: sched_hook_user(void *task, void *arg __unused)
835: {
1.28 misho 836: #if SUP_ENABLE == KQ_SUPPORT
1.8 misho 837: sched_task_t *t = task;
838: struct kevent chg[1];
839: struct timespec timeout = { 0, 0 };
840:
841: if (!t || !TASK_ROOT(t))
842: return (void*) -1;
843:
844: #ifdef __NetBSD__
845: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
846: 0, (intptr_t) TASK_VAL(t));
847: #else
848: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
849: 0, (void*) TASK_VAL(t));
850: #endif
851: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
852: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
853: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
854: else
855: LOGERR;
856: return (void*) -1;
857: }
858:
1.25 misho 859: #endif
1.8 misho 860: return NULL;
861: }
862: #endif
863:
1.28 misho 864: #if SUP_ENABLE == KQ_SUPPORT
865: static inline void
866: fetch_hook_kevent_proceed(int en, struct kevent *res, sched_root_task_t *r)
1.1 misho 867: {
1.28 misho 868: struct kevent evt[1];
869: register int i;
1.6 misho 870: sched_task_t *task, *tmp;
1.28 misho 871: struct timespec now = { 0, 0 };
1.11 misho 872: #ifdef AIO_SUPPORT
873: int len, fd;
874: struct aiocb *acb;
875: #ifdef EVFILT_LIO
876: int l;
877: off_t off;
878: struct aiocb **acbs;
879: struct iovec *iv;
880: #endif /* EVFILT_LIO */
881: #endif /* AIO_SUPPORT */
1.1 misho 882:
883: for (i = 0; i < en; i++) {
884: memcpy(evt, &res[i], sizeof evt);
885: evt->flags = EV_DELETE;
886: /* Put read/write task to ready queue */
887: switch (res[i].filter) {
888: case EVFILT_READ:
1.6 misho 889: TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) {
1.32 misho 890: if (TASK_FD(task) == ((intptr_t) res[i].udata)) {
1.14 misho 891: TASK_RET(task) = res[i].data;
1.19 misho 892: TASK_FLAG(task) = (u_long) res[i].fflags;
1.28 misho 893:
1.32 misho 894: /* remove read handle */
895: remove_task_from(task, &r->root_read);
896:
897: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
898: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
899: task->task_type = taskUNUSE;
900: insert_task_to(task, &r->root_unuse);
901: } else {
902: task->task_type = taskREADY;
903: insert_task_to(task, &r->root_ready);
904: }
1.3 misho 905: } else {
906: task->task_type = taskREADY;
1.28 misho 907: insert_task_to(task, &r->root_ready);
1.3 misho 908: }
1.32 misho 909: break;
1.3 misho 910: }
1.1 misho 911: }
912: break;
913: case EVFILT_WRITE:
1.6 misho 914: TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) {
1.32 misho 915: if (TASK_FD(task) == ((intptr_t) res[i].udata)) {
1.14 misho 916: TASK_RET(task) = res[i].data;
1.19 misho 917: TASK_FLAG(task) = (u_long) res[i].fflags;
1.28 misho 918:
1.32 misho 919: /* remove write handle */
920: remove_task_from(task, &r->root_write);
921:
922: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
923: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
924: task->task_type = taskUNUSE;
925: insert_task_to(task, &r->root_unuse);
926: } else {
927: task->task_type = taskREADY;
928: insert_task_to(task, &r->root_ready);
929: }
1.3 misho 930: } else {
931: task->task_type = taskREADY;
1.28 misho 932: insert_task_to(task, &r->root_ready);
1.3 misho 933: }
1.32 misho 934: break;
1.3 misho 935: }
1.1 misho 936: }
937: break;
1.7 misho 938: case EVFILT_TIMER:
939: TAILQ_FOREACH_SAFE(task, &r->root_alarm, task_node, tmp) {
1.32 misho 940: if ((uintptr_t) TASK_DATA(task) == ((uintptr_t) res[i].udata)) {
1.14 misho 941: TASK_RET(task) = res[i].data;
1.19 misho 942: TASK_FLAG(task) = (u_long) res[i].fflags;
1.32 misho 943:
944: /* remove alarm handle */
945: transit_task2ready(task, &r->root_alarm);
946: break;
1.14 misho 947: }
1.7 misho 948: }
949: break;
1.8 misho 950: case EVFILT_VNODE:
951: TAILQ_FOREACH_SAFE(task, &r->root_node, task_node, tmp) {
1.32 misho 952: if (TASK_FD(task) == ((intptr_t) res[i].udata)) {
1.14 misho 953: TASK_RET(task) = res[i].data;
1.19 misho 954: TASK_FLAG(task) = (u_long) res[i].fflags;
1.32 misho 955:
956: /* remove node handle */
957: transit_task2ready(task, &r->root_node);
958: break;
1.8 misho 959: }
960: }
961: break;
962: case EVFILT_PROC:
963: TAILQ_FOREACH_SAFE(task, &r->root_proc, task_node, tmp) {
1.32 misho 964: if (TASK_VAL(task) == ((uintptr_t) res[i].udata)) {
1.14 misho 965: TASK_RET(task) = res[i].data;
1.19 misho 966: TASK_FLAG(task) = (u_long) res[i].fflags;
1.32 misho 967:
968: /* remove proc handle */
969: transit_task2ready(task, &r->root_proc);
970: break;
1.8 misho 971: }
972: }
973: break;
974: case EVFILT_SIGNAL:
975: TAILQ_FOREACH_SAFE(task, &r->root_signal, task_node, tmp) {
1.32 misho 976: if (TASK_VAL(task) == ((uintptr_t) res[i].udata)) {
1.14 misho 977: TASK_RET(task) = res[i].data;
1.19 misho 978: TASK_FLAG(task) = (u_long) res[i].fflags;
1.32 misho 979:
980: /* remove signal handle */
981: transit_task2ready(task, &r->root_signal);
982: break;
1.14 misho 983: }
1.8 misho 984: }
985: break;
1.11 misho 986: #ifdef AIO_SUPPORT
987: case EVFILT_AIO:
988: TAILQ_FOREACH_SAFE(task, &r->root_aio, task_node, tmp) {
989: acb = (struct aiocb*) TASK_VAL(task);
1.32 misho 990: if (acb == ((struct aiocb*) res[i].udata)) {
1.14 misho 991: TASK_RET(task) = res[i].data;
1.19 misho 992: TASK_FLAG(task) = (u_long) res[i].fflags;
1.32 misho 993:
994: /* remove user handle */
995: transit_task2ready(task, &r->root_aio);
996:
997: fd = acb->aio_fildes;
998: if ((len = aio_return(acb)) != -1) {
999: if (lseek(fd, acb->aio_offset + len, SEEK_CUR) == -1)
1000: LOGERR;
1001: } else
1002: LOGERR;
1003: free(acb);
1004: TASK_DATLEN(task) = (u_long) len;
1005: TASK_FD(task) = fd;
1006: break;
1.14 misho 1007: }
1.11 misho 1008: }
1009: break;
1010: #ifdef EVFILT_LIO
1011: case EVFILT_LIO:
1012: TAILQ_FOREACH_SAFE(task, &r->root_lio, task_node, tmp) {
1013: acbs = (struct aiocb**) TASK_VAL(task);
1.32 misho 1014: if (acbs == ((struct aiocb**) res[i].udata)) {
1.14 misho 1015: TASK_RET(task) = res[i].data;
1.19 misho 1016: TASK_FLAG(task) = (u_long) res[i].fflags;
1.28 misho 1017:
1.32 misho 1018: /* remove user handle */
1019: transit_task2ready(task, &r->root_lio);
1020:
1021: iv = (struct iovec*) TASK_DATA(task);
1022: fd = acbs[0]->aio_fildes;
1023: off = acbs[0]->aio_offset;
1024: for (len = 0; i < TASK_DATLEN(task); len += l, i++) {
1025: if ((iv[i].iov_len = aio_return(acbs[i])) == -1)
1026: l = 0;
1027: else
1028: l = iv[i].iov_len;
1029: free(acbs[i]);
1030: }
1031: free(acbs);
1032: TASK_DATLEN(task) = (u_long) len;
1033: TASK_FD(task) = fd;
1034:
1035: if (lseek(fd, off + len, SEEK_CUR) == -1)
1036: LOGERR;
1037: break;
1.11 misho 1038: }
1039: }
1040: break;
1041: #endif /* EVFILT_LIO */
1042: #endif /* AIO_SUPPORT */
1.8 misho 1043: #ifdef EVFILT_USER
1044: case EVFILT_USER:
1045: TAILQ_FOREACH_SAFE(task, &r->root_user, task_node, tmp) {
1.32 misho 1046: if (TASK_VAL(task) == ((uintptr_t) res[i].udata)) {
1.14 misho 1047: TASK_RET(task) = res[i].data;
1.19 misho 1048: TASK_FLAG(task) = (u_long) res[i].fflags;
1.32 misho 1049:
1050: /* remove user handle */
1051: transit_task2ready(task, &r->root_user);
1052: break;
1.8 misho 1053: }
1054: }
1055: break;
1.11 misho 1056: #endif /* EVFILT_USER */
1.1 misho 1057: }
1.28 misho 1058:
1.4 misho 1059: if (kevent(r->root_kq, evt, 1, NULL, 0, &now) == -1) {
1.28 misho 1060: if (r->root_hooks.hook_exec.exception)
1061: r->root_hooks.hook_exec.exception(r, NULL);
1062: else
1063: LOGERR;
1064: }
1065: }
1066: }
1067: #endif
1068:
1069: #if SUP_ENABLE == EP_SUPPORT
1070: static inline void
1071: fetch_hook_epoll_proceed(int en, struct epoll_event *res, sched_root_task_t *r)
1072: {
1073: register int i, flg;
1074: int ops = EPOLL_CTL_DEL;
1.32 misho 1075: sched_task_t *t, *tmp, *task;
1.28 misho 1076: struct epoll_event evt[1];
1077:
1078: for (i = 0; i < en; i++) {
1079: memcpy(evt, &res[i], sizeof evt);
1080:
1.32 misho 1081: if (evt->events & (EPOLLIN | EPOLLPRI)) {
1.28 misho 1082: flg = 0;
1.32 misho 1083: task = NULL;
1084: TAILQ_FOREACH_SAFE(t, &r->root_read, task_node, tmp) {
1085: if (TASK_FD(t) == evt->data.fd) {
1086: if (!flg)
1087: task = t;
1.28 misho 1088: flg++;
1.32 misho 1089: }
1090: }
1.28 misho 1091:
1.32 misho 1092: if (flg && task) {
1093: TASK_FLAG(task) = ioctl(TASK_FD(task), FIONREAD, &TASK_RET(task));
1.28 misho 1094: /* remove read handle */
1095: remove_task_from(task, &r->root_read);
1096:
1097: if (r->root_hooks.hook_exec.exception && evt->events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) {
1098: if (r->root_hooks.hook_exec.exception(r, (void*) (intptr_t)
1099: (evt->events & EPOLLERR ? EV_ERROR | EV_EOF : EV_EOF))) {
1100: task->task_type = taskUNUSE;
1101: insert_task_to(task, &r->root_unuse);
1102: } else {
1103: task->task_type = taskREADY;
1104: insert_task_to(task, &r->root_ready);
1105: }
1106: } else {
1107: task->task_type = taskREADY;
1108: insert_task_to(task, &r->root_ready);
1109: }
1.32 misho 1110:
1111: evt->events ^= evt->events;
1112: if (FD_ISSET(evt->data.fd, &r->root_fds[1])) {
1113: ops = EPOLL_CTL_MOD;
1114: evt->events |= EPOLLOUT;
1115: }
1116: if (flg > 1) {
1117: ops = EPOLL_CTL_MOD;
1118: evt->events |= EPOLLIN | EPOLLPRI;
1119: } else
1120: FD_CLR(evt->data.fd, &r->root_fds[0]);
1.28 misho 1121: }
1.32 misho 1122: } else if (evt->events & EPOLLOUT) {
1.28 misho 1123: flg = 0;
1.32 misho 1124: task = NULL;
1125: TAILQ_FOREACH_SAFE(t, &r->root_write, task_node, tmp) {
1126: if (TASK_FD(t) == evt->data.fd) {
1127: if (!flg)
1128: task = t;
1.28 misho 1129: flg++;
1130: }
1.32 misho 1131: }
1132:
1133: if (flg && task) {
1134: TASK_FLAG(task) = ioctl(TASK_FD(task), FIONWRITE, &TASK_RET(task));
1.28 misho 1135: /* remove write handle */
1136: remove_task_from(task, &r->root_write);
1137:
1138: if (r->root_hooks.hook_exec.exception && evt->events & (EPOLLERR | EPOLLHUP)) {
1139: if (r->root_hooks.hook_exec.exception(r, (void*) (intptr_t)
1140: (evt->events & EPOLLERR ? EV_ERROR | EV_EOF : EV_EOF))) {
1141: task->task_type = taskUNUSE;
1142: insert_task_to(task, &r->root_unuse);
1143: } else {
1144: task->task_type = taskREADY;
1145: insert_task_to(task, &r->root_ready);
1146: }
1147: } else {
1148: task->task_type = taskREADY;
1149: insert_task_to(task, &r->root_ready);
1150: }
1.32 misho 1151:
1152: evt->events ^= evt->events;
1153: if (FD_ISSET(evt->data.fd, &r->root_fds[0])) {
1154: ops = EPOLL_CTL_MOD;
1155: evt->events |= EPOLLIN | EPOLLPRI;
1156: }
1157: if (flg > 1) {
1158: ops = EPOLL_CTL_MOD;
1159: evt->events |= EPOLLOUT;
1160: } else
1161: FD_CLR(evt->data.fd, &r->root_fds[1]);
1.28 misho 1162: }
1163: }
1164:
1165: if (epoll_ctl(r->root_kq, ops, evt->data.fd, evt) == -1) {
1.3 misho 1166: if (r->root_hooks.hook_exec.exception) {
1.28 misho 1167: r->root_hooks.hook_exec.exception(r, NULL);
1.3 misho 1168: } else
1169: LOGERR;
1170: }
1.25 misho 1171: }
1.28 misho 1172: }
1173: #endif
1174:
1175: #if SUP_ENABLE == NO_SUPPORT
1176: static inline void
1177: fetch_hook_select_proceed(int en, fd_set rfd, fd_set wfd, fd_set xfd, sched_root_task_t *r)
1178: {
1179: register int i, flg;
1.32 misho 1180: sched_task_t *t, *tmp, *task = NULL;
1.28 misho 1181:
1182: /* skip select check if return value from select is zero */
1183: if (!en)
1184: return;
1185:
1.25 misho 1186: for (i = 0; i < r->root_kq; i++) {
1187: if (FD_ISSET(i, &rfd) || FD_ISSET(i, &xfd)) {
1188: flg = 0;
1.32 misho 1189: TAILQ_FOREACH_SAFE(t, &r->root_read, task_node, tmp) {
1190: if (TASK_FD(t) == i) {
1191: if (!flg)
1192: task = t;
1.25 misho 1193: flg++;
1194: }
1.32 misho 1195: }
1196:
1197: if (flg && task) {
1198: TASK_FLAG(task) = ioctl(TASK_FD(task), FIONREAD, &TASK_RET(task));
1199:
1.25 misho 1200: /* remove read handle */
1.28 misho 1201: remove_task_from(task, &r->root_read);
1202:
1.25 misho 1203: if (r->root_hooks.hook_exec.exception) {
1204: if (r->root_hooks.hook_exec.exception(r, NULL)) {
1205: task->task_type = taskUNUSE;
1.28 misho 1206: insert_task_to(task, &r->root_unuse);
1.25 misho 1207: } else {
1208: task->task_type = taskREADY;
1.28 misho 1209: insert_task_to(task, &r->root_ready);
1.25 misho 1210: }
1211: } else {
1212: task->task_type = taskREADY;
1.28 misho 1213: insert_task_to(task, &r->root_ready);
1.25 misho 1214: }
1.32 misho 1215:
1216: /* remove resouce */
1217: if (flg == 1)
1218: FD_CLR(i, &r->root_fds[0]);
1.25 misho 1219: }
1.32 misho 1220: } else if (FD_ISSET(i, &wfd)) {
1.25 misho 1221: flg = 0;
1.32 misho 1222: TAILQ_FOREACH_SAFE(t, &r->root_write, task_node, tmp) {
1223: if (TASK_FD(t) == i) {
1224: if (!flg)
1225: task = t;
1.25 misho 1226: flg++;
1227: }
1.32 misho 1228: }
1229:
1230: if (flg && task) {
1231: TASK_FLAG(task) = ioctl(TASK_FD(task), FIONWRITE, &TASK_RET(task));
1232:
1.25 misho 1233: /* remove write handle */
1.28 misho 1234: remove_task_from(task, &r->root_write);
1235:
1.25 misho 1236: if (r->root_hooks.hook_exec.exception) {
1237: if (r->root_hooks.hook_exec.exception(r, NULL)) {
1238: task->task_type = taskUNUSE;
1.28 misho 1239: insert_task_to(task, &r->root_unuse);
1.25 misho 1240: } else {
1241: task->task_type = taskREADY;
1.28 misho 1242: insert_task_to(task, &r->root_ready);
1.25 misho 1243: }
1244: } else {
1245: task->task_type = taskREADY;
1.28 misho 1246: insert_task_to(task, &r->root_ready);
1.25 misho 1247: }
1.32 misho 1248:
1249: /* remove resouce */
1250: if (flg == 1)
1251: FD_CLR(i, &r->root_fds[1]);
1.25 misho 1252: }
1253: }
1254: }
1255:
1256: /* optimize select */
1257: for (i = r->root_kq - 1; i > 2; i--)
1258: if (FD_ISSET(i, &r->root_fds[0]) || FD_ISSET(i, &r->root_fds[1]))
1259: break;
1260: if (i > 2)
1261: r->root_kq = i + 1;
1.28 misho 1262: }
1263: #endif
1264:
1265: /*
1266: * sched_hook_fetch() - Default FETCH hook
1267: *
1268: * @root = root task
1269: * @arg = unused
1270: * return: NULL error or !=NULL fetched task
1271: */
1272: void *
1273: sched_hook_fetch(void *root, void *arg __unused)
1274: {
1275: sched_root_task_t *r = root;
1276: sched_task_t *task, *tmp;
1277: struct timespec now, m, mtmp;
1278: #if SUP_ENABLE == KQ_SUPPORT
1279: struct kevent res[KQ_EVENTS];
1280: struct timespec *timeout;
1281: #elif SUP_ENABLE == EP_SUPPORT
1282: struct epoll_event res[KQ_EVENTS];
1283: u_long timeout = 0;
1284: #else
1285: struct timeval *timeout, tv;
1286: fd_set rfd, wfd, xfd;
1287: #endif
1288: int en;
1289:
1290: if (!r)
1291: return NULL;
1292:
1293: /* get new task by queue priority */
1294: while ((task = TAILQ_FIRST(&r->root_event))) {
1295: transit_task2unuse(task, &r->root_event);
1296: return task;
1297: }
1298: while ((task = TAILQ_FIRST(&r->root_ready))) {
1299: transit_task2unuse(task, &r->root_ready);
1300: return task;
1301: }
1302:
1.33 ! misho 1303: /* if present member of task, set NOWAIT */
! 1304: if (!TAILQ_FIRST(&r->root_task)) {
! 1305: /* timer tasks */
1.28 misho 1306: #ifdef TIMER_WITHOUT_SORT
1.33 ! misho 1307: clock_gettime(CLOCK_MONOTONIC, &now);
1.28 misho 1308:
1.33 ! misho 1309: sched_timespecclear(&r->root_wait);
! 1310: TAILQ_FOREACH(task, &r->root_timer, task_node) {
! 1311: if (!sched_timespecisset(&r->root_wait))
! 1312: r->root_wait = TASK_TS(task);
! 1313: else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
! 1314: r->root_wait = TASK_TS(task);
! 1315: }
! 1316:
! 1317: if (TAILQ_FIRST(&r->root_timer)) {
! 1318: m = r->root_wait;
! 1319: sched_timespecsub(&m, &now, &mtmp);
! 1320: r->root_wait = mtmp;
! 1321: } else {
! 1322: /* set wait INFTIM */
! 1323: sched_timespecinf(&r->root_wait);
! 1324: }
1.28 misho 1325: #else /* ! TIMER_WITHOUT_SORT */
1.33 ! misho 1326: if ((task = TAILQ_FIRST(&r->root_timer))) {
! 1327: clock_gettime(CLOCK_MONOTONIC, &now);
1.28 misho 1328:
1.33 ! misho 1329: m = TASK_TS(task);
! 1330: sched_timespecsub(&m, &now, &mtmp);
! 1331: r->root_wait = mtmp;
! 1332: } else {
! 1333: /* set wait INFTIM */
! 1334: sched_timespecinf(&r->root_wait);
! 1335: }
1.28 misho 1336: #endif /* TIMER_WITHOUT_SORT */
1.33 ! misho 1337: } else /* no waiting for event, because we have ready task */
1.28 misho 1338: sched_timespecclear(&r->root_wait);
1339:
1340: if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1) {
1341: #if SUP_ENABLE == KQ_SUPPORT
1342: timeout = &r->root_wait;
1343: #elif SUP_ENABLE == EP_SUPPORT
1344: timeout = r->root_wait.tv_sec * 1000 + r->root_wait.tv_nsec / 1000000;
1345: #else
1346: sched_timespec2val(&r->root_wait, &tv);
1347: timeout = &tv;
1348: #endif /* KQ_SUPPORT */
1349: } else if (sched_timespecisinf(&r->root_poll))
1350: #if SUP_ENABLE == EP_SUPPORT
1351: timeout = -1;
1352: #else
1353: timeout = NULL;
1354: #endif
1355: else {
1356: #if SUP_ENABLE == KQ_SUPPORT
1357: timeout = &r->root_poll;
1358: #elif SUP_ENABLE == EP_SUPPORT
1359: timeout = r->root_poll.tv_sec * 1000 + r->root_poll.tv_nsec / 1000000;
1360: #else
1361: sched_timespec2val(&r->root_poll, &tv);
1362: timeout = &tv;
1363: #endif /* KQ_SUPPORT */
1364: }
1365:
1366: #if SUP_ENABLE == KQ_SUPPORT
1367: if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
1368: #elif SUP_ENABLE == EP_SUPPORT
1369: if ((en = epoll_wait(r->root_kq, res, KQ_EVENTS, timeout)) == -1) {
1370: #else
1371: rfd = xfd = r->root_fds[0];
1372: wfd = r->root_fds[1];
1373: if ((en = select(r->root_kq, &rfd, &wfd, &xfd, timeout)) == -1) {
1374: #endif /* KQ_SUPPORT */
1375: if (r->root_hooks.hook_exec.exception) {
1376: if (r->root_hooks.hook_exec.exception(r, NULL))
1377: return NULL;
1378: } else if (errno != EINTR)
1379: LOGERR;
1380: goto skip_event;
1381: }
1382:
1383: /* Go and catch the cat into pipes ... */
1384: #if SUP_ENABLE == KQ_SUPPORT
1385: /* kevent dispatcher */
1386: fetch_hook_kevent_proceed(en, res, r);
1387: #elif SUP_ENABLE == EP_SUPPORT
1388: /* epoll dispatcher */
1389: fetch_hook_epoll_proceed(en, res, r);
1390: #else
1391: /* select dispatcher */
1392: fetch_hook_select_proceed(en, rfd, wfd, xfd, r);
1393: #endif /* KQ_SUPPORT */
1.1 misho 1394:
1.24 misho 1395: skip_event:
1.2 misho 1396: /* timer update & put in ready queue */
1.4 misho 1397: clock_gettime(CLOCK_MONOTONIC, &now);
1.1 misho 1398:
1.6 misho 1399: TAILQ_FOREACH_SAFE(task, &r->root_timer, task_node, tmp)
1.28 misho 1400: if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0)
1401: transit_task2ready(task, &r->root_timer);
1.1 misho 1402:
1.12 misho 1403: /* put regular task priority task to ready queue,
1.13 misho 1404: if there is no ready task or reach max missing hit for regular task */
1.12 misho 1405: if ((task = TAILQ_FIRST(&r->root_task))) {
1.13 misho 1406: if (!TAILQ_FIRST(&r->root_ready) || r->root_miss >= TASK_VAL(task)) {
1407: r->root_miss ^= r->root_miss;
1.1 misho 1408:
1.28 misho 1409: transit_task2ready(task, &r->root_task);
1.1 misho 1410: } else
1.13 misho 1411: r->root_miss++;
1.1 misho 1412: } else
1.13 misho 1413: r->root_miss ^= r->root_miss;
1.1 misho 1414:
1415: /* OK, lets get ready task !!! */
1.6 misho 1416: task = TAILQ_FIRST(&r->root_ready);
1.28 misho 1417: if (task)
1418: transit_task2unuse(task, &r->root_ready);
1.1 misho 1419: return task;
1420: }
1.3 misho 1421:
1422: /*
1423: * sched_hook_exception() - Default EXCEPTION hook
1.5 misho 1424: *
1.3 misho 1425: * @root = root task
1426: * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
1427: * return: <0 errors and 0 ok
1428: */
1429: void *
1430: sched_hook_exception(void *root, void *arg)
1431: {
1432: sched_root_task_t *r = root;
1433:
1.6 misho 1434: if (!r)
1.3 misho 1435: return NULL;
1436:
1437: /* custom exception handling ... */
1438: if (arg) {
1439: if (arg == (void*) EV_EOF)
1440: return NULL;
1441: return (void*) -1; /* raise scheduler error!!! */
1442: }
1443:
1444: /* if error hook exists */
1445: if (r->root_hooks.hook_root.error)
1446: return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
1447:
1448: /* default case! */
1449: LOGERR;
1450: return NULL;
1451: }
1.5 misho 1452:
1453: /*
1454: * sched_hook_condition() - Default CONDITION hook
1455: *
1456: * @root = root task
1457: * @arg = killState from schedRun()
1458: * return: NULL kill scheduler loop or !=NULL ok
1459: */
1460: void *
1461: sched_hook_condition(void *root, void *arg)
1462: {
1463: sched_root_task_t *r = root;
1464:
1.6 misho 1465: if (!r)
1.5 misho 1466: return NULL;
1467:
1.28 misho 1468: return (void*) (*r->root_cond - *(intptr_t*) arg);
1.5 misho 1469: }
1.19 misho 1470:
1471: /*
1472: * sched_hook_rtc() - Default RTC hook
1473: *
1474: * @task = current task
1475: * @arg = unused
1476: * return: <0 errors and 0 ok
1477: */
1478: void *
1479: sched_hook_rtc(void *task, void *arg __unused)
1480: {
1.30 misho 1481: #if defined(HAVE_LIBRT) && defined(HAVE_TIMER_CREATE) && \
1482: defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
1.19 misho 1483: sched_task_t *sigt = NULL, *t = task;
1484: struct itimerspec its;
1485: struct sigevent evt;
1486: timer_t tmr;
1.28 misho 1487: #if SUP_ENABLE != KQ_SUPPORT
1488: struct sigaction sa;
1489: #endif
1.19 misho 1490:
1491: if (!t || !TASK_ROOT(t))
1492: return (void*) -1;
1493:
1494: memset(&evt, 0, sizeof evt);
1495: evt.sigev_notify = SIGEV_SIGNAL;
1.20 misho 1496: evt.sigev_signo = (intptr_t) TASK_DATA(t) + SIGRTMIN;
1.28 misho 1497: evt.sigev_value.sival_ptr = t;
1.19 misho 1498:
1499: if (timer_create(CLOCK_MONOTONIC, &evt, &tmr) == -1) {
1500: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1501: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1502: else
1503: LOGERR;
1504: return (void*) -1;
1505: } else
1506: TASK_FLAG(t) = (u_long) tmr;
1507:
1.28 misho 1508: #if SUP_ENABLE == KQ_SUPPORT
1.21 misho 1509: if (!(sigt = schedSignal(TASK_ROOT(t), _sched_rtcWrapper, TASK_ARG(t), evt.sigev_signo,
1510: t, (size_t) tmr))) {
1.19 misho 1511: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1512: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1513: else
1514: LOGERR;
1515: timer_delete(tmr);
1516: return (void*) -1;
1517: } else
1518: TASK_RET(t) = (uintptr_t) sigt;
1.28 misho 1519: #else
1520: memset(&sa, 0, sizeof sa);
1521: sigemptyset(&sa.sa_mask);
1522: sa.sa_sigaction = _sched_rtcSigWrapper;
1523: sa.sa_flags = SA_SIGINFO | SA_RESTART;
1524:
1525: if (sigaction(evt.sigev_signo, &sa, NULL) == -1) {
1526: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1527: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1528: else
1529: LOGERR;
1530: timer_delete(tmr);
1531: return (void*) -1;
1532: }
1533: #endif
1.19 misho 1534:
1535: memset(&its, 0, sizeof its);
1536: its.it_value.tv_sec = t->task_val.ts.tv_sec;
1537: its.it_value.tv_nsec = t->task_val.ts.tv_nsec;
1538:
1539: if (timer_settime(tmr, TIMER_RELTIME, &its, NULL) == -1) {
1540: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1541: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1542: else
1543: LOGERR;
1544: schedCancel(sigt);
1545: timer_delete(tmr);
1546: return (void*) -1;
1547: }
1.30 misho 1548: #endif /* HAVE_TIMER_CREATE */
1.19 misho 1549: return NULL;
1550: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>