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

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