Annotation of libaitsched/src/hooks.c, revision 1.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 $
        !             6: * $Id: aitcrc.c,v 1.4.2.1 2011/05/10 20:48:49 misho Exp $
        !             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: 
        !            15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
        !            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
        !            52:  * @root = root task
        !            53:  * @data = optional data if !=NULL
        !            54:  * return: <0 errors and 0 ok
        !            55:  */
        !            56: void *
        !            57: sched_hook_init(void *root, void *data)
        !            58: {
        !            59:        sched_root_task_t *r = root;
        !            60: 
        !            61:        if (!r || r->root_data.iov_base || r->root_data.iov_len)
        !            62:                return (void*) -1;
        !            63: 
        !            64:        r->root_data.iov_base = malloc(sizeof(struct sched_IO));
        !            65:        if (!r->root_data.iov_base) {
        !            66:                LOGERR;
        !            67:                return (void*) -1;
        !            68:        } else {
        !            69:                r->root_data.iov_len = sizeof(struct sched_IO);
        !            70:                memset(r->root_data.iov_base, 0, r->root_data.iov_len);
        !            71:        }
        !            72: 
        !            73:        r->root_kq = kqueue();
        !            74:        if (r->root_kq == -1) {
        !            75:                LOGERR;
        !            76:                return (void*) -1;
        !            77:        }
        !            78: 
        !            79:        return NULL;
        !            80: }
        !            81: 
        !            82: /*
        !            83:  * sched_hook_fini() - Default FINI hook
        !            84:  * @root = root task
        !            85:  * @arg = unused
        !            86:  * return: <0 errors and 0 ok
        !            87:  */
        !            88: void *
        !            89: sched_hook_fini(void *root, void *arg __unused)
        !            90: {
        !            91:        sched_root_task_t *r = root;
        !            92: 
        !            93:        if (!r)
        !            94:                return (void*) -1;
        !            95: 
        !            96:        if (r->root_kq > 2) {
        !            97:                close(r->root_kq);
        !            98:                r->root_kq = 0;
        !            99:        }
        !           100: 
        !           101:        if (r->root_data.iov_base && r->root_data.iov_len) {
        !           102:                free(r->root_data.iov_base);
        !           103:                r->root_data.iov_base = NULL;
        !           104:                r->root_data.iov_len = 0;
        !           105:        }
        !           106: 
        !           107:        return NULL;
        !           108: }
        !           109: 
        !           110: /*
        !           111:  * sched_hook_cancel() - Default CANCEL hook
        !           112:  * @task = current task
        !           113:  * @arg = unused
        !           114:  * return: <0 errors and 0 ok
        !           115:  */
        !           116: void *
        !           117: sched_hook_cancel(void *task, void *arg __unused)
        !           118: {
        !           119:        struct sched_IO *io;
        !           120:        sched_task_t *t = task;
        !           121:        struct kevent chg[1];
        !           122:        struct timespec timeout;
        !           123: 
        !           124:        if (!t || !t->task_root || !ROOT_DATA(t->task_root) || !ROOT_DATLEN(t->task_root))
        !           125:                return (void*) -1;
        !           126:        else
        !           127:                io = ROOT_DATA(t->task_root);
        !           128: 
        !           129:        timespecclear(&timeout);
        !           130:        switch (t->task_type) {
        !           131:                case taskREAD:
        !           132:                        if (FD_ISSET(TASK_FD(t), &io->wfd))
        !           133:                                EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, &TASK_FD(t));
        !           134:                        else
        !           135:                                EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, &TASK_FD(t));
        !           136:                        kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout);
        !           137: 
        !           138:                        FD_CLR(TASK_FD(t), &io->rfd);
        !           139:                        break;
        !           140:                case taskWRITE:
        !           141:                        if (FD_ISSET(TASK_FD(t), &io->rfd))
        !           142:                                EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, &TASK_FD(t));
        !           143:                        else
        !           144:                                EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, &TASK_FD(t));
        !           145:                        kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout);
        !           146: 
        !           147:                        FD_CLR(TASK_FD(t), &io->wfd);
        !           148:                        break;
        !           149:                default:
        !           150:                        break;
        !           151:        }
        !           152: 
        !           153:        return NULL;
        !           154: }
        !           155: 
        !           156: /*
        !           157:  * sched_hook_read() - Default READ hook
        !           158:  * @task = current task
        !           159:  * @arg = unused
        !           160:  * return: <0 errors and 0 ok
        !           161:  */
        !           162: void *
        !           163: sched_hook_read(void *task, void *arg __unused)
        !           164: {
        !           165:        struct sched_IO *io;
        !           166:        sched_task_t *t = task;
        !           167:        struct kevent chg[1];
        !           168:        struct timespec timeout;
        !           169: 
        !           170:        if (!t || !t->task_root || !ROOT_DATA(t->task_root) || !ROOT_DATLEN(t->task_root))
        !           171:                return (void*) -1;
        !           172:        else
        !           173:                io = ROOT_DATA(t->task_root);
        !           174: 
        !           175:        if (FD_ISSET(TASK_FD(t), &io->rfd))
        !           176:                return NULL;
        !           177:        else
        !           178:                FD_SET(TASK_FD(t), &io->rfd);
        !           179: 
        !           180:        timespecclear(&timeout);
        !           181:        EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, &TASK_FD(t));
        !           182:        if (kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
        !           183:                LOGERR;
        !           184:                return (void*) -1;
        !           185:        }
        !           186: 
        !           187:        return NULL;
        !           188: }
        !           189: 
        !           190: /*
        !           191:  * sched_hook_write() - Default WRITE hook
        !           192:  * @task = current task
        !           193:  * @arg = unused
        !           194:  * return: <0 errors and 0 ok
        !           195:  */
        !           196: void *
        !           197: sched_hook_write(void *task, void *arg __unused)
        !           198: {
        !           199:        struct sched_IO *io;
        !           200:        sched_task_t *t = task;
        !           201:        struct kevent chg[1];
        !           202:        struct timespec timeout;
        !           203: 
        !           204:        if (!t || !t->task_root || !ROOT_DATA(t->task_root) || !ROOT_DATLEN(t->task_root))
        !           205:                return (void*) -1;
        !           206:        else
        !           207:                io = ROOT_DATA(t->task_root);
        !           208: 
        !           209:        if (FD_ISSET(TASK_FD(t), &io->wfd))
        !           210:                return NULL;
        !           211:        else
        !           212:                FD_SET(TASK_FD(t), &io->wfd);
        !           213: 
        !           214:        timespecclear(&timeout);
        !           215:        EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, &TASK_FD(t));
        !           216:        if (kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
        !           217:                LOGERR;
        !           218:                return (void*) -1;
        !           219:        }
        !           220: 
        !           221:        return NULL;
        !           222: }
        !           223: 
        !           224: /*
        !           225:  * sched_hook_fetch() - Default FETCH hook
        !           226:  * @root = root task
        !           227:  * @arg = unused
        !           228:  * return: NULL error or !=NULL fetched task
        !           229:  */
        !           230: void *
        !           231: sched_hook_fetch(void *root, void *arg __unused)
        !           232: {
        !           233:        struct sched_IO *io;
        !           234:        sched_root_task_t *r = root;
        !           235:        sched_task_t *task;
        !           236:        struct timeval now, m, mtmp;
        !           237:        struct timespec nw, *timeout;
        !           238:        struct kevent evt[1], res[KQ_EVENTS];
        !           239:        register int i;
        !           240:        int en;
        !           241: 
        !           242:        if (!r || !ROOT_DATA(r) || !ROOT_DATLEN(r))
        !           243:                return NULL;
        !           244: 
        !           245:        /* get new task by queue priority */
        !           246: retry:
        !           247:        while ((task = TAILQ_FIRST(&r->root_event))) {
        !           248:                TAILQ_REMOVE(&r->root_event, task, task_node);
        !           249:                task->task_type = taskUNUSE;
        !           250:                TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
        !           251:                return task;
        !           252:        }
        !           253:        while ((task = TAILQ_FIRST(&r->root_ready))) {
        !           254:                TAILQ_REMOVE(&r->root_ready, task, task_node);
        !           255:                task->task_type = taskUNUSE;
        !           256:                TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
        !           257:                return task;
        !           258:        }
        !           259: 
        !           260: #ifdef TIMER_WITHOUT_SORT
        !           261:        clock_gettime(CLOCK_MONOTONIC, &nw);
        !           262:        now.tv_sec = nw.tv_sec;
        !           263:        now.tv_usec = nw.tv_nsec / 1000;
        !           264: 
        !           265:        timerclear(&r->root_wait);
        !           266:        TAILQ_FOREACH(task, &r->root_timer, task_node) {
        !           267:                if (!timerisset(&r->root_wait))
        !           268:                        r->root_wait = TASK_TV(task);
        !           269:                else if (timercmp(&TASK_TV(task), &r->root_wait, -) < 0)
        !           270:                        r->root_wait = TASK_TV(task);
        !           271:        }
        !           272: 
        !           273:        if (TAILQ_FIRST(&r->root_timer)) {
        !           274:                m = r->root_wait;
        !           275:                timersub(&m, &now, &mtmp);
        !           276:                r->root_wait = mtmp;
        !           277:        } else {
        !           278:                /* set wait INFTIM */
        !           279:                r->root_wait.tv_sec = r->root_wait.tv_usec = -1;
        !           280:        }
        !           281: #else
        !           282:        if (!TAILQ_FIRST(&r->root_eventlo) && (task = TAILQ_FIRST(&r->root_timer))) {
        !           283:                clock_gettime(CLOCK_MONOTONIC, &nw);
        !           284:                now.tv_sec = nw.tv_sec;
        !           285:                now.tv_usec = nw.tv_nsec / 1000;
        !           286: 
        !           287:                m = TASK_TV(task);
        !           288:                timersub(&m, &now, &mtmp);
        !           289:                r->root_wait = mtmp;
        !           290:        } else {
        !           291:                /* set wait INFTIM */
        !           292:                r->root_wait.tv_sec = r->root_wait.tv_usec = -1;
        !           293:        }
        !           294: #endif
        !           295:        /* if present member of eventLo, set NOWAIT */
        !           296:        if (TAILQ_FIRST(&r->root_eventlo))
        !           297:                timerclear(&r->root_wait);
        !           298: 
        !           299:        if (r->root_wait.tv_sec != -1 && r->root_wait.tv_usec != -1) {
        !           300:                nw.tv_sec = r->root_wait.tv_sec;
        !           301:                nw.tv_nsec = r->root_wait.tv_usec * 1000;
        !           302:                timeout = &nw;
        !           303:        } else  /* wait INFTIM */
        !           304:                timeout = NULL;
        !           305:        if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
        !           306:                LOGERR;
        !           307:                goto retry;
        !           308:        }
        !           309: 
        !           310:        timespecclear(&nw);
        !           311:        /* Go and catch the cat into pipes ... */
        !           312:        for (i = 0; i < en; i++) {
        !           313:                memcpy(evt, &res[i], sizeof evt);
        !           314:                evt->flags = EV_DELETE;
        !           315:                /* Put read/write task to ready queue */
        !           316:                switch (res[i].filter) {
        !           317:                        case EVFILT_READ:
        !           318:                                TAILQ_FOREACH(task, &r->root_read, task_node) {
        !           319:                                        if (TASK_FD(task) != *((int*) res[i].udata))
        !           320:                                                continue;
        !           321:                                        /* remove read handle */
        !           322:                                        io = ROOT_DATA(task->task_root);
        !           323:                                        FD_CLR(TASK_FD(task), &io->rfd);
        !           324: 
        !           325:                                        TAILQ_REMOVE(&r->root_read, task, task_node);
        !           326:                                        task->task_type = taskREADY;
        !           327:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
        !           328:                                        break;
        !           329:                                }
        !           330:                                break;
        !           331:                        case EVFILT_WRITE:
        !           332:                                TAILQ_FOREACH(task, &r->root_write, task_node) {
        !           333:                                        if (TASK_FD(task) != *((int*) res[i].udata))
        !           334:                                                continue;
        !           335:                                        /* remove write handle */
        !           336:                                        io = ROOT_DATA(task->task_root);
        !           337:                                        FD_CLR(TASK_FD(task), &io->wfd);
        !           338: 
        !           339:                                        TAILQ_REMOVE(&r->root_write, task, task_node);
        !           340:                                        task->task_type = taskREADY;
        !           341:                                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
        !           342:                                        break;
        !           343:                                }
        !           344:                                break;
        !           345:                }
        !           346: 
        !           347:                if (kevent(r->root_kq, evt, 1, NULL, 0, &nw) == -1)
        !           348:                        LOGERR;
        !           349:        }
        !           350: 
        !           351:        /* timer update */
        !           352:        clock_gettime(CLOCK_MONOTONIC, &nw);
        !           353:        now.tv_sec = nw.tv_sec;
        !           354:        now.tv_usec = nw.tv_nsec / 1000;
        !           355: 
        !           356:        TAILQ_FOREACH(task, &r->root_timer, task_node)
        !           357:                if (timercmp(&now, &TASK_TV(task), -) >= 0) {
        !           358:                        TAILQ_REMOVE(&r->root_timer, task, task_node);
        !           359:                        task->task_type = taskREADY;
        !           360:                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
        !           361:                }
        !           362: 
        !           363:        /* put eventlo priority task to ready queue, if there is no ready task or 
        !           364:                reach max missed fetch-rotate */
        !           365:        if ((task = TAILQ_FIRST(&r->root_eventlo))) {
        !           366:                if (!TAILQ_FIRST(&r->root_ready) || r->root_eventlo_miss > MAX_EVENTLO_MISS) {
        !           367:                        r->root_eventlo_miss = 0;
        !           368: 
        !           369:                        TAILQ_REMOVE(&r->root_eventlo, task, task_node);
        !           370:                        task->task_type = taskREADY;
        !           371:                        TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
        !           372:                } else
        !           373:                        r->root_eventlo_miss++;
        !           374:        } else
        !           375:                r->root_eventlo_miss = 0;
        !           376: 
        !           377:        /* OK, lets get ready task !!! */
        !           378:        if (!(task = TAILQ_FIRST(&r->root_ready)))
        !           379:                goto retry;
        !           380:        TAILQ_REMOVE(&r->root_ready, task, task_node);
        !           381:        task->task_type = taskUNUSE;
        !           382:        TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
        !           383:        return task;
        !           384: }
        !           385: 

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