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