Annotation of libaitsched/src/tasks.c, revision 1.4.2.2

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.4.2.2 ! misho       6: * $Id: tasks.c,v 1.4.2.1 2012/01/08 03:50:11 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: 
                     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: 
                     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: {
                     54:        sched_task_t *task;
                     55: 
                     56:        TAILQ_FOREACH(task, &root->root_unuse, task_node) {
                     57:                if (!TASK_ISLOCKED(task)) {
1.4.2.1   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.4.2.1   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.4.2.1   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.1       misho     102:  * @root = root task
                    103:  * @func = task execution function
                    104:  * @arg = 1st func argument
1.2       misho     105:  * @fd = fd handle
1.4.2.2 ! misho     106:  * @opt_data = Optional data
        !           107:  * @opt_dlen = Optional data length
1.1       misho     108:  * return: NULL error or !=NULL new queued task
                    109:  */
                    110: sched_task_t *
1.4.2.2 ! misho     111: schedRead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
        !           112:                void *opt_data, size_t opt_dlen)
1.1       misho     113: {
                    114:        sched_task_t *task;
                    115:        void *ptr;
                    116: 
                    117:        if (!root || !func)
                    118:                return NULL;
                    119: 
                    120:        /* get new task */
1.4       misho     121:        if (!(task = _sched_useTask(root)))
                    122:                return NULL;
1.1       misho     123: 
                    124:        memset(task, 0, sizeof(sched_task_t));
                    125:        task->task_id = 0;
1.4       misho     126:        task->task_lock = 0;
1.1       misho     127:        task->task_func = func;
1.4.2.1   misho     128:        TASK_TYPE(task) = taskREAD;
                    129:        TASK_ROOT(task) = root;
1.1       misho     130: 
                    131:        TASK_ARG(task) = arg;
1.2       misho     132:        TASK_FD(task) = fd;
1.1       misho     133: 
1.4.2.2 ! misho     134:        TASK_DATA(task) = opt_data;
        !           135:        TASK_DATLEN(task) = opt_dlen;
        !           136: 
1.1       misho     137:        if (root->root_hooks.hook_add.read)
                    138:                ptr = root->root_hooks.hook_add.read(task, NULL);
                    139:        else
                    140:                ptr = NULL;
                    141: 
1.4.2.1   misho     142:        if (!ptr) {
                    143: #ifdef HAVE_LIBPTHREAD
                    144:                pthread_mutex_lock(&root->root_mtx[taskREAD]);
                    145: #endif
1.1       misho     146:                TAILQ_INSERT_TAIL(&root->root_read, task, task_node);
1.4.2.1   misho     147: #ifdef HAVE_LIBPTHREAD
                    148:                pthread_mutex_unlock(&root->root_mtx[taskREAD]);
                    149: #endif
                    150:        } else
1.4       misho     151:                task = _sched_unuseTask(task);
1.1       misho     152: 
                    153:        return task;
                    154: }
                    155: 
                    156: /*
1.2       misho     157:  * schedWrite() - Add WRITE I/O task to scheduler queue
1.1       misho     158:  * @root = root task
                    159:  * @func = task execution function
                    160:  * @arg = 1st func argument
1.2       misho     161:  * @fd = fd handle
1.4.2.2 ! misho     162:  * @opt_data = Optional data
        !           163:  * @opt_dlen = Optional data length
1.1       misho     164:  * return: NULL error or !=NULL new queued task
                    165:  */
                    166: sched_task_t *
1.4.2.2 ! misho     167: schedWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
        !           168:                void *opt_data, size_t opt_dlen)
1.1       misho     169: {
                    170:        sched_task_t *task;
                    171:        void *ptr;
                    172: 
                    173:        if (!root || !func)
                    174:                return NULL;
                    175: 
                    176:        /* get new task */
1.4       misho     177:        if (!(task = _sched_useTask(root)))
                    178:                return NULL;
1.1       misho     179: 
                    180:        memset(task, 0, sizeof(sched_task_t));
                    181:        task->task_id = 0;
1.4       misho     182:        task->task_lock = 0;
1.1       misho     183:        task->task_func = func;
1.4.2.1   misho     184:        TASK_TYPE(task) = taskWRITE;
                    185:        TASK_ROOT(task) = root;
1.1       misho     186: 
                    187:        TASK_ARG(task) = arg;
1.2       misho     188:        TASK_FD(task) = fd;
1.1       misho     189: 
1.4.2.2 ! misho     190:        TASK_DATA(task) = opt_data;
        !           191:        TASK_DATLEN(task) = opt_dlen;
        !           192: 
1.1       misho     193:        if (root->root_hooks.hook_add.write)
                    194:                ptr = root->root_hooks.hook_add.write(task, NULL);
                    195:        else
                    196:                ptr = NULL;
                    197: 
1.4.2.1   misho     198:        if (!ptr) {
                    199: #ifdef HAVE_LIBPTHREAD
                    200:                pthread_mutex_lock(&root->root_mtx[taskWRITE]);
                    201: #endif
1.1       misho     202:                TAILQ_INSERT_TAIL(&root->root_write, task, task_node);
1.4.2.1   misho     203: #ifdef HAVE_LIBPTHREAD
                    204:                pthread_mutex_unlock(&root->root_mtx[taskWRITE]);
                    205: #endif
                    206:        } else
1.4       misho     207:                task = _sched_unuseTask(task);
1.1       misho     208: 
                    209:        return task;
                    210: }
                    211: 
                    212: /*
                    213:  * schedTimer() - Add TIMER task to scheduler queue
                    214:  * @root = root task
                    215:  * @func = task execution function
                    216:  * @arg = 1st func argument
1.3       misho     217:  * @tv = timeout argument structure
1.4.2.2 ! misho     218:  * @opt_data = Optional data
        !           219:  * @opt_dlen = Optional data length
1.1       misho     220:  * return: NULL error or !=NULL new queued task
                    221:  */
                    222: sched_task_t *
1.4.2.2 ! misho     223: schedTimer(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timeval tv, 
        !           224:                void *opt_data, size_t opt_dlen)
1.1       misho     225: {
                    226:        sched_task_t *task, *t = NULL;
                    227:        void *ptr;
                    228:        struct timeval now;
                    229:        struct timespec nw;
                    230: 
                    231:        if (!root || !func)
                    232:                return NULL;
                    233: 
                    234:        /* get new task */
1.4       misho     235:        if (!(task = _sched_useTask(root)))
                    236:                return NULL;
1.1       misho     237: 
                    238:        memset(task, 0, sizeof(sched_task_t));
                    239:        task->task_id = 0;
1.4       misho     240:        task->task_lock = 0;
1.1       misho     241:        task->task_func = func;
1.4.2.1   misho     242:        TASK_TYPE(task) = taskTIMER;
                    243:        TASK_ROOT(task) = root;
1.1       misho     244: 
                    245:        TASK_ARG(task) = arg;
                    246: 
1.4.2.2 ! misho     247:        TASK_DATA(task) = opt_data;
        !           248:        TASK_DATLEN(task) = opt_dlen;
        !           249: 
1.1       misho     250:        /* calculate timeval structure */
                    251:        clock_gettime(CLOCK_MONOTONIC, &nw);
1.3       misho     252:        now.tv_sec = nw.tv_sec + tv.tv_sec;
                    253:        now.tv_usec = nw.tv_nsec / 1000 + tv.tv_usec;
1.1       misho     254:        if (now.tv_usec >= 1000000) {
                    255:                now.tv_sec++;
                    256:                now.tv_usec -= 1000000;
                    257:        } else if (now.tv_usec < 0) {
                    258:                now.tv_sec--;
                    259:                now.tv_usec += 1000000;
                    260:        }
                    261:        TASK_TV(task) = now;
                    262: 
                    263:        if (root->root_hooks.hook_add.timer)
                    264:                ptr = root->root_hooks.hook_add.timer(task, NULL);
                    265:        else
                    266:                ptr = NULL;
                    267: 
                    268:        if (!ptr) {
1.4.2.1   misho     269: #ifdef HAVE_LIBPTHREAD
                    270:                pthread_mutex_lock(&root->root_mtx[taskTIMER]);
                    271: #endif
1.1       misho     272: #ifdef TIMER_WITHOUT_SORT
                    273:                TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
                    274: #else
                    275:                TAILQ_FOREACH(t, &root->root_timer, task_node)
                    276:                        if (timercmp(&TASK_TV(task), &TASK_TV(t), -) < 1)
                    277:                                break;
                    278:                if (!t)
                    279:                        TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
                    280:                else
                    281:                        TAILQ_INSERT_BEFORE(t, task, task_node);
                    282: #endif
1.4.2.1   misho     283: #ifdef HAVE_LIBPTHREAD
                    284:                pthread_mutex_unlock(&root->root_mtx[taskTIMER]);
                    285: #endif
1.4       misho     286:        } else
                    287:                task = _sched_unuseTask(task);
1.1       misho     288: 
                    289:        return task;
                    290: }
                    291: 
                    292: /*
                    293:  * schedEvent() - Add EVENT task to scheduler queue
                    294:  * @root = root task
                    295:  * @func = task execution function
                    296:  * @arg = 1st func argument
1.2       misho     297:  * @val = additional func argument
1.4.2.2 ! misho     298:  * @opt_data = Optional data
        !           299:  * @opt_dlen = Optional data length
1.1       misho     300:  * return: NULL error or !=NULL new queued task
                    301:  */
                    302: sched_task_t *
1.4.2.2 ! misho     303: schedEvent(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val, 
        !           304:                void *opt_data, size_t opt_dlen)
1.1       misho     305: {
                    306:        sched_task_t *task;
                    307:        void *ptr;
                    308: 
                    309:        if (!root || !func)
                    310:                return NULL;
                    311: 
                    312:        /* get new task */
1.4       misho     313:        if (!(task = _sched_useTask(root)))
                    314:                return NULL;
1.1       misho     315: 
                    316:        memset(task, 0, sizeof(sched_task_t));
                    317:        task->task_id = 0;
1.4       misho     318:        task->task_lock = 0;
1.1       misho     319:        task->task_func = func;
1.4.2.1   misho     320:        TASK_TYPE(task) = taskEVENT;
                    321:        TASK_ROOT(task) = root;
1.1       misho     322: 
                    323:        TASK_ARG(task) = arg;
1.2       misho     324:        TASK_VAL(task) = val;
1.1       misho     325: 
1.4.2.2 ! misho     326:        TASK_DATA(task) = opt_data;
        !           327:        TASK_DATLEN(task) = opt_dlen;
        !           328: 
1.1       misho     329:        if (root->root_hooks.hook_add.event)
                    330:                ptr = root->root_hooks.hook_add.event(task, NULL);
                    331:        else
                    332:                ptr = NULL;
                    333: 
1.4.2.1   misho     334:        if (!ptr) {
                    335: #ifdef HAVE_LIBPTHREAD
                    336:                pthread_mutex_lock(&root->root_mtx[taskEVENT]);
                    337: #endif
1.1       misho     338:                TAILQ_INSERT_TAIL(&root->root_event, task, task_node);
1.4.2.1   misho     339: #ifdef HAVE_LIBPTHREAD
                    340:                pthread_mutex_unlock(&root->root_mtx[taskEVENT]);
                    341: #endif
                    342:        } else
1.4       misho     343:                task = _sched_unuseTask(task);
1.1       misho     344: 
                    345:        return task;
                    346: }
                    347: 
                    348: 
                    349: /*
                    350:  * schedEventLo() - Add EVENT_Lo task to scheduler queue
                    351:  * @root = root task
                    352:  * @func = task execution function
                    353:  * @arg = 1st func argument
1.2       misho     354:  * @val = additional func argument
1.4.2.2 ! misho     355:  * @opt_data = Optional data
        !           356:  * @opt_dlen = Optional data length
1.1       misho     357:  * return: NULL error or !=NULL new queued task
                    358:  */
                    359: sched_task_t *
1.4.2.2 ! misho     360: schedEventLo(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val, 
        !           361:                void *opt_data, size_t opt_dlen)
1.1       misho     362: {
                    363:        sched_task_t *task;
                    364:        void *ptr;
                    365: 
                    366:        if (!root || !func)
                    367:                return NULL;
                    368: 
                    369:        /* get new task */
1.4       misho     370:        if (!(task = _sched_useTask(root)))
                    371:                return NULL;
1.1       misho     372: 
                    373:        memset(task, 0, sizeof(sched_task_t));
                    374:        task->task_id = 0;
1.4       misho     375:        task->task_lock = 0;
1.1       misho     376:        task->task_func = func;
1.4.2.1   misho     377:        TASK_TYPE(task) = taskEVENT;
                    378:        TASK_ROOT(task) = root;
1.1       misho     379: 
                    380:        TASK_ARG(task) = arg;
1.2       misho     381:        TASK_VAL(task) = val;
1.1       misho     382: 
1.4.2.2 ! misho     383:        TASK_DATA(task) = opt_data;
        !           384:        TASK_DATLEN(task) = opt_dlen;
        !           385: 
1.1       misho     386:        if (root->root_hooks.hook_add.eventlo)
                    387:                ptr = root->root_hooks.hook_add.eventlo(task, NULL);
                    388:        else
                    389:                ptr = NULL;
                    390: 
1.4.2.1   misho     391:        if (!ptr) {
                    392: #ifdef HAVE_LIBPTHREAD
                    393:                pthread_mutex_lock(&root->root_mtx[taskEVENTLO]);
                    394: #endif
1.1       misho     395:                TAILQ_INSERT_TAIL(&root->root_eventlo, task, task_node);
1.4.2.1   misho     396: #ifdef HAVE_LIBPTHREAD
                    397:                pthread_mutex_unlock(&root->root_mtx[taskEVENTLO]);
                    398: #endif
                    399:        } else
1.4       misho     400:                task = _sched_unuseTask(task);
1.1       misho     401: 
                    402:        return task;
                    403: }
                    404: 
                    405: /*
                    406:  * schedCallOnce() - Call once from scheduler
                    407:  * @root = root task
                    408:  * @func = task execution function
                    409:  * @arg = 1st func argument
1.2       misho     410:  * @val = additional func argument
1.4.2.2 ! misho     411:  * @opt_data = Optional data
        !           412:  * @opt_dlen = Optional data length
1.2       misho     413:  * return: return value from called func
1.1       misho     414:  */
                    415: sched_task_t *
1.4.2.2 ! misho     416: schedCallOnce(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val, 
        !           417:                void *opt_data, size_t opt_dlen)
1.1       misho     418: {
                    419:        sched_task_t *task;
1.2       misho     420:        void *ret;
1.1       misho     421: 
                    422:        if (!root || !func)
                    423:                return NULL;
                    424: 
                    425:        /* get new task */
1.4       misho     426:        if (!(task = _sched_useTask(root)))
                    427:                return NULL;
1.1       misho     428: 
                    429:        memset(task, 0, sizeof(sched_task_t));
                    430:        task->task_id = 0;
1.4       misho     431:        task->task_lock = 0;
1.1       misho     432:        task->task_func = func;
1.4.2.1   misho     433:        TASK_TYPE(task) = taskEVENT;
                    434:        TASK_ROOT(task) = root;
1.1       misho     435: 
                    436:        TASK_ARG(task) = arg;
1.2       misho     437:        TASK_VAL(task) = val;
1.1       misho     438: 
1.4.2.2 ! misho     439:        TASK_DATA(task) = opt_data;
        !           440:        TASK_DATLEN(task) = opt_dlen;
        !           441: 
1.2       misho     442:        ret = schedCall(task);
1.1       misho     443: 
1.4       misho     444:        _sched_unuseTask(task);
1.2       misho     445:        return ret;
1.1       misho     446: }

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