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

1.1       misho       1: /*************************************************************************
                      2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
                      3: *  by Michael Pounov <misho@openbsd-bg.org>
                      4: *
                      5: * $Author: misho $
1.7.2.3 ! misho       6: * $Id: hooks.c,v 1.7.2.2 2012/05/31 14:45:10 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.5       misho      15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
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: 
                     50: /*
                     51:  * sched_hook_init() - Default INIT hook
1.5       misho      52:  *
1.1       misho      53:  * @root = root task
1.6       misho      54:  * @arg = unused
1.1       misho      55:  * return: <0 errors and 0 ok
                     56:  */
                     57: void *
1.6       misho      58: sched_hook_init(void *root, void *arg __unused)
1.1       misho      59: {
                     60:        sched_root_task_t *r = root;
                     61: 
1.6       misho      62:        if (!r)
1.1       misho      63:                return (void*) -1;
                     64: 
                     65:        r->root_kq = kqueue();
                     66:        if (r->root_kq == -1) {
                     67:                LOGERR;
                     68:                return (void*) -1;
                     69:        }
                     70: 
                     71:        return NULL;
                     72: }
                     73: 
                     74: /*
                     75:  * sched_hook_fini() - Default FINI hook
1.5       misho      76:  *
1.1       misho      77:  * @root = root task
                     78:  * @arg = unused
                     79:  * return: <0 errors and 0 ok
                     80:  */
                     81: void *
                     82: sched_hook_fini(void *root, void *arg __unused)
                     83: {
                     84:        sched_root_task_t *r = root;
                     85: 
                     86:        if (!r)
                     87:                return (void*) -1;
                     88: 
                     89:        if (r->root_kq > 2) {
                     90:                close(r->root_kq);
                     91:                r->root_kq = 0;
                     92:        }
                     93: 
                     94:        return NULL;
                     95: }
                     96: 
                     97: /*
                     98:  * sched_hook_cancel() - Default CANCEL hook
1.5       misho      99:  *
1.1       misho     100:  * @task = current task
                    101:  * @arg = unused
                    102:  * return: <0 errors and 0 ok
                    103:  */
                    104: void *
                    105: sched_hook_cancel(void *task, void *arg __unused)
                    106: {
                    107:        sched_task_t *t = task;
                    108:        struct kevent chg[1];
1.2       misho     109:        struct timespec timeout = { 0, 0 };
1.1       misho     110: 
1.6       misho     111:        if (!t || !TASK_ROOT(t))
1.1       misho     112:                return (void*) -1;
                    113: 
1.4       misho     114:        switch (TASK_TYPE(t)) {
1.1       misho     115:                case taskREAD:
1.2       misho     116: #ifdef __NetBSD__
                    117:                        EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
                    118: #else
                    119:                        EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (void*) TASK_FD(t));
                    120: #endif
1.1       misho     121:                        break;
                    122:                case taskWRITE:
1.2       misho     123: #ifdef __NetBSD__
                    124:                        EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
                    125: #else
                    126:                        EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
                    127: #endif
1.1       misho     128:                        break;
1.7       misho     129:                case taskALARM:
                    130: #ifdef __NetBSD__
                    131:                        EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE, 
                    132:                                        0, 0, (intptr_t) TASK_DATA(t));
                    133: #else
                    134:                        EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE, 
                    135:                                        0, 0, (void*) TASK_DATA(t));
                    136: #endif
                    137:                        break;
1.7.2.1   misho     138:                case taskNODE:
                    139: #ifdef __NetBSD__
                    140:                        EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
                    141: #else
                    142:                        EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
                    143: #endif
1.1       misho     144:                        break;
1.7.2.1   misho     145:                case taskPROC:
                    146: #ifdef __NetBSD__
                    147:                        EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
                    148: #else
                    149:                        EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
                    150: #endif
                    151:                        break;
                    152:                case taskSIGNAL:
                    153: #ifdef __NetBSD__
                    154:                        EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
                    155: #else
                    156:                        EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
                    157: #endif
                    158:                        break;
                    159:                case taskUSER:
                    160: #ifdef __NetBSD__
                    161:                        EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
                    162: #else
                    163:                        EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
                    164: #endif
                    165:                        break;
                    166:                default:
1.7.2.3 ! misho     167:                        return NULL;
1.1       misho     168:        }
                    169: 
1.7.2.1   misho     170:        kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout);
1.1       misho     171:        return NULL;
                    172: }
                    173: 
                    174: /*
                    175:  * sched_hook_read() - Default READ hook
1.5       misho     176:  *
1.1       misho     177:  * @task = current task
                    178:  * @arg = unused
                    179:  * return: <0 errors and 0 ok
                    180:  */
                    181: void *
                    182: sched_hook_read(void *task, void *arg __unused)
                    183: {
                    184:        sched_task_t *t = task;
                    185:        struct kevent chg[1];
1.2       misho     186:        struct timespec timeout = { 0, 0 };
1.1       misho     187: 
1.6       misho     188:        if (!t || !TASK_ROOT(t))
1.1       misho     189:                return (void*) -1;
                    190: 
1.2       misho     191: #ifdef __NetBSD__
1.7.2.1   misho     192:        EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
1.2       misho     193: #else
1.7.2.1   misho     194:        EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
1.2       misho     195: #endif
1.4       misho     196:        if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
                    197:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                    198:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1.3       misho     199:                else
                    200:                        LOGERR;
1.1       misho     201:                return (void*) -1;
                    202:        }
                    203: 
                    204:        return NULL;
                    205: }
                    206: 
                    207: /*
                    208:  * sched_hook_write() - Default WRITE hook
1.5       misho     209:  *
1.1       misho     210:  * @task = current task
                    211:  * @arg = unused
                    212:  * return: <0 errors and 0 ok
                    213:  */
                    214: void *
                    215: sched_hook_write(void *task, void *arg __unused)
                    216: {
                    217:        sched_task_t *t = task;
                    218:        struct kevent chg[1];
1.2       misho     219:        struct timespec timeout = { 0, 0 };
1.1       misho     220: 
1.6       misho     221:        if (!t || !TASK_ROOT(t))
1.1       misho     222:                return (void*) -1;
                    223: 
1.2       misho     224: #ifdef __NetBSD__
1.7.2.1   misho     225:        EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
1.2       misho     226: #else
1.7.2.1   misho     227:        EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
1.2       misho     228: #endif
1.4       misho     229:        if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
                    230:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                    231:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1.3       misho     232:                else
                    233:                        LOGERR;
1.1       misho     234:                return (void*) -1;
                    235:        }
                    236: 
                    237:        return NULL;
                    238: }
                    239: 
                    240: /*
1.7       misho     241:  * sched_hook_alarm() - Default ALARM hook
                    242:  *
                    243:  * @task = current task
                    244:  * @arg = unused
                    245:  * return: <0 errors and 0 ok
                    246:  */
                    247: void *
                    248: sched_hook_alarm(void *task, void *arg __unused)
                    249: {
                    250:        sched_task_t *t = task;
                    251:        struct kevent chg[1];
                    252:        struct timespec timeout = { 0, 0 };
                    253: 
                    254:        if (!t || !TASK_ROOT(t))
                    255:                return (void*) -1;
                    256: 
                    257: #ifdef __NetBSD__
                    258:        EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 
                    259:                        t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000, 
                    260:                        (intptr_t) TASK_DATA(t));
                    261: #else
                    262:        EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 
                    263:                        t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000, 
                    264:                        (void*) TASK_DATA(t));
                    265: #endif
                    266:        if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
                    267:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                    268:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                    269:                else
                    270:                        LOGERR;
                    271:                return (void*) -1;
                    272:        }
                    273: 
                    274:        return NULL;
                    275: }
                    276: 
                    277: /*
1.7.2.1   misho     278:  * sched_hook_node() - Default NODE hook
                    279:  *
                    280:  * @task = current task
                    281:  * @arg = unused
                    282:  * return: <0 errors and 0 ok
                    283:  */
                    284: void *
                    285: sched_hook_node(void *task, void *arg __unused)
                    286: {
                    287:        sched_task_t *t = task;
                    288:        struct kevent chg[1];
                    289:        struct timespec timeout = { 0, 0 };
                    290: 
                    291:        if (!t || !TASK_ROOT(t))
                    292:                return (void*) -1;
                    293: 
                    294: #ifdef __NetBSD__
                    295:        EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR, 
                    296:                        NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | 
                    297:                        NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (intptr_t) TASK_FD(t));
                    298: #else
                    299:        EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR, 
                    300:                        NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | 
                    301:                        NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (void*) TASK_FD(t));
                    302: #endif
                    303:        if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
                    304:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                    305:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                    306:                else
                    307:                        LOGERR;
                    308:                return (void*) -1;
                    309:        }
                    310: 
                    311:        return NULL;
                    312: }
                    313: 
                    314: /*
                    315:  * sched_hook_proc() - Default PROC hook
                    316:  *
                    317:  * @task = current task
                    318:  * @arg = unused
                    319:  * return: <0 errors and 0 ok
                    320:  */
                    321: void *
                    322: sched_hook_proc(void *task, void *arg __unused)
                    323: {
                    324:        sched_task_t *t = task;
                    325:        struct kevent chg[1];
                    326:        struct timespec timeout = { 0, 0 };
                    327: 
                    328:        if (!t || !TASK_ROOT(t))
                    329:                return (void*) -1;
                    330: 
                    331: #ifdef __NetBSD__
                    332:        EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR, 
                    333:                        NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (intptr_t) TASK_VAL(t));
                    334: #else
                    335:        EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR, 
                    336:                        NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (void*) TASK_VAL(t));
                    337: #endif
                    338:        if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
                    339:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                    340:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                    341:                else
                    342:                        LOGERR;
                    343:                return (void*) -1;
                    344:        }
                    345: 
                    346:        return NULL;
                    347: }
                    348: 
                    349: /*
                    350:  * sched_hook_signal() - Default SIGNAL hook
                    351:  *
                    352:  * @task = current task
                    353:  * @arg = unused
                    354:  * return: <0 errors and 0 ok
                    355:  */
                    356: void *
                    357: sched_hook_signal(void *task, void *arg __unused)
                    358: {
                    359:        sched_task_t *t = task;
                    360:        struct kevent chg[1];
                    361:        struct timespec timeout = { 0, 0 };
                    362: 
                    363:        if (!t || !TASK_ROOT(t))
                    364:                return (void*) -1;
                    365: 
                    366: #ifdef __NetBSD__
                    367:        EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD, 0, 0, (intptr_t) TASK_VAL(t));
                    368: #else
                    369:        EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD, 0, 0, (void*) TASK_VAL(t));
                    370: #endif
                    371:        if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
                    372:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                    373:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                    374:                else
                    375:                        LOGERR;
                    376:                return (void*) -1;
                    377:        }
                    378: 
                    379:        return NULL;
                    380: }
                    381: 
                    382: /*
                    383:  * sched_hook_user() - Default USER hook
                    384:  *
                    385:  * @task = current task
                    386:  * @arg = unused
                    387:  * return: <0 errors and 0 ok
                    388:  */
                    389: void *
                    390: sched_hook_user(void *task, void *arg __unused)
                    391: {
                    392:        sched_task_t *t = task;
                    393:        struct kevent chg[1];
                    394:        struct timespec timeout = { 0, 0 };
                    395: 
                    396:        if (!t || !TASK_ROOT(t))
                    397:                return (void*) -1;
                    398: 
                    399: #ifdef __NetBSD__
1.7.2.2   misho     400:        EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t), 
                    401:                        0, (intptr_t) TASK_VAL(t));
1.7.2.1   misho     402: #else
1.7.2.2   misho     403:        EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t), 
                    404:                        0, (void*) TASK_VAL(t));
1.7.2.1   misho     405: #endif
                    406:        if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
                    407:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
                    408:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
                    409:                else
                    410:                        LOGERR;
                    411:                return (void*) -1;
                    412:        }
                    413: 
                    414:        return NULL;
                    415: }
                    416: 
                    417: /*
1.1       misho     418:  * sched_hook_fetch() - Default FETCH hook
1.5       misho     419:  *
1.1       misho     420:  * @root = root task
                    421:  * @arg = unused
                    422:  * return: NULL error or !=NULL fetched task
                    423:  */
                    424: void *
                    425: sched_hook_fetch(void *root, void *arg __unused)
                    426: {
                    427:        sched_root_task_t *r = root;
1.6       misho     428:        sched_task_t *task, *tmp;
1.4       misho     429:        struct timespec now, m, mtmp;
                    430:        struct timespec *timeout;
1.1       misho     431:        struct kevent evt[1], res[KQ_EVENTS];
                    432:        register int i;
                    433:        int en;
                    434: 
1.6       misho     435:        if (!r)
1.1       misho     436:                return NULL;
                    437: 
                    438:        /* get new task by queue priority */
                    439:        while ((task = TAILQ_FIRST(&r->root_event))) {
1.4       misho     440: #ifdef HAVE_LIBPTHREAD
                    441:                pthread_mutex_lock(&r->root_mtx[taskEVENT]);
                    442: #endif
1.1       misho     443:                TAILQ_REMOVE(&r->root_event, task, task_node);
1.4       misho     444: #ifdef HAVE_LIBPTHREAD
                    445:                pthread_mutex_unlock(&r->root_mtx[taskEVENT]);
                    446: #endif
1.1       misho     447:                task->task_type = taskUNUSE;
1.4       misho     448: #ifdef HAVE_LIBPTHREAD
                    449:                pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    450: #endif
1.1       misho     451:                TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     452: #ifdef HAVE_LIBPTHREAD
                    453:                pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    454: #endif
1.1       misho     455:                return task;
                    456:        }
                    457:        while ((task = TAILQ_FIRST(&r->root_ready))) {
1.4       misho     458: #ifdef HAVE_LIBPTHREAD
                    459:                pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    460: #endif
1.1       misho     461:                TAILQ_REMOVE(&r->root_ready, task, task_node);
1.4       misho     462: #ifdef HAVE_LIBPTHREAD
                    463:                pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    464: #endif
1.1       misho     465:                task->task_type = taskUNUSE;
1.4       misho     466: #ifdef HAVE_LIBPTHREAD
                    467:                pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    468: #endif
1.1       misho     469:                TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     470: #ifdef HAVE_LIBPTHREAD
                    471:                pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    472: #endif
1.1       misho     473:                return task;
                    474:        }
                    475: 
                    476: #ifdef TIMER_WITHOUT_SORT
1.4       misho     477:        clock_gettime(CLOCK_MONOTONIC, &now);
1.1       misho     478: 
1.4       misho     479:        sched_timespecclear(&r->root_wait);
1.1       misho     480:        TAILQ_FOREACH(task, &r->root_timer, task_node) {
1.4       misho     481:                if (!sched_timespecisset(&r->root_wait))
                    482:                        r->root_wait = TASK_TS(task);
                    483:                else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
                    484:                        r->root_wait = TASK_TS(task);
1.1       misho     485:        }
                    486: 
                    487:        if (TAILQ_FIRST(&r->root_timer)) {
                    488:                m = r->root_wait;
1.4       misho     489:                sched_timespecsub(&m, &now, &mtmp);
1.1       misho     490:                r->root_wait = mtmp;
                    491:        } else {
                    492:                /* set wait INFTIM */
1.4       misho     493:                sched_timespecinf(&r->root_wait);
1.1       misho     494:        }
                    495: #else
                    496:        if (!TAILQ_FIRST(&r->root_eventlo) && (task = TAILQ_FIRST(&r->root_timer))) {
1.4       misho     497:                clock_gettime(CLOCK_MONOTONIC, &now);
1.1       misho     498: 
1.4       misho     499:                m = TASK_TS(task);
                    500:                sched_timespecsub(&m, &now, &mtmp);
1.1       misho     501:                r->root_wait = mtmp;
                    502:        } else {
                    503:                /* set wait INFTIM */
1.4       misho     504:                sched_timespecinf(&r->root_wait);
1.1       misho     505:        }
                    506: #endif
                    507:        /* if present member of eventLo, set NOWAIT */
                    508:        if (TAILQ_FIRST(&r->root_eventlo))
1.4       misho     509:                sched_timespecclear(&r->root_wait);
1.1       misho     510: 
1.4       misho     511:        if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1)
                    512:                timeout = &r->root_wait;
                    513:        else if (sched_timespecisinf(&r->root_poll))
1.1       misho     514:                timeout = NULL;
1.4       misho     515:        else
                    516:                timeout = &r->root_poll;
1.1       misho     517:        if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
1.3       misho     518:                if (r->root_hooks.hook_exec.exception) {
                    519:                        if (r->root_hooks.hook_exec.exception(r, NULL))
                    520:                                return NULL;
1.6       misho     521:                } else if (errno != EINTR)
1.3       misho     522:                        LOGERR;
1.2       misho     523:                return NULL;
1.1       misho     524:        }
                    525: 
1.4       misho     526:        now.tv_sec = now.tv_nsec = 0;
1.1       misho     527:        /* Go and catch the cat into pipes ... */
                    528:        for (i = 0; i < en; i++) {
                    529:                memcpy(evt, &res[i], sizeof evt);
                    530:                evt->flags = EV_DELETE;
                    531:                /* Put read/write task to ready queue */
                    532:                switch (res[i].filter) {
                    533:                        case EVFILT_READ:
1.6       misho     534:                                TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) {
1.3       misho     535:                                        if (TASK_FD(task) != ((intptr_t) res[i].udata))
1.1       misho     536:                                                continue;
                    537:                                        /* remove read handle */
1.4       misho     538: #ifdef HAVE_LIBPTHREAD
                    539:                                        pthread_mutex_lock(&r->root_mtx[taskREAD]);
                    540: #endif
1.1       misho     541:                                        TAILQ_REMOVE(&r->root_read, task, task_node);
1.4       misho     542: #ifdef HAVE_LIBPTHREAD
                    543:                                        pthread_mutex_unlock(&r->root_mtx[taskREAD]);
                    544: #endif
1.3       misho     545:                                        if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
                    546:                                                if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
                    547:                                                        task->task_type = taskUNUSE;
1.4       misho     548: #ifdef HAVE_LIBPTHREAD
                    549:                                                        pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    550: #endif
1.3       misho     551:                                                        TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     552: #ifdef HAVE_LIBPTHREAD
                    553:                                                        pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    554: #endif
1.3       misho     555:                                                } else {
                    556:                                                        task->task_type = taskREADY;
1.4       misho     557: #ifdef HAVE_LIBPTHREAD
                    558:                                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    559: #endif
1.3       misho     560:                                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     561: #ifdef HAVE_LIBPTHREAD
                    562:                                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    563: #endif
1.3       misho     564:                                                }
                    565:                                        } else {
1.2       misho     566:                                                task->task_type = taskREADY;
1.4       misho     567: #ifdef HAVE_LIBPTHREAD
                    568:                                                pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    569: #endif
1.2       misho     570:                                                TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     571: #ifdef HAVE_LIBPTHREAD
                    572:                                                pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    573: #endif
1.3       misho     574:                                        }
1.1       misho     575:                                        break;
                    576:                                }
                    577:                                break;
                    578:                        case EVFILT_WRITE:
1.6       misho     579:                                TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) {
1.3       misho     580:                                        if (TASK_FD(task) != ((intptr_t) res[i].udata))
1.1       misho     581:                                                continue;
                    582:                                        /* remove write handle */
1.4       misho     583: #ifdef HAVE_LIBPTHREAD
                    584:                                        pthread_mutex_lock(&r->root_mtx[taskWRITE]);
                    585: #endif
1.1       misho     586:                                        TAILQ_REMOVE(&r->root_write, task, task_node);
1.4       misho     587: #ifdef HAVE_LIBPTHREAD
                    588:                                        pthread_mutex_unlock(&r->root_mtx[taskWRITE]);
                    589: #endif
1.3       misho     590:                                        if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
                    591:                                                if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
                    592:                                                        task->task_type = taskUNUSE;
1.4       misho     593: #ifdef HAVE_LIBPTHREAD
                    594:                                                        pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    595: #endif
1.3       misho     596:                                                        TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     597: #ifdef HAVE_LIBPTHREAD
                    598:                                                        pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    599: #endif
1.3       misho     600:                                                } else {
                    601:                                                        task->task_type = taskREADY;
1.4       misho     602: #ifdef HAVE_LIBPTHREAD
                    603:                                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    604: #endif
1.3       misho     605:                                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     606: #ifdef HAVE_LIBPTHREAD
                    607:                                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    608: #endif
1.3       misho     609:                                                }
                    610:                                        } else {
1.2       misho     611:                                                task->task_type = taskREADY;
1.4       misho     612: #ifdef HAVE_LIBPTHREAD
                    613:                                                pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    614: #endif
1.2       misho     615:                                                TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     616: #ifdef HAVE_LIBPTHREAD
                    617:                                                pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    618: #endif
1.3       misho     619:                                        }
1.1       misho     620:                                        break;
                    621:                                }
                    622:                                break;
1.7       misho     623:                        case EVFILT_TIMER:
                    624:                                TAILQ_FOREACH_SAFE(task, &r->root_alarm, task_node, tmp) {
                    625:                                        if ((uintptr_t) TASK_DATA(task) != ((uintptr_t) res[i].udata))
                    626:                                                continue;
                    627:                                        /* remove alarm handle */
                    628: #ifdef HAVE_LIBPTHREAD
                    629:                                        pthread_mutex_lock(&r->root_mtx[taskALARM]);
                    630: #endif
                    631:                                        TAILQ_REMOVE(&r->root_alarm, task, task_node);
                    632: #ifdef HAVE_LIBPTHREAD
                    633:                                        pthread_mutex_unlock(&r->root_mtx[taskALARM]);
                    634: #endif
                    635:                                        task->task_type = taskREADY;
                    636: #ifdef HAVE_LIBPTHREAD
                    637:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    638: #endif
                    639:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
                    640: #ifdef HAVE_LIBPTHREAD
                    641:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    642: #endif
                    643:                                        break;
                    644:                                }
                    645:                                break;
1.7.2.1   misho     646:                        case EVFILT_VNODE:
                    647:                                TAILQ_FOREACH_SAFE(task, &r->root_node, task_node, tmp) {
                    648:                                        if (TASK_FD(task) != ((intptr_t) res[i].udata))
                    649:                                                continue;
1.7.2.2   misho     650:                                        else {
                    651:                                                TASK_DATA(task) = (void*) res[i].data;
                    652:                                                TASK_DATLEN(task) = res[i].fflags;
                    653:                                        }
1.7.2.1   misho     654:                                        /* remove node handle */
                    655: #ifdef HAVE_LIBPTHREAD
                    656:                                        pthread_mutex_lock(&r->root_mtx[taskNODE]);
                    657: #endif
                    658:                                        TAILQ_REMOVE(&r->root_node, task, task_node);
                    659: #ifdef HAVE_LIBPTHREAD
                    660:                                        pthread_mutex_unlock(&r->root_mtx[taskNODE]);
                    661: #endif
                    662:                                        task->task_type = taskREADY;
                    663: #ifdef HAVE_LIBPTHREAD
                    664:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    665: #endif
                    666:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
                    667: #ifdef HAVE_LIBPTHREAD
                    668:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    669: #endif
                    670:                                        break;
                    671:                                }
                    672:                                break;
                    673:                        case EVFILT_PROC:
                    674:                                TAILQ_FOREACH_SAFE(task, &r->root_proc, task_node, tmp) {
                    675:                                        if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
                    676:                                                continue;
1.7.2.2   misho     677:                                        else {
                    678:                                                TASK_DATA(task) = (void*) res[i].data;
                    679:                                                TASK_DATLEN(task) = res[i].fflags;
                    680:                                        }
1.7.2.1   misho     681:                                        /* remove proc handle */
                    682: #ifdef HAVE_LIBPTHREAD
                    683:                                        pthread_mutex_lock(&r->root_mtx[taskPROC]);
                    684: #endif
                    685:                                        TAILQ_REMOVE(&r->root_proc, task, task_node);
                    686: #ifdef HAVE_LIBPTHREAD
                    687:                                        pthread_mutex_unlock(&r->root_mtx[taskPROC]);
                    688: #endif
                    689:                                        task->task_type = taskREADY;
                    690: #ifdef HAVE_LIBPTHREAD
                    691:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    692: #endif
                    693:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
                    694: #ifdef HAVE_LIBPTHREAD
                    695:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    696: #endif
                    697:                                        break;
                    698:                                }
                    699:                                break;
                    700:                        case EVFILT_SIGNAL:
                    701:                                TAILQ_FOREACH_SAFE(task, &r->root_signal, task_node, tmp) {
                    702:                                        if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
                    703:                                                continue;
                    704:                                        /* remove signal handle */
                    705: #ifdef HAVE_LIBPTHREAD
                    706:                                        pthread_mutex_lock(&r->root_mtx[taskSIGNAL]);
                    707: #endif
                    708:                                        TAILQ_REMOVE(&r->root_signal, task, task_node);
                    709: #ifdef HAVE_LIBPTHREAD
                    710:                                        pthread_mutex_unlock(&r->root_mtx[taskSIGNAL]);
                    711: #endif
                    712:                                        task->task_type = taskREADY;
                    713: #ifdef HAVE_LIBPTHREAD
                    714:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    715: #endif
                    716:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
                    717: #ifdef HAVE_LIBPTHREAD
                    718:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    719: #endif
                    720:                                        break;
                    721:                                }
                    722:                                break;
                    723:                        case EVFILT_USER:
                    724:                                TAILQ_FOREACH_SAFE(task, &r->root_user, task_node, tmp) {
                    725:                                        if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
                    726:                                                continue;
1.7.2.2   misho     727:                                        else {
                    728:                                                TASK_DATA(task) = (void*) res[i].data;
                    729:                                                TASK_DATLEN(task) = res[i].fflags;
                    730:                                        }
1.7.2.1   misho     731:                                        /* remove user handle */
                    732: #ifdef HAVE_LIBPTHREAD
                    733:                                        pthread_mutex_lock(&r->root_mtx[taskUSER]);
                    734: #endif
                    735:                                        TAILQ_REMOVE(&r->root_user, task, task_node);
                    736: #ifdef HAVE_LIBPTHREAD
                    737:                                        pthread_mutex_unlock(&r->root_mtx[taskUSER]);
                    738: #endif
                    739:                                        task->task_type = taskREADY;
                    740: #ifdef HAVE_LIBPTHREAD
                    741:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    742: #endif
                    743:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
                    744: #ifdef HAVE_LIBPTHREAD
                    745:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    746: #endif
                    747:                                        break;
                    748:                                }
                    749:                                break;
1.1       misho     750:                }
1.4       misho     751:                if (kevent(r->root_kq, evt, 1, NULL, 0, &now) == -1) {
1.3       misho     752:                        if (r->root_hooks.hook_exec.exception) {
                    753:                                if (r->root_hooks.hook_exec.exception(r, NULL))
                    754:                                        return NULL;
                    755:                        } else
                    756:                                LOGERR;
                    757:                }
1.1       misho     758:        }
                    759: 
1.2       misho     760:        /* timer update & put in ready queue */
1.4       misho     761:        clock_gettime(CLOCK_MONOTONIC, &now);
1.1       misho     762: 
1.6       misho     763:        TAILQ_FOREACH_SAFE(task, &r->root_timer, task_node, tmp)
1.4       misho     764:                if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0) {
                    765: #ifdef HAVE_LIBPTHREAD
                    766:                        pthread_mutex_lock(&r->root_mtx[taskTIMER]);
                    767: #endif
1.1       misho     768:                        TAILQ_REMOVE(&r->root_timer, task, task_node);
1.4       misho     769: #ifdef HAVE_LIBPTHREAD
                    770:                        pthread_mutex_unlock(&r->root_mtx[taskTIMER]);
                    771: #endif
1.1       misho     772:                        task->task_type = taskREADY;
1.4       misho     773: #ifdef HAVE_LIBPTHREAD
                    774:                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    775: #endif
1.1       misho     776:                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     777: #ifdef HAVE_LIBPTHREAD
                    778:                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    779: #endif
1.1       misho     780:                }
                    781: 
                    782:        /* put eventlo priority task to ready queue, if there is no ready task or 
                    783:                reach max missed fetch-rotate */
                    784:        if ((task = TAILQ_FIRST(&r->root_eventlo))) {
                    785:                if (!TAILQ_FIRST(&r->root_ready) || r->root_eventlo_miss > MAX_EVENTLO_MISS) {
                    786:                        r->root_eventlo_miss = 0;
                    787: 
1.4       misho     788: #ifdef HAVE_LIBPTHREAD
                    789:                        pthread_mutex_lock(&r->root_mtx[taskEVENTLO]);
                    790: #endif
1.1       misho     791:                        TAILQ_REMOVE(&r->root_eventlo, task, task_node);
1.4       misho     792: #ifdef HAVE_LIBPTHREAD
                    793:                        pthread_mutex_unlock(&r->root_mtx[taskEVENTLO]);
                    794: #endif
1.1       misho     795:                        task->task_type = taskREADY;
1.4       misho     796: #ifdef HAVE_LIBPTHREAD
                    797:                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    798: #endif
1.1       misho     799:                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     800: #ifdef HAVE_LIBPTHREAD
                    801:                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    802: #endif
1.1       misho     803:                } else
                    804:                        r->root_eventlo_miss++;
                    805:        } else
                    806:                r->root_eventlo_miss = 0;
                    807: 
                    808:        /* OK, lets get ready task !!! */
1.6       misho     809:        task = TAILQ_FIRST(&r->root_ready);
                    810:        if (!(task))
                    811:                return NULL;
                    812: 
1.4       misho     813: #ifdef HAVE_LIBPTHREAD
                    814:        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    815: #endif
1.1       misho     816:        TAILQ_REMOVE(&r->root_ready, task, task_node);
1.4       misho     817: #ifdef HAVE_LIBPTHREAD
                    818:        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    819: #endif
1.1       misho     820:        task->task_type = taskUNUSE;
1.4       misho     821: #ifdef HAVE_LIBPTHREAD
                    822:        pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    823: #endif
1.1       misho     824:        TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     825: #ifdef HAVE_LIBPTHREAD
                    826:        pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    827: #endif
1.1       misho     828:        return task;
                    829: }
1.3       misho     830: 
                    831: /*
                    832:  * sched_hook_exception() - Default EXCEPTION hook
1.5       misho     833:  *
1.3       misho     834:  * @root = root task
                    835:  * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
                    836:  * return: <0 errors and 0 ok
                    837:  */
                    838: void *
                    839: sched_hook_exception(void *root, void *arg)
                    840: {
                    841:        sched_root_task_t *r = root;
                    842: 
1.6       misho     843:        if (!r)
1.3       misho     844:                return NULL;
                    845: 
                    846:        /* custom exception handling ... */
                    847:        if (arg) {
                    848:                if (arg == (void*) EV_EOF)
                    849:                        return NULL;
                    850:                return (void*) -1;      /* raise scheduler error!!! */
                    851:        }
                    852: 
                    853:        /* if error hook exists */
                    854:        if (r->root_hooks.hook_root.error)
                    855:                return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
                    856: 
                    857:        /* default case! */
                    858:        LOGERR;
                    859:        return NULL;
                    860: }
1.5       misho     861: 
                    862: /*
                    863:  * sched_hook_condition() - Default CONDITION hook
                    864:  *
                    865:  * @root = root task
                    866:  * @arg = killState from schedRun()
                    867:  * return: NULL kill scheduler loop or !=NULL ok
                    868:  */
                    869: void *
                    870: sched_hook_condition(void *root, void *arg)
                    871: {
                    872:        sched_root_task_t *r = root;
                    873: 
1.6       misho     874:        if (!r)
1.5       misho     875:                return NULL;
                    876: 
                    877:        return (void*) (r->root_cond - *(intptr_t*) arg);
                    878: }

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