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