Annotation of libaitsched/src/tasks.c, revision 1.7.4.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.4.1 ! misho       6: * $Id: tasks.c,v 1.7 2012/05/14 12:09:13 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.6       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: 
                     48: 
1.4       misho      49: #pragma GCC visibility push(hidden)
                     50: 
                     51: inline sched_task_t *
                     52: _sched_useTask(sched_root_task_t * __restrict root)
                     53: {
1.7       misho      54:        sched_task_t *task, *tmp;
1.4       misho      55: 
1.7       misho      56:        TAILQ_FOREACH_SAFE(task, &root->root_unuse, task_node, tmp) {
1.4       misho      57:                if (!TASK_ISLOCKED(task)) {
1.5       misho      58: #ifdef HAVE_LIBPTHREAD
                     59:                        pthread_mutex_lock(&root->root_mtx[taskUNUSE]);
                     60: #endif
1.4       misho      61:                        TAILQ_REMOVE(&root->root_unuse, task, task_node);
1.5       misho      62: #ifdef HAVE_LIBPTHREAD
                     63:                        pthread_mutex_unlock(&root->root_mtx[taskUNUSE]);
                     64: #endif
1.4       misho      65:                        break;
                     66:                }
                     67:        }
                     68: 
                     69:        if (!task) {
                     70:                task = malloc(sizeof(sched_task_t));
                     71:                if (!task) {
                     72:                        LOGERR;
                     73:                        return NULL;
                     74:                }
                     75:        }
                     76: 
                     77:        return task;
                     78: }
                     79: 
                     80: inline sched_task_t *
                     81: _sched_unuseTask(sched_task_t * __restrict task)
                     82: {
                     83:        TASK_UNLOCK(task);
1.5       misho      84:        TASK_TYPE(task) = taskUNUSE;
                     85: #ifdef HAVE_LIBPTHREAD
                     86:        pthread_mutex_lock(&TASK_ROOT(task)->root_mtx[taskUNUSE]);
                     87: #endif
                     88:        TAILQ_INSERT_TAIL(&TASK_ROOT(task)->root_unuse, task, task_node);
                     89: #ifdef HAVE_LIBPTHREAD
                     90:        pthread_mutex_unlock(&TASK_ROOT(task)->root_mtx[taskUNUSE]);
                     91: #endif
1.4       misho      92:        task = NULL;
                     93: 
                     94:        return task;
                     95: }
                     96: 
                     97: #pragma GCC visibility pop
                     98: 
                     99: 
1.1       misho     100: /*
1.2       misho     101:  * schedRead() - Add READ I/O task to scheduler queue
1.6       misho     102:  *
1.1       misho     103:  * @root = root task
                    104:  * @func = task execution function
                    105:  * @arg = 1st func argument
1.2       misho     106:  * @fd = fd handle
1.5       misho     107:  * @opt_data = Optional data
                    108:  * @opt_dlen = Optional data length
1.1       misho     109:  * return: NULL error or !=NULL new queued task
                    110:  */
                    111: sched_task_t *
1.5       misho     112: schedRead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    113:                void *opt_data, size_t opt_dlen)
1.1       misho     114: {
                    115:        sched_task_t *task;
                    116:        void *ptr;
                    117: 
                    118:        if (!root || !func)
                    119:                return NULL;
                    120: 
                    121:        /* get new task */
1.4       misho     122:        if (!(task = _sched_useTask(root)))
                    123:                return NULL;
1.1       misho     124: 
                    125:        memset(task, 0, sizeof(sched_task_t));
                    126:        task->task_id = 0;
1.4       misho     127:        task->task_lock = 0;
1.1       misho     128:        task->task_func = func;
1.5       misho     129:        TASK_TYPE(task) = taskREAD;
                    130:        TASK_ROOT(task) = root;
1.1       misho     131: 
                    132:        TASK_ARG(task) = arg;
1.2       misho     133:        TASK_FD(task) = fd;
1.1       misho     134: 
1.5       misho     135:        TASK_DATA(task) = opt_data;
                    136:        TASK_DATLEN(task) = opt_dlen;
                    137: 
1.1       misho     138:        if (root->root_hooks.hook_add.read)
                    139:                ptr = root->root_hooks.hook_add.read(task, NULL);
                    140:        else
                    141:                ptr = NULL;
                    142: 
1.5       misho     143:        if (!ptr) {
                    144: #ifdef HAVE_LIBPTHREAD
                    145:                pthread_mutex_lock(&root->root_mtx[taskREAD]);
                    146: #endif
1.1       misho     147:                TAILQ_INSERT_TAIL(&root->root_read, task, task_node);
1.5       misho     148: #ifdef HAVE_LIBPTHREAD
                    149:                pthread_mutex_unlock(&root->root_mtx[taskREAD]);
                    150: #endif
                    151:        } else
1.4       misho     152:                task = _sched_unuseTask(task);
1.1       misho     153: 
                    154:        return task;
                    155: }
                    156: 
                    157: /*
1.2       misho     158:  * schedWrite() - Add WRITE I/O task to scheduler queue
1.6       misho     159:  *
1.1       misho     160:  * @root = root task
                    161:  * @func = task execution function
                    162:  * @arg = 1st func argument
1.2       misho     163:  * @fd = fd handle
1.5       misho     164:  * @opt_data = Optional data
                    165:  * @opt_dlen = Optional data length
1.1       misho     166:  * return: NULL error or !=NULL new queued task
                    167:  */
                    168: sched_task_t *
1.5       misho     169: schedWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    170:                void *opt_data, size_t opt_dlen)
1.1       misho     171: {
                    172:        sched_task_t *task;
                    173:        void *ptr;
                    174: 
                    175:        if (!root || !func)
                    176:                return NULL;
                    177: 
                    178:        /* get new task */
1.4       misho     179:        if (!(task = _sched_useTask(root)))
                    180:                return NULL;
1.1       misho     181: 
                    182:        memset(task, 0, sizeof(sched_task_t));
                    183:        task->task_id = 0;
1.4       misho     184:        task->task_lock = 0;
1.1       misho     185:        task->task_func = func;
1.5       misho     186:        TASK_TYPE(task) = taskWRITE;
                    187:        TASK_ROOT(task) = root;
1.1       misho     188: 
                    189:        TASK_ARG(task) = arg;
1.2       misho     190:        TASK_FD(task) = fd;
1.1       misho     191: 
1.5       misho     192:        TASK_DATA(task) = opt_data;
                    193:        TASK_DATLEN(task) = opt_dlen;
                    194: 
1.1       misho     195:        if (root->root_hooks.hook_add.write)
                    196:                ptr = root->root_hooks.hook_add.write(task, NULL);
                    197:        else
                    198:                ptr = NULL;
                    199: 
1.5       misho     200:        if (!ptr) {
                    201: #ifdef HAVE_LIBPTHREAD
                    202:                pthread_mutex_lock(&root->root_mtx[taskWRITE]);
                    203: #endif
1.1       misho     204:                TAILQ_INSERT_TAIL(&root->root_write, task, task_node);
1.5       misho     205: #ifdef HAVE_LIBPTHREAD
                    206:                pthread_mutex_unlock(&root->root_mtx[taskWRITE]);
                    207: #endif
                    208:        } else
1.4       misho     209:                task = _sched_unuseTask(task);
1.1       misho     210: 
                    211:        return task;
                    212: }
                    213: 
                    214: /*
1.7.4.1 ! misho     215:  * schedAlarm() - Add ALARM task to scheduler queue
        !           216:  *
        !           217:  * @root = root task
        !           218:  * @func = task execution function
        !           219:  * @arg = 1st func argument
        !           220:  * @ts = timeout argument structure
        !           221:  * @opt_data = Optional data
        !           222:  * @opt_dlen = Optional data length
        !           223:  * return: NULL error or !=NULL new queued task
        !           224:  */
        !           225: sched_task_t *
        !           226: schedAlarm(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts, 
        !           227:                void *opt_data, size_t opt_dlen)
        !           228: {
        !           229:        sched_task_t *task;
        !           230:        void *ptr;
        !           231: 
        !           232:        if (!root || !func)
        !           233:                return NULL;
        !           234: 
        !           235:        /* get new task */
        !           236:        if (!(task = _sched_useTask(root)))
        !           237:                return NULL;
        !           238: 
        !           239:        memset(task, 0, sizeof(sched_task_t));
        !           240:        task->task_id = 0;
        !           241:        task->task_lock = 0;
        !           242:        task->task_func = func;
        !           243:        TASK_TYPE(task) = taskALARM;
        !           244:        TASK_ROOT(task) = root;
        !           245: 
        !           246:        TASK_ARG(task) = arg;
        !           247:        TASK_TS(task) = ts;
        !           248: 
        !           249:        TASK_DATA(task) = opt_data;
        !           250:        TASK_DATLEN(task) = opt_dlen;
        !           251: 
        !           252:        if (root->root_hooks.hook_add.alarm)
        !           253:                ptr = root->root_hooks.hook_add.alarm(task, NULL);
        !           254:        else
        !           255:                ptr = NULL;
        !           256: 
        !           257:        if (!ptr) {
        !           258: #ifdef HAVE_LIBPTHREAD
        !           259:                pthread_mutex_lock(&root->root_mtx[taskALARM]);
        !           260: #endif
        !           261:                TAILQ_INSERT_TAIL(&root->root_alarm, task, task_node);
        !           262: #ifdef HAVE_LIBPTHREAD
        !           263:                pthread_mutex_unlock(&root->root_mtx[taskALARM]);
        !           264: #endif
        !           265:        } else
        !           266:                task = _sched_unuseTask(task);
        !           267: 
        !           268:        return task;
        !           269: }
        !           270: 
        !           271: /*
1.1       misho     272:  * schedTimer() - Add TIMER task to scheduler queue
1.6       misho     273:  *
1.1       misho     274:  * @root = root task
                    275:  * @func = task execution function
                    276:  * @arg = 1st func argument
1.5       misho     277:  * @ts = timeout argument structure
                    278:  * @opt_data = Optional data
                    279:  * @opt_dlen = Optional data length
1.1       misho     280:  * return: NULL error or !=NULL new queued task
                    281:  */
                    282: sched_task_t *
1.5       misho     283: schedTimer(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts, 
                    284:                void *opt_data, size_t opt_dlen)
1.1       misho     285: {
                    286:        sched_task_t *task, *t = NULL;
                    287:        void *ptr;
1.5       misho     288:        struct timespec now;
1.1       misho     289: 
                    290:        if (!root || !func)
                    291:                return NULL;
                    292: 
                    293:        /* get new task */
1.4       misho     294:        if (!(task = _sched_useTask(root)))
                    295:                return NULL;
1.1       misho     296: 
                    297:        memset(task, 0, sizeof(sched_task_t));
                    298:        task->task_id = 0;
1.4       misho     299:        task->task_lock = 0;
1.1       misho     300:        task->task_func = func;
1.5       misho     301:        TASK_TYPE(task) = taskTIMER;
                    302:        TASK_ROOT(task) = root;
1.1       misho     303: 
                    304:        TASK_ARG(task) = arg;
                    305: 
1.5       misho     306:        TASK_DATA(task) = opt_data;
                    307:        TASK_DATLEN(task) = opt_dlen;
                    308: 
1.1       misho     309:        /* calculate timeval structure */
1.5       misho     310:        clock_gettime(CLOCK_MONOTONIC, &now);
                    311:        now.tv_sec += ts.tv_sec;
                    312:        now.tv_nsec += ts.tv_nsec;
                    313:        if (now.tv_nsec >= 1000000000L) {
1.1       misho     314:                now.tv_sec++;
1.5       misho     315:                now.tv_nsec -= 1000000000L;
                    316:        } else if (now.tv_nsec < 0) {
1.1       misho     317:                now.tv_sec--;
1.5       misho     318:                now.tv_nsec += 1000000000L;
1.1       misho     319:        }
1.5       misho     320:        TASK_TS(task) = now;
1.1       misho     321: 
                    322:        if (root->root_hooks.hook_add.timer)
                    323:                ptr = root->root_hooks.hook_add.timer(task, NULL);
                    324:        else
                    325:                ptr = NULL;
                    326: 
                    327:        if (!ptr) {
1.5       misho     328: #ifdef HAVE_LIBPTHREAD
                    329:                pthread_mutex_lock(&root->root_mtx[taskTIMER]);
                    330: #endif
1.1       misho     331: #ifdef TIMER_WITHOUT_SORT
                    332:                TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
                    333: #else
                    334:                TAILQ_FOREACH(t, &root->root_timer, task_node)
1.5       misho     335:                        if (sched_timespeccmp(&TASK_TS(task), &TASK_TS(t), -) < 1)
1.1       misho     336:                                break;
                    337:                if (!t)
                    338:                        TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
                    339:                else
                    340:                        TAILQ_INSERT_BEFORE(t, task, task_node);
                    341: #endif
1.5       misho     342: #ifdef HAVE_LIBPTHREAD
                    343:                pthread_mutex_unlock(&root->root_mtx[taskTIMER]);
                    344: #endif
1.4       misho     345:        } else
                    346:                task = _sched_unuseTask(task);
1.1       misho     347: 
                    348:        return task;
                    349: }
                    350: 
                    351: /*
                    352:  * schedEvent() - Add EVENT task to scheduler queue
1.6       misho     353:  *
1.1       misho     354:  * @root = root task
                    355:  * @func = task execution function
                    356:  * @arg = 1st func argument
1.2       misho     357:  * @val = additional func argument
1.5       misho     358:  * @opt_data = Optional data
                    359:  * @opt_dlen = Optional data length
1.1       misho     360:  * return: NULL error or !=NULL new queued task
                    361:  */
                    362: sched_task_t *
1.5       misho     363: schedEvent(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val, 
                    364:                void *opt_data, size_t opt_dlen)
1.1       misho     365: {
                    366:        sched_task_t *task;
                    367:        void *ptr;
                    368: 
                    369:        if (!root || !func)
                    370:                return NULL;
                    371: 
                    372:        /* get new task */
1.4       misho     373:        if (!(task = _sched_useTask(root)))
                    374:                return NULL;
1.1       misho     375: 
                    376:        memset(task, 0, sizeof(sched_task_t));
                    377:        task->task_id = 0;
1.4       misho     378:        task->task_lock = 0;
1.1       misho     379:        task->task_func = func;
1.5       misho     380:        TASK_TYPE(task) = taskEVENT;
                    381:        TASK_ROOT(task) = root;
1.1       misho     382: 
                    383:        TASK_ARG(task) = arg;
1.2       misho     384:        TASK_VAL(task) = val;
1.1       misho     385: 
1.5       misho     386:        TASK_DATA(task) = opt_data;
                    387:        TASK_DATLEN(task) = opt_dlen;
                    388: 
1.1       misho     389:        if (root->root_hooks.hook_add.event)
                    390:                ptr = root->root_hooks.hook_add.event(task, NULL);
                    391:        else
                    392:                ptr = NULL;
                    393: 
1.5       misho     394:        if (!ptr) {
                    395: #ifdef HAVE_LIBPTHREAD
                    396:                pthread_mutex_lock(&root->root_mtx[taskEVENT]);
                    397: #endif
1.1       misho     398:                TAILQ_INSERT_TAIL(&root->root_event, task, task_node);
1.5       misho     399: #ifdef HAVE_LIBPTHREAD
                    400:                pthread_mutex_unlock(&root->root_mtx[taskEVENT]);
                    401: #endif
                    402:        } else
1.4       misho     403:                task = _sched_unuseTask(task);
1.1       misho     404: 
                    405:        return task;
                    406: }
                    407: 
                    408: 
                    409: /*
                    410:  * schedEventLo() - Add EVENT_Lo task to scheduler queue
1.6       misho     411:  *
1.1       misho     412:  * @root = root task
                    413:  * @func = task execution function
                    414:  * @arg = 1st func argument
1.2       misho     415:  * @val = additional func argument
1.5       misho     416:  * @opt_data = Optional data
                    417:  * @opt_dlen = Optional data length
1.1       misho     418:  * return: NULL error or !=NULL new queued task
                    419:  */
                    420: sched_task_t *
1.5       misho     421: schedEventLo(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val, 
                    422:                void *opt_data, size_t opt_dlen)
1.1       misho     423: {
                    424:        sched_task_t *task;
                    425:        void *ptr;
                    426: 
                    427:        if (!root || !func)
                    428:                return NULL;
                    429: 
                    430:        /* get new task */
1.4       misho     431:        if (!(task = _sched_useTask(root)))
                    432:                return NULL;
1.1       misho     433: 
                    434:        memset(task, 0, sizeof(sched_task_t));
                    435:        task->task_id = 0;
1.4       misho     436:        task->task_lock = 0;
1.1       misho     437:        task->task_func = func;
1.5       misho     438:        TASK_TYPE(task) = taskEVENT;
                    439:        TASK_ROOT(task) = root;
1.1       misho     440: 
                    441:        TASK_ARG(task) = arg;
1.2       misho     442:        TASK_VAL(task) = val;
1.1       misho     443: 
1.5       misho     444:        TASK_DATA(task) = opt_data;
                    445:        TASK_DATLEN(task) = opt_dlen;
                    446: 
1.1       misho     447:        if (root->root_hooks.hook_add.eventlo)
                    448:                ptr = root->root_hooks.hook_add.eventlo(task, NULL);
                    449:        else
                    450:                ptr = NULL;
                    451: 
1.5       misho     452:        if (!ptr) {
                    453: #ifdef HAVE_LIBPTHREAD
                    454:                pthread_mutex_lock(&root->root_mtx[taskEVENTLO]);
                    455: #endif
1.1       misho     456:                TAILQ_INSERT_TAIL(&root->root_eventlo, task, task_node);
1.5       misho     457: #ifdef HAVE_LIBPTHREAD
                    458:                pthread_mutex_unlock(&root->root_mtx[taskEVENTLO]);
                    459: #endif
                    460:        } else
1.4       misho     461:                task = _sched_unuseTask(task);
1.1       misho     462: 
                    463:        return task;
                    464: }
                    465: 
                    466: /*
                    467:  * schedCallOnce() - Call once from scheduler
1.6       misho     468:  *
1.1       misho     469:  * @root = root task
                    470:  * @func = task execution function
                    471:  * @arg = 1st func argument
1.2       misho     472:  * @val = additional func argument
1.5       misho     473:  * @opt_data = Optional data
                    474:  * @opt_dlen = Optional data length
1.2       misho     475:  * return: return value from called func
1.1       misho     476:  */
                    477: sched_task_t *
1.5       misho     478: schedCallOnce(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val, 
                    479:                void *opt_data, size_t opt_dlen)
1.1       misho     480: {
                    481:        sched_task_t *task;
1.2       misho     482:        void *ret;
1.1       misho     483: 
                    484:        if (!root || !func)
                    485:                return NULL;
                    486: 
                    487:        /* get new task */
1.4       misho     488:        if (!(task = _sched_useTask(root)))
                    489:                return NULL;
1.1       misho     490: 
                    491:        memset(task, 0, sizeof(sched_task_t));
                    492:        task->task_id = 0;
1.4       misho     493:        task->task_lock = 0;
1.1       misho     494:        task->task_func = func;
1.5       misho     495:        TASK_TYPE(task) = taskEVENT;
                    496:        TASK_ROOT(task) = root;
1.1       misho     497: 
                    498:        TASK_ARG(task) = arg;
1.2       misho     499:        TASK_VAL(task) = val;
1.1       misho     500: 
1.5       misho     501:        TASK_DATA(task) = opt_data;
                    502:        TASK_DATLEN(task) = opt_dlen;
                    503: 
1.2       misho     504:        ret = schedCall(task);
1.1       misho     505: 
1.4       misho     506:        _sched_unuseTask(task);
1.2       misho     507:        return ret;
1.1       misho     508: }

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