Annotation of libaitsched/src/hooks.c, revision 1.36

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.36    ! misho       6: * $Id: hooks.c,v 1.35.4.2 2022/10/17 22:41:48 misho Exp $
1.1       misho       7: *
                      8: **************************************************************************
                      9: The ELWIX and AITNET software is distributed under the following
                     10: terms:
                     11: 
                     12: All of the documentation and software included in the ELWIX and AITNET
                     13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
                     14: 
1.36    ! misho      15: Copyright 2004 - 2022
1.1       misho      16:        by Michael Pounov <misho@elwix.org>.  All rights reserved.
                     17: 
                     18: Redistribution and use in source and binary forms, with or without
                     19: modification, are permitted provided that the following conditions
                     20: are met:
                     21: 1. Redistributions of source code must retain the above copyright
                     22:    notice, this list of conditions and the following disclaimer.
                     23: 2. Redistributions in binary form must reproduce the above copyright
                     24:    notice, this list of conditions and the following disclaimer in the
                     25:    documentation and/or other materials provided with the distribution.
                     26: 3. All advertising materials mentioning features or use of this software
                     27:    must display the following acknowledgement:
                     28: This product includes software developed by Michael Pounov <misho@elwix.org>
                     29: ELWIX - Embedded LightWeight unIX and its contributors.
                     30: 4. Neither the name of AITNET nor the names of its contributors
                     31:    may be used to endorse or promote products derived from this software
                     32:    without specific prior written permission.
                     33: 
                     34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
                     35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     44: SUCH DAMAGE.
                     45: */
                     46: #include "global.h"
                     47: #include "hooks.h"
                     48: 
                     49: 
1.28      misho      50: static inline void
                     51: transit_task2ready(sched_task_t * __restrict t, sched_queue_t * __restrict q)
                     52: {
                     53:        remove_task_from(t, q);
                     54: 
                     55:        t->task_type = taskREADY;
                     56:        insert_task_to(t, &(TASK_ROOT(t))->root_ready);
                     57: }
                     58: 
                     59: #ifdef HAVE_LIBPTHREAD
                     60: static void *
                     61: _sched_threadWrapper(sched_task_t *t)
                     62: {
                     63:        void *ret = NULL;
                     64:        sched_root_task_t *r;
                     65: 
                     66:        if (!t || !TASK_ROOT(t))
                     67:                pthread_exit(ret);
                     68:        else
                     69:                r = (sched_root_task_t*) TASK_ROOT(t);
                     70: 
                     71:        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
                     72:        /*
                     73:        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
                     74:        */
                     75: 
                     76:        /* notify parent, thread is ready for execution */
                     77:        pthread_testcancel();
                     78: 
                     79:        ret = schedCall(t);
                     80:        r->root_ret = ret;
                     81: 
                     82:        if (TASK_VAL(t)) {
                     83:                transit_task2unuse(t, &r->root_thread);
                     84:                TASK_VAL(t) = 0;
                     85:        }
                     86: 
                     87:        pthread_exit(ret);
                     88: }
                     89: #endif
                     90: 
1.29      misho      91: #if defined(HAVE_LIBRT) && defined(HAVE_TIMER_CREATE) && \
                     92:        defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
1.28      misho      93: #if SUP_ENABLE == KQ_SUPPORT
                     94: static void *
                     95: _sched_rtcWrapper(sched_task_t *t)
                     96: {
                     97:        sched_task_t *task;
                     98:        void *ret;
                     99: 
                    100:        if (!t || !TASK_ROOT(t) || !TASK_DATA(t))
                    101:                return NULL;
                    102:        else {
                    103:                task = (sched_task_t*) TASK_DATA(t);
                    104:                timer_delete((timer_t) TASK_DATLEN(t));
                    105:        }
                    106: 
                    107:        ret = schedCall(task);
                    108: 
                    109:        transit_task2unuse(task, &(TASK_ROOT(task))->root_rtc);
                    110:        return ret;
                    111: }
                    112: #else
                    113: static void
                    114: _sched_rtcSigWrapper(int sig, siginfo_t *si, void *uc)
                    115: {
                    116:        sched_task_t *task;
                    117: 
                    118:        if (si && si->si_value.sival_ptr) {
                    119:                task = (sched_task_t*) si->si_value.sival_ptr;
                    120:                timer_delete((timer_t) TASK_FLAG(task));
                    121: 
                    122:                TASK_RET(task) = (intptr_t) schedCall(task);
                    123: 
                    124:                transit_task2unuse(task, &(TASK_ROOT(task))->root_rtc);
                    125:        }
                    126: }
                    127: #endif
                    128: #endif
                    129: 
1.1       misho     130: /*
                    131:  * sched_hook_init() - Default INIT hook
1.5       misho     132:  *
1.1       misho     133:  * @root = root task
1.6       misho     134:  * @arg = unused
1.1       misho     135:  * return: <0 errors and 0 ok
                    136:  */
                    137: void *
1.6       misho     138: sched_hook_init(void *root, void *arg __unused)
1.1       misho     139: {
                    140:        sched_root_task_t *r = root;
                    141: 
1.6       misho     142:        if (!r)
1.1       misho     143:                return (void*) -1;
                    144: 
1.28      misho     145: #if SUP_ENABLE == KQ_SUPPORT
1.1       misho     146:        r->root_kq = kqueue();
                    147:        if (r->root_kq == -1) {
                    148:                LOGERR;
                    149:                return (void*) -1;
                    150:        }
1.28      misho     151: #elif SUP_ENABLE == EP_SUPPORT
                    152:        r->root_kq = epoll_create(KQ_EVENTS);
                    153:        if (r->root_kq == -1) {
                    154:                LOGERR;
                    155:                return (void*) -1;
                    156:        }
1.25      misho     157: #else
                    158:        r->root_kq ^= r->root_kq;
                    159:        FD_ZERO(&r->root_fds[0]);
                    160:        FD_ZERO(&r->root_fds[1]);
                    161: #endif
1.1       misho     162: 
                    163:        return NULL;
                    164: }
                    165: 
                    166: /*
                    167:  * sched_hook_fini() - Default FINI hook
1.5       misho     168:  *
1.1       misho     169:  * @root = root task
                    170:  * @arg = unused
                    171:  * return: <0 errors and 0 ok
                    172:  */
                    173: void *
                    174: sched_hook_fini(void *root, void *arg __unused)
                    175: {
                    176:        sched_root_task_t *r = root;
                    177: 
                    178:        if (!r)
                    179:                return (void*) -1;
                    180: 
1.28      misho     181: #if SUP_ENABLE == KQ_SUPPORT || SUP_ENABLE == EP_SUPPORT
1.1       misho     182:        if (r->root_kq > 2) {
                    183:                close(r->root_kq);
                    184:                r->root_kq = 0;
                    185:        }
1.25      misho     186: #else
                    187:        FD_ZERO(&r->root_fds[1]);
                    188:        FD_ZERO(&r->root_fds[0]);
                    189:        r->root_kq ^= r->root_kq;
                    190: #endif
1.1       misho     191: 
                    192:        return NULL;
                    193: }
                    194: 
                    195: /*
                    196:  * sched_hook_cancel() - Default CANCEL hook
1.5       misho     197:  *
1.1       misho     198:  * @task = current task
                    199:  * @arg = unused
                    200:  * return: <0 errors and 0 ok
                    201:  */
                    202: void *
                    203: sched_hook_cancel(void *task, void *arg __unused)
                    204: {
1.28      misho     205:        sched_task_t *t = task, *tmp, *tt;
                    206:        sched_root_task_t *r = NULL;
                    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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.35      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.28      misho    1051: 
1.35      misho    1052:                                                        if (lseek(fd, off + len, SEEK_CUR) == -1)
                   1053:                                                                LOGERR;
1.32      misho    1054:                                                }
1.35      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.35      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.35      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.35      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.36    ! misho    1189:                        if (errno == EBADF) {
        !          1190:                                epoll_ctl(r->root_kq, EPOLL_CTL_DEL, evt->data.fd, evt);
        !          1191:                                schedCancelby(r, taskREAD, CRITERIA_FD, 
        !          1192:                                                (void*) (uintptr_t) evt->data.fd, NULL);
        !          1193:                                schedCancelby(r, taskWRITE, CRITERIA_FD, 
        !          1194:                                                (void*) (uintptr_t) evt->data.fd, NULL);
        !          1195:                        }
1.3       misho    1196:                        if (r->root_hooks.hook_exec.exception) {
1.28      misho    1197:                                r->root_hooks.hook_exec.exception(r, NULL);
1.3       misho    1198:                        } else
                   1199:                                LOGERR;
                   1200:                }
1.25      misho    1201:        }
1.28      misho    1202: }
                   1203: #endif
                   1204: 
                   1205: #if SUP_ENABLE == NO_SUPPORT
                   1206: static inline void 
                   1207: fetch_hook_select_proceed(int en, fd_set rfd, fd_set wfd, fd_set xfd, sched_root_task_t *r)
                   1208: {
                   1209:        register int i, flg;
1.32      misho    1210:        sched_task_t *t, *tmp, *task = NULL;
1.28      misho    1211: 
                   1212:        /* skip select check if return value from select is zero */
                   1213:        if (!en)
                   1214:                return;
                   1215: 
1.25      misho    1216:        for (i = 0; i < r->root_kq; i++) {
                   1217:                if (FD_ISSET(i, &rfd) || FD_ISSET(i, &xfd)) {
                   1218:                        flg = 0;
1.32      misho    1219:                        TAILQ_FOREACH_SAFE(t, &r->root_read, task_node, tmp) {
                   1220:                                if (TASK_FD(t) == i) {
                   1221:                                        if (!flg)
                   1222:                                                task = t;
1.25      misho    1223:                                        flg++;
                   1224:                                }
1.32      misho    1225:                        }
                   1226: 
                   1227:                        if (flg && task) {
                   1228:                                TASK_FLAG(task) = ioctl(TASK_FD(task), FIONREAD, &TASK_RET(task));
                   1229: 
1.25      misho    1230:                                /* remove read handle */
1.28      misho    1231:                                remove_task_from(task, &r->root_read);
                   1232: 
1.25      misho    1233:                                if (r->root_hooks.hook_exec.exception) {
                   1234:                                        if (r->root_hooks.hook_exec.exception(r, NULL)) {
                   1235:                                                task->task_type = taskUNUSE;
1.28      misho    1236:                                                insert_task_to(task, &r->root_unuse);
1.25      misho    1237:                                        } else {
                   1238:                                                task->task_type = taskREADY;
1.28      misho    1239:                                                insert_task_to(task, &r->root_ready);
1.25      misho    1240:                                        }
                   1241:                                } else {
                   1242:                                        task->task_type = taskREADY;
1.28      misho    1243:                                        insert_task_to(task, &r->root_ready);
1.25      misho    1244:                                }
1.32      misho    1245: 
                   1246:                                /* remove resouce */
                   1247:                                if (flg == 1)
                   1248:                                        FD_CLR(i, &r->root_fds[0]);
1.25      misho    1249:                        }
1.32      misho    1250:                } else if (FD_ISSET(i, &wfd)) {
1.25      misho    1251:                        flg = 0;
1.32      misho    1252:                        TAILQ_FOREACH_SAFE(t, &r->root_write, task_node, tmp) {
                   1253:                                if (TASK_FD(t) == i) {
                   1254:                                        if (!flg)
                   1255:                                                task = t;
1.25      misho    1256:                                        flg++;
                   1257:                                }
1.32      misho    1258:                        }
                   1259: 
                   1260:                        if (flg && task) {
                   1261:                                TASK_FLAG(task) = ioctl(TASK_FD(task), FIONWRITE, &TASK_RET(task));
                   1262: 
1.25      misho    1263:                                /* remove write handle */
1.28      misho    1264:                                remove_task_from(task, &r->root_write);
                   1265: 
1.25      misho    1266:                                if (r->root_hooks.hook_exec.exception) {
                   1267:                                        if (r->root_hooks.hook_exec.exception(r, NULL)) {
                   1268:                                                task->task_type = taskUNUSE;
1.28      misho    1269:                                                insert_task_to(task, &r->root_unuse);
1.25      misho    1270:                                        } else {
                   1271:                                                task->task_type = taskREADY;
1.28      misho    1272:                                                insert_task_to(task, &r->root_ready);
1.25      misho    1273:                                        }
                   1274:                                } else {
                   1275:                                        task->task_type = taskREADY;
1.28      misho    1276:                                        insert_task_to(task, &r->root_ready);
1.25      misho    1277:                                }
1.32      misho    1278: 
                   1279:                                /* remove resouce */
                   1280:                                if (flg == 1)
                   1281:                                        FD_CLR(i, &r->root_fds[1]);
1.25      misho    1282:                        }
                   1283:                }
                   1284:        }
                   1285: 
                   1286:        /* optimize select */
                   1287:        for (i = r->root_kq - 1; i > 2; i--)
                   1288:                if (FD_ISSET(i, &r->root_fds[0]) || FD_ISSET(i, &r->root_fds[1]))
                   1289:                        break;
                   1290:        if (i > 2)
                   1291:                r->root_kq = i + 1;
1.28      misho    1292: }
                   1293: #endif
                   1294: 
                   1295: /*
                   1296:  * sched_hook_fetch() - Default FETCH hook
                   1297:  *
                   1298:  * @root = root task
                   1299:  * @arg = unused
                   1300:  * return: NULL error or !=NULL fetched task
                   1301:  */
                   1302: void *
                   1303: sched_hook_fetch(void *root, void *arg __unused)
                   1304: {
                   1305:        sched_root_task_t *r = root;
                   1306:        sched_task_t *task, *tmp;
                   1307:        struct timespec now, m, mtmp;
                   1308: #if SUP_ENABLE == KQ_SUPPORT
                   1309:        struct kevent res[KQ_EVENTS];
                   1310:        struct timespec *timeout;
                   1311: #elif SUP_ENABLE == EP_SUPPORT
                   1312:        struct epoll_event res[KQ_EVENTS];
                   1313:        u_long timeout = 0;
                   1314: #else
                   1315:        struct timeval *timeout, tv;
                   1316:        fd_set rfd, wfd, xfd;
                   1317: #endif
                   1318:        int en;
                   1319: 
                   1320:        if (!r)
                   1321:                return NULL;
                   1322: 
                   1323:        /* get new task by queue priority */
                   1324:        while ((task = TAILQ_FIRST(&r->root_event))) {
                   1325:                transit_task2unuse(task, &r->root_event);
                   1326:                return task;
                   1327:        }
                   1328:        while ((task = TAILQ_FIRST(&r->root_ready))) {
                   1329:                transit_task2unuse(task, &r->root_ready);
                   1330:                return task;
                   1331:        }
                   1332: 
1.33      misho    1333:        /* if present member of task, set NOWAIT */
                   1334:        if (!TAILQ_FIRST(&r->root_task)) {
                   1335:                /* timer tasks */
1.28      misho    1336: #ifdef TIMER_WITHOUT_SORT
1.33      misho    1337:                clock_gettime(CLOCK_MONOTONIC, &now);
1.28      misho    1338: 
1.33      misho    1339:                sched_timespecclear(&r->root_wait);
                   1340:                TAILQ_FOREACH(task, &r->root_timer, task_node) {
                   1341:                        if (!sched_timespecisset(&r->root_wait))
                   1342:                                r->root_wait = TASK_TS(task);
                   1343:                        else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
                   1344:                                r->root_wait = TASK_TS(task);
                   1345:                }
                   1346: 
                   1347:                if (TAILQ_FIRST(&r->root_timer)) {
                   1348:                        m = r->root_wait;
                   1349:                        sched_timespecsub(&m, &now, &mtmp);
                   1350:                        r->root_wait = mtmp;
                   1351:                } else {
                   1352:                        /* set wait INFTIM */
                   1353:                        sched_timespecinf(&r->root_wait);
                   1354:                }
1.28      misho    1355: #else  /* ! TIMER_WITHOUT_SORT */
1.33      misho    1356:                if ((task = TAILQ_FIRST(&r->root_timer))) {
                   1357:                        clock_gettime(CLOCK_MONOTONIC, &now);
1.28      misho    1358: 
1.33      misho    1359:                        m = TASK_TS(task);
                   1360:                        sched_timespecsub(&m, &now, &mtmp);
                   1361:                        r->root_wait = mtmp;
                   1362:                } else {
                   1363:                        /* set wait INFTIM */
                   1364:                        sched_timespecinf(&r->root_wait);
                   1365:                }
1.28      misho    1366: #endif /* TIMER_WITHOUT_SORT */
1.33      misho    1367:        } else  /* no waiting for event, because we have ready task */
1.28      misho    1368:                sched_timespecclear(&r->root_wait);
                   1369: 
                   1370:        if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1) {
                   1371: #if SUP_ENABLE == KQ_SUPPORT
                   1372:                timeout = &r->root_wait;
                   1373: #elif SUP_ENABLE == EP_SUPPORT
                   1374:                timeout = r->root_wait.tv_sec * 1000 + r->root_wait.tv_nsec / 1000000;
                   1375: #else
                   1376:                sched_timespec2val(&r->root_wait, &tv);
                   1377:                timeout = &tv;
                   1378: #endif /* KQ_SUPPORT */
                   1379:        } else if (sched_timespecisinf(&r->root_poll))
                   1380: #if SUP_ENABLE == EP_SUPPORT
                   1381:                timeout = -1;
                   1382: #else
                   1383:                timeout = NULL;
                   1384: #endif
                   1385:        else {
                   1386: #if SUP_ENABLE == KQ_SUPPORT
                   1387:                timeout = &r->root_poll;
                   1388: #elif SUP_ENABLE == EP_SUPPORT
                   1389:                timeout = r->root_poll.tv_sec * 1000 + r->root_poll.tv_nsec / 1000000;
                   1390: #else
                   1391:                sched_timespec2val(&r->root_poll, &tv);
                   1392:                timeout = &tv;
                   1393: #endif /* KQ_SUPPORT */
                   1394:        }
                   1395: 
                   1396: #if SUP_ENABLE == KQ_SUPPORT
                   1397:        if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
                   1398: #elif SUP_ENABLE == EP_SUPPORT
                   1399:        if ((en = epoll_wait(r->root_kq, res, KQ_EVENTS, timeout)) == -1) {
                   1400: #else
                   1401:        rfd = xfd = r->root_fds[0];
                   1402:        wfd = r->root_fds[1];
                   1403:        if ((en = select(r->root_kq, &rfd, &wfd, &xfd, timeout)) == -1) {
                   1404: #endif /* KQ_SUPPORT */
                   1405:                if (r->root_hooks.hook_exec.exception) {
                   1406:                        if (r->root_hooks.hook_exec.exception(r, NULL))
                   1407:                                return NULL;
                   1408:                } else if (errno != EINTR)
                   1409:                        LOGERR;
                   1410:                goto skip_event;
                   1411:        }
                   1412: 
                   1413:        /* Go and catch the cat into pipes ... */
                   1414: #if SUP_ENABLE == KQ_SUPPORT
                   1415:        /* kevent dispatcher */
                   1416:        fetch_hook_kevent_proceed(en, res, r);
                   1417: #elif SUP_ENABLE == EP_SUPPORT
                   1418:        /* epoll dispatcher */
                   1419:        fetch_hook_epoll_proceed(en, res, r);
                   1420: #else
                   1421:        /* select dispatcher */
                   1422:        fetch_hook_select_proceed(en, rfd, wfd, xfd, r);
                   1423: #endif /* KQ_SUPPORT */
1.1       misho    1424: 
1.24      misho    1425: skip_event:
1.2       misho    1426:        /* timer update & put in ready queue */
1.4       misho    1427:        clock_gettime(CLOCK_MONOTONIC, &now);
1.1       misho    1428: 
1.6       misho    1429:        TAILQ_FOREACH_SAFE(task, &r->root_timer, task_node, tmp)
1.28      misho    1430:                if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0)
                   1431:                        transit_task2ready(task, &r->root_timer);
1.1       misho    1432: 
1.12      misho    1433:        /* put regular task priority task to ready queue, 
1.13      misho    1434:                if there is no ready task or reach max missing hit for regular task */
1.12      misho    1435:        if ((task = TAILQ_FIRST(&r->root_task))) {
1.13      misho    1436:                if (!TAILQ_FIRST(&r->root_ready) || r->root_miss >= TASK_VAL(task)) {
                   1437:                        r->root_miss ^= r->root_miss;
1.1       misho    1438: 
1.28      misho    1439:                        transit_task2ready(task, &r->root_task);
1.1       misho    1440:                } else
1.13      misho    1441:                        r->root_miss++;
1.1       misho    1442:        } else
1.13      misho    1443:                r->root_miss ^= r->root_miss;
1.1       misho    1444: 
                   1445:        /* OK, lets get ready task !!! */
1.6       misho    1446:        task = TAILQ_FIRST(&r->root_ready);
1.28      misho    1447:        if (task)
                   1448:                transit_task2unuse(task, &r->root_ready);
1.1       misho    1449:        return task;
                   1450: }
1.3       misho    1451: 
                   1452: /*
                   1453:  * sched_hook_exception() - Default EXCEPTION hook
1.5       misho    1454:  *
1.3       misho    1455:  * @root = root task
                   1456:  * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
                   1457:  * return: <0 errors and 0 ok
                   1458:  */
                   1459: void *
                   1460: sched_hook_exception(void *root, void *arg)
                   1461: {
                   1462:        sched_root_task_t *r = root;
                   1463: 
1.6       misho    1464:        if (!r)
1.3       misho    1465:                return NULL;
                   1466: 
                   1467:        /* custom exception handling ... */
                   1468:        if (arg) {
                   1469:                if (arg == (void*) EV_EOF)
                   1470:                        return NULL;
                   1471:                return (void*) -1;      /* raise scheduler error!!! */
                   1472:        }
                   1473: 
                   1474:        /* if error hook exists */
                   1475:        if (r->root_hooks.hook_root.error)
                   1476:                return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
                   1477: 
                   1478:        /* default case! */
                   1479:        LOGERR;
                   1480:        return NULL;
                   1481: }
1.5       misho    1482: 
                   1483: /*
                   1484:  * sched_hook_condition() - Default CONDITION hook
                   1485:  *
                   1486:  * @root = root task
                   1487:  * @arg = killState from schedRun()
                   1488:  * return: NULL kill scheduler loop or !=NULL ok
                   1489:  */
                   1490: void *
                   1491: sched_hook_condition(void *root, void *arg)
                   1492: {
                   1493:        sched_root_task_t *r = root;
                   1494: 
1.6       misho    1495:        if (!r)
1.5       misho    1496:                return NULL;
                   1497: 
1.28      misho    1498:        return (void*) (*r->root_cond - *(intptr_t*) arg);
1.5       misho    1499: }
1.19      misho    1500: 
                   1501: /*
                   1502:  * sched_hook_rtc() - Default RTC hook
                   1503:  *
                   1504:  * @task = current task
                   1505:  * @arg = unused
                   1506:  * return: <0 errors and 0 ok
                   1507:  */
                   1508: void *
                   1509: sched_hook_rtc(void *task, void *arg __unused)
                   1510: {
1.30      misho    1511: #if defined(HAVE_LIBRT) && defined(HAVE_TIMER_CREATE) && \
                   1512:        defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
1.19      misho    1513:        sched_task_t *sigt = NULL, *t = task;
                   1514:        struct itimerspec its;
                   1515:        struct sigevent evt;
                   1516:        timer_t tmr;
1.28      misho    1517: #if SUP_ENABLE != KQ_SUPPORT
                   1518:        struct sigaction sa;
                   1519: #endif
1.19      misho    1520: 
                   1521:        if (!t || !TASK_ROOT(t))
                   1522:                return (void*) -1;
                   1523: 
                   1524:        memset(&evt, 0, sizeof evt);
                   1525:        evt.sigev_notify = SIGEV_SIGNAL;
1.20      misho    1526:        evt.sigev_signo = (intptr_t) TASK_DATA(t) + SIGRTMIN;
1.28      misho    1527:        evt.sigev_value.sival_ptr = t;
1.19      misho    1528: 
                   1529:        if (timer_create(CLOCK_MONOTONIC, &evt, &tmr) == -1) {
                   1530:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                   1531:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                   1532:                else
                   1533:                        LOGERR;
                   1534:                return (void*) -1;
                   1535:        } else
                   1536:                TASK_FLAG(t) = (u_long) tmr;
                   1537: 
1.28      misho    1538: #if SUP_ENABLE == KQ_SUPPORT
1.21      misho    1539:        if (!(sigt = schedSignal(TASK_ROOT(t), _sched_rtcWrapper, TASK_ARG(t), evt.sigev_signo, 
                   1540:                                t, (size_t) tmr))) {
1.19      misho    1541:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                   1542:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                   1543:                else
                   1544:                        LOGERR;
                   1545:                timer_delete(tmr);
                   1546:                return (void*) -1;
                   1547:        } else
                   1548:                TASK_RET(t) = (uintptr_t) sigt;
1.28      misho    1549: #else
                   1550:        memset(&sa, 0, sizeof sa);
                   1551:        sigemptyset(&sa.sa_mask);
                   1552:        sa.sa_sigaction = _sched_rtcSigWrapper;
                   1553:        sa.sa_flags = SA_SIGINFO | SA_RESTART;
                   1554: 
                   1555:        if (sigaction(evt.sigev_signo, &sa, NULL) == -1) {
                   1556:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                   1557:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                   1558:                else
                   1559:                        LOGERR;
                   1560:                timer_delete(tmr);
                   1561:                return (void*) -1;
                   1562:        }
                   1563: #endif
1.19      misho    1564: 
                   1565:        memset(&its, 0, sizeof its);
                   1566:        its.it_value.tv_sec = t->task_val.ts.tv_sec;
                   1567:        its.it_value.tv_nsec = t->task_val.ts.tv_nsec;
                   1568: 
                   1569:        if (timer_settime(tmr, TIMER_RELTIME, &its, NULL) == -1) {
                   1570:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                   1571:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                   1572:                else
                   1573:                        LOGERR;
                   1574:                schedCancel(sigt);
                   1575:                timer_delete(tmr);
                   1576:                return (void*) -1;
                   1577:        }
1.30      misho    1578: #endif /* HAVE_TIMER_CREATE */
1.19      misho    1579:        return NULL;
                   1580: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>