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