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

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.1 ! misho       6: * $Id: hooks.c,v 1.7 2012/05/30 08:52:45 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:
        !           167:                        return (void*) -1;
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__
        !           400:        EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, NOTE_FFNOP, 0, (intptr_t) TASK_VAL(t));
        !           401: #else
        !           402:        EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, NOTE_FFNOP, 0, (void*) TASK_VAL(t));
        !           403: #endif
        !           404:        if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
        !           405:                if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
        !           406:                        TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
        !           407:                else
        !           408:                        LOGERR;
        !           409:                return (void*) -1;
        !           410:        }
        !           411: 
        !           412:        return NULL;
        !           413: }
        !           414: 
        !           415: /*
1.1       misho     416:  * sched_hook_fetch() - Default FETCH hook
1.5       misho     417:  *
1.1       misho     418:  * @root = root task
                    419:  * @arg = unused
                    420:  * return: NULL error or !=NULL fetched task
                    421:  */
                    422: void *
                    423: sched_hook_fetch(void *root, void *arg __unused)
                    424: {
                    425:        sched_root_task_t *r = root;
1.6       misho     426:        sched_task_t *task, *tmp;
1.4       misho     427:        struct timespec now, m, mtmp;
                    428:        struct timespec *timeout;
1.1       misho     429:        struct kevent evt[1], res[KQ_EVENTS];
                    430:        register int i;
                    431:        int en;
                    432: 
1.6       misho     433:        if (!r)
1.1       misho     434:                return NULL;
                    435: 
                    436:        /* get new task by queue priority */
                    437:        while ((task = TAILQ_FIRST(&r->root_event))) {
1.4       misho     438: #ifdef HAVE_LIBPTHREAD
                    439:                pthread_mutex_lock(&r->root_mtx[taskEVENT]);
                    440: #endif
1.1       misho     441:                TAILQ_REMOVE(&r->root_event, task, task_node);
1.4       misho     442: #ifdef HAVE_LIBPTHREAD
                    443:                pthread_mutex_unlock(&r->root_mtx[taskEVENT]);
                    444: #endif
1.1       misho     445:                task->task_type = taskUNUSE;
1.4       misho     446: #ifdef HAVE_LIBPTHREAD
                    447:                pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    448: #endif
1.1       misho     449:                TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     450: #ifdef HAVE_LIBPTHREAD
                    451:                pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    452: #endif
1.1       misho     453:                return task;
                    454:        }
                    455:        while ((task = TAILQ_FIRST(&r->root_ready))) {
1.4       misho     456: #ifdef HAVE_LIBPTHREAD
                    457:                pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    458: #endif
1.1       misho     459:                TAILQ_REMOVE(&r->root_ready, task, task_node);
1.4       misho     460: #ifdef HAVE_LIBPTHREAD
                    461:                pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    462: #endif
1.1       misho     463:                task->task_type = taskUNUSE;
1.4       misho     464: #ifdef HAVE_LIBPTHREAD
                    465:                pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    466: #endif
1.1       misho     467:                TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     468: #ifdef HAVE_LIBPTHREAD
                    469:                pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    470: #endif
1.1       misho     471:                return task;
                    472:        }
                    473: 
                    474: #ifdef TIMER_WITHOUT_SORT
1.4       misho     475:        clock_gettime(CLOCK_MONOTONIC, &now);
1.1       misho     476: 
1.4       misho     477:        sched_timespecclear(&r->root_wait);
1.1       misho     478:        TAILQ_FOREACH(task, &r->root_timer, task_node) {
1.4       misho     479:                if (!sched_timespecisset(&r->root_wait))
                    480:                        r->root_wait = TASK_TS(task);
                    481:                else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
                    482:                        r->root_wait = TASK_TS(task);
1.1       misho     483:        }
                    484: 
                    485:        if (TAILQ_FIRST(&r->root_timer)) {
                    486:                m = r->root_wait;
1.4       misho     487:                sched_timespecsub(&m, &now, &mtmp);
1.1       misho     488:                r->root_wait = mtmp;
                    489:        } else {
                    490:                /* set wait INFTIM */
1.4       misho     491:                sched_timespecinf(&r->root_wait);
1.1       misho     492:        }
                    493: #else
                    494:        if (!TAILQ_FIRST(&r->root_eventlo) && (task = TAILQ_FIRST(&r->root_timer))) {
1.4       misho     495:                clock_gettime(CLOCK_MONOTONIC, &now);
1.1       misho     496: 
1.4       misho     497:                m = TASK_TS(task);
                    498:                sched_timespecsub(&m, &now, &mtmp);
1.1       misho     499:                r->root_wait = mtmp;
                    500:        } else {
                    501:                /* set wait INFTIM */
1.4       misho     502:                sched_timespecinf(&r->root_wait);
1.1       misho     503:        }
                    504: #endif
                    505:        /* if present member of eventLo, set NOWAIT */
                    506:        if (TAILQ_FIRST(&r->root_eventlo))
1.4       misho     507:                sched_timespecclear(&r->root_wait);
1.1       misho     508: 
1.4       misho     509:        if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1)
                    510:                timeout = &r->root_wait;
                    511:        else if (sched_timespecisinf(&r->root_poll))
1.1       misho     512:                timeout = NULL;
1.4       misho     513:        else
                    514:                timeout = &r->root_poll;
1.1       misho     515:        if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
1.3       misho     516:                if (r->root_hooks.hook_exec.exception) {
                    517:                        if (r->root_hooks.hook_exec.exception(r, NULL))
                    518:                                return NULL;
1.6       misho     519:                } else if (errno != EINTR)
1.3       misho     520:                        LOGERR;
1.2       misho     521:                return NULL;
1.1       misho     522:        }
                    523: 
1.4       misho     524:        now.tv_sec = now.tv_nsec = 0;
1.1       misho     525:        /* Go and catch the cat into pipes ... */
                    526:        for (i = 0; i < en; i++) {
                    527:                memcpy(evt, &res[i], sizeof evt);
                    528:                evt->flags = EV_DELETE;
                    529:                /* Put read/write task to ready queue */
                    530:                switch (res[i].filter) {
                    531:                        case EVFILT_READ:
1.6       misho     532:                                TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) {
1.3       misho     533:                                        if (TASK_FD(task) != ((intptr_t) res[i].udata))
1.1       misho     534:                                                continue;
                    535:                                        /* remove read handle */
1.4       misho     536: #ifdef HAVE_LIBPTHREAD
                    537:                                        pthread_mutex_lock(&r->root_mtx[taskREAD]);
                    538: #endif
1.1       misho     539:                                        TAILQ_REMOVE(&r->root_read, task, task_node);
1.4       misho     540: #ifdef HAVE_LIBPTHREAD
                    541:                                        pthread_mutex_unlock(&r->root_mtx[taskREAD]);
                    542: #endif
1.3       misho     543:                                        if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
                    544:                                                if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
                    545:                                                        task->task_type = taskUNUSE;
1.4       misho     546: #ifdef HAVE_LIBPTHREAD
                    547:                                                        pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    548: #endif
1.3       misho     549:                                                        TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     550: #ifdef HAVE_LIBPTHREAD
                    551:                                                        pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    552: #endif
1.3       misho     553:                                                } else {
                    554:                                                        task->task_type = taskREADY;
1.4       misho     555: #ifdef HAVE_LIBPTHREAD
                    556:                                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    557: #endif
1.3       misho     558:                                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     559: #ifdef HAVE_LIBPTHREAD
                    560:                                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    561: #endif
1.3       misho     562:                                                }
                    563:                                        } else {
1.2       misho     564:                                                task->task_type = taskREADY;
1.4       misho     565: #ifdef HAVE_LIBPTHREAD
                    566:                                                pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    567: #endif
1.2       misho     568:                                                TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     569: #ifdef HAVE_LIBPTHREAD
                    570:                                                pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    571: #endif
1.3       misho     572:                                        }
1.1       misho     573:                                        break;
                    574:                                }
                    575:                                break;
                    576:                        case EVFILT_WRITE:
1.6       misho     577:                                TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) {
1.3       misho     578:                                        if (TASK_FD(task) != ((intptr_t) res[i].udata))
1.1       misho     579:                                                continue;
                    580:                                        /* remove write handle */
1.4       misho     581: #ifdef HAVE_LIBPTHREAD
                    582:                                        pthread_mutex_lock(&r->root_mtx[taskWRITE]);
                    583: #endif
1.1       misho     584:                                        TAILQ_REMOVE(&r->root_write, task, task_node);
1.4       misho     585: #ifdef HAVE_LIBPTHREAD
                    586:                                        pthread_mutex_unlock(&r->root_mtx[taskWRITE]);
                    587: #endif
1.3       misho     588:                                        if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
                    589:                                                if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
                    590:                                                        task->task_type = taskUNUSE;
1.4       misho     591: #ifdef HAVE_LIBPTHREAD
                    592:                                                        pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    593: #endif
1.3       misho     594:                                                        TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     595: #ifdef HAVE_LIBPTHREAD
                    596:                                                        pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    597: #endif
1.3       misho     598:                                                } else {
                    599:                                                        task->task_type = taskREADY;
1.4       misho     600: #ifdef HAVE_LIBPTHREAD
                    601:                                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    602: #endif
1.3       misho     603:                                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     604: #ifdef HAVE_LIBPTHREAD
                    605:                                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    606: #endif
1.3       misho     607:                                                }
                    608:                                        } else {
1.2       misho     609:                                                task->task_type = taskREADY;
1.4       misho     610: #ifdef HAVE_LIBPTHREAD
                    611:                                                pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    612: #endif
1.2       misho     613:                                                TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     614: #ifdef HAVE_LIBPTHREAD
                    615:                                                pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    616: #endif
1.3       misho     617:                                        }
1.1       misho     618:                                        break;
                    619:                                }
                    620:                                break;
1.7       misho     621:                        case EVFILT_TIMER:
                    622:                                TAILQ_FOREACH_SAFE(task, &r->root_alarm, task_node, tmp) {
                    623:                                        if ((uintptr_t) TASK_DATA(task) != ((uintptr_t) res[i].udata))
                    624:                                                continue;
                    625:                                        /* remove alarm handle */
                    626: #ifdef HAVE_LIBPTHREAD
                    627:                                        pthread_mutex_lock(&r->root_mtx[taskALARM]);
                    628: #endif
                    629:                                        TAILQ_REMOVE(&r->root_alarm, task, task_node);
                    630: #ifdef HAVE_LIBPTHREAD
                    631:                                        pthread_mutex_unlock(&r->root_mtx[taskALARM]);
                    632: #endif
                    633:                                        task->task_type = taskREADY;
                    634: #ifdef HAVE_LIBPTHREAD
                    635:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    636: #endif
                    637:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
                    638: #ifdef HAVE_LIBPTHREAD
                    639:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    640: #endif
                    641:                                        break;
                    642:                                }
                    643:                                break;
1.7.2.1 ! misho     644:                        case EVFILT_VNODE:
        !           645:                                TAILQ_FOREACH_SAFE(task, &r->root_node, task_node, tmp) {
        !           646:                                        if (TASK_FD(task) != ((intptr_t) res[i].udata))
        !           647:                                                continue;
        !           648:                                        /* remove node handle */
        !           649: #ifdef HAVE_LIBPTHREAD
        !           650:                                        pthread_mutex_lock(&r->root_mtx[taskNODE]);
        !           651: #endif
        !           652:                                        TAILQ_REMOVE(&r->root_node, task, task_node);
        !           653: #ifdef HAVE_LIBPTHREAD
        !           654:                                        pthread_mutex_unlock(&r->root_mtx[taskNODE]);
        !           655: #endif
        !           656:                                        task->task_type = taskREADY;
        !           657: #ifdef HAVE_LIBPTHREAD
        !           658:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
        !           659: #endif
        !           660:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
        !           661: #ifdef HAVE_LIBPTHREAD
        !           662:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
        !           663: #endif
        !           664:                                        break;
        !           665:                                }
        !           666:                                break;
        !           667:                        case EVFILT_PROC:
        !           668:                                TAILQ_FOREACH_SAFE(task, &r->root_proc, task_node, tmp) {
        !           669:                                        if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
        !           670:                                                continue;
        !           671:                                        /* remove proc handle */
        !           672: #ifdef HAVE_LIBPTHREAD
        !           673:                                        pthread_mutex_lock(&r->root_mtx[taskPROC]);
        !           674: #endif
        !           675:                                        TAILQ_REMOVE(&r->root_proc, task, task_node);
        !           676: #ifdef HAVE_LIBPTHREAD
        !           677:                                        pthread_mutex_unlock(&r->root_mtx[taskPROC]);
        !           678: #endif
        !           679:                                        task->task_type = taskREADY;
        !           680: #ifdef HAVE_LIBPTHREAD
        !           681:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
        !           682: #endif
        !           683:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
        !           684: #ifdef HAVE_LIBPTHREAD
        !           685:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
        !           686: #endif
        !           687:                                        break;
        !           688:                                }
        !           689:                                break;
        !           690:                        case EVFILT_SIGNAL:
        !           691:                                TAILQ_FOREACH_SAFE(task, &r->root_signal, task_node, tmp) {
        !           692:                                        if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
        !           693:                                                continue;
        !           694:                                        /* remove signal handle */
        !           695: #ifdef HAVE_LIBPTHREAD
        !           696:                                        pthread_mutex_lock(&r->root_mtx[taskSIGNAL]);
        !           697: #endif
        !           698:                                        TAILQ_REMOVE(&r->root_signal, task, task_node);
        !           699: #ifdef HAVE_LIBPTHREAD
        !           700:                                        pthread_mutex_unlock(&r->root_mtx[taskSIGNAL]);
        !           701: #endif
        !           702:                                        task->task_type = taskREADY;
        !           703: #ifdef HAVE_LIBPTHREAD
        !           704:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
        !           705: #endif
        !           706:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
        !           707: #ifdef HAVE_LIBPTHREAD
        !           708:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
        !           709: #endif
        !           710:                                        break;
        !           711:                                }
        !           712:                                break;
        !           713:                        case EVFILT_USER:
        !           714:                                TAILQ_FOREACH_SAFE(task, &r->root_user, task_node, tmp) {
        !           715:                                        if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
        !           716:                                                continue;
        !           717:                                        /* remove user handle */
        !           718: #ifdef HAVE_LIBPTHREAD
        !           719:                                        pthread_mutex_lock(&r->root_mtx[taskUSER]);
        !           720: #endif
        !           721:                                        TAILQ_REMOVE(&r->root_user, task, task_node);
        !           722: #ifdef HAVE_LIBPTHREAD
        !           723:                                        pthread_mutex_unlock(&r->root_mtx[taskUSER]);
        !           724: #endif
        !           725:                                        task->task_type = taskREADY;
        !           726: #ifdef HAVE_LIBPTHREAD
        !           727:                                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
        !           728: #endif
        !           729:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
        !           730: #ifdef HAVE_LIBPTHREAD
        !           731:                                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
        !           732: #endif
        !           733:                                        break;
        !           734:                                }
        !           735:                                break;
1.1       misho     736:                }
1.4       misho     737:                if (kevent(r->root_kq, evt, 1, NULL, 0, &now) == -1) {
1.3       misho     738:                        if (r->root_hooks.hook_exec.exception) {
                    739:                                if (r->root_hooks.hook_exec.exception(r, NULL))
                    740:                                        return NULL;
                    741:                        } else
                    742:                                LOGERR;
                    743:                }
1.1       misho     744:        }
                    745: 
1.2       misho     746:        /* timer update & put in ready queue */
1.4       misho     747:        clock_gettime(CLOCK_MONOTONIC, &now);
1.1       misho     748: 
1.6       misho     749:        TAILQ_FOREACH_SAFE(task, &r->root_timer, task_node, tmp)
1.4       misho     750:                if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0) {
                    751: #ifdef HAVE_LIBPTHREAD
                    752:                        pthread_mutex_lock(&r->root_mtx[taskTIMER]);
                    753: #endif
1.1       misho     754:                        TAILQ_REMOVE(&r->root_timer, task, task_node);
1.4       misho     755: #ifdef HAVE_LIBPTHREAD
                    756:                        pthread_mutex_unlock(&r->root_mtx[taskTIMER]);
                    757: #endif
1.1       misho     758:                        task->task_type = taskREADY;
1.4       misho     759: #ifdef HAVE_LIBPTHREAD
                    760:                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    761: #endif
1.1       misho     762:                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     763: #ifdef HAVE_LIBPTHREAD
                    764:                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    765: #endif
1.1       misho     766:                }
                    767: 
                    768:        /* put eventlo priority task to ready queue, if there is no ready task or 
                    769:                reach max missed fetch-rotate */
                    770:        if ((task = TAILQ_FIRST(&r->root_eventlo))) {
                    771:                if (!TAILQ_FIRST(&r->root_ready) || r->root_eventlo_miss > MAX_EVENTLO_MISS) {
                    772:                        r->root_eventlo_miss = 0;
                    773: 
1.4       misho     774: #ifdef HAVE_LIBPTHREAD
                    775:                        pthread_mutex_lock(&r->root_mtx[taskEVENTLO]);
                    776: #endif
1.1       misho     777:                        TAILQ_REMOVE(&r->root_eventlo, task, task_node);
1.4       misho     778: #ifdef HAVE_LIBPTHREAD
                    779:                        pthread_mutex_unlock(&r->root_mtx[taskEVENTLO]);
                    780: #endif
1.1       misho     781:                        task->task_type = taskREADY;
1.4       misho     782: #ifdef HAVE_LIBPTHREAD
                    783:                        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    784: #endif
1.1       misho     785:                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4       misho     786: #ifdef HAVE_LIBPTHREAD
                    787:                        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    788: #endif
1.1       misho     789:                } else
                    790:                        r->root_eventlo_miss++;
                    791:        } else
                    792:                r->root_eventlo_miss = 0;
                    793: 
                    794:        /* OK, lets get ready task !!! */
1.6       misho     795:        task = TAILQ_FIRST(&r->root_ready);
                    796:        if (!(task))
                    797:                return NULL;
                    798: 
1.4       misho     799: #ifdef HAVE_LIBPTHREAD
                    800:        pthread_mutex_lock(&r->root_mtx[taskREADY]);
                    801: #endif
1.1       misho     802:        TAILQ_REMOVE(&r->root_ready, task, task_node);
1.4       misho     803: #ifdef HAVE_LIBPTHREAD
                    804:        pthread_mutex_unlock(&r->root_mtx[taskREADY]);
                    805: #endif
1.1       misho     806:        task->task_type = taskUNUSE;
1.4       misho     807: #ifdef HAVE_LIBPTHREAD
                    808:        pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
                    809: #endif
1.1       misho     810:        TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4       misho     811: #ifdef HAVE_LIBPTHREAD
                    812:        pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
                    813: #endif
1.1       misho     814:        return task;
                    815: }
1.3       misho     816: 
                    817: /*
                    818:  * sched_hook_exception() - Default EXCEPTION hook
1.5       misho     819:  *
1.3       misho     820:  * @root = root task
                    821:  * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
                    822:  * return: <0 errors and 0 ok
                    823:  */
                    824: void *
                    825: sched_hook_exception(void *root, void *arg)
                    826: {
                    827:        sched_root_task_t *r = root;
                    828: 
1.6       misho     829:        if (!r)
1.3       misho     830:                return NULL;
                    831: 
                    832:        /* custom exception handling ... */
                    833:        if (arg) {
                    834:                if (arg == (void*) EV_EOF)
                    835:                        return NULL;
                    836:                return (void*) -1;      /* raise scheduler error!!! */
                    837:        }
                    838: 
                    839:        /* if error hook exists */
                    840:        if (r->root_hooks.hook_root.error)
                    841:                return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
                    842: 
                    843:        /* default case! */
                    844:        LOGERR;
                    845:        return NULL;
                    846: }
1.5       misho     847: 
                    848: /*
                    849:  * sched_hook_condition() - Default CONDITION hook
                    850:  *
                    851:  * @root = root task
                    852:  * @arg = killState from schedRun()
                    853:  * return: NULL kill scheduler loop or !=NULL ok
                    854:  */
                    855: void *
                    856: sched_hook_condition(void *root, void *arg)
                    857: {
                    858:        sched_root_task_t *r = root;
                    859: 
1.6       misho     860:        if (!r)
1.5       misho     861:                return NULL;
                    862: 
                    863:        return (void*) (r->root_cond - *(intptr_t*) arg);
                    864: }

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