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

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.31    ! misho       6: * $Id: tasks.c,v 1.30.6.2 2023/02/24 16:21:23 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.31    ! misho      15: Copyright 2004 - 2023
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.13      misho      49: /*
                     50:  * sched_useTask() - Get and init new task
                     51:  *
                     52:  * @root = root task
                     53:  * return: NULL error or !=NULL prepared task
                     54:  */
1.16      misho      55: sched_task_t *
1.13      misho      56: sched_useTask(sched_root_task_t * __restrict root)
1.4       misho      57: {
1.7       misho      58:        sched_task_t *task, *tmp;
1.4       misho      59: 
1.25      misho      60:        SCHED_QLOCK(root, taskUNUSE);
1.7       misho      61:        TAILQ_FOREACH_SAFE(task, &root->root_unuse, task_node, tmp) {
1.4       misho      62:                if (!TASK_ISLOCKED(task)) {
                     63:                        TAILQ_REMOVE(&root->root_unuse, task, task_node);
                     64:                        break;
                     65:                }
                     66:        }
1.25      misho      67:        SCHED_QUNLOCK(root, taskUNUSE);
1.4       misho      68: 
                     69:        if (!task) {
1.29      misho      70:                task = e_malloc(sizeof(sched_task_t));
1.4       misho      71:                if (!task) {
                     72:                        LOGERR;
                     73:                        return NULL;
                     74:                }
                     75:        }
                     76: 
1.9       misho      77:        memset(task, 0, sizeof(sched_task_t));
                     78:        task->task_id = (uintptr_t) task;
1.4       misho      79:        return task;
                     80: }
                     81: 
1.13      misho      82: /*
                     83:  * sched_unuseTask() - Unlock and put task to unuse queue
                     84:  *
                     85:  * @task = task
                     86:  * return: always is NULL
                     87:  */
1.16      misho      88: sched_task_t *
1.13      misho      89: sched_unuseTask(sched_task_t * __restrict task)
1.4       misho      90: {
                     91:        TASK_UNLOCK(task);
1.25      misho      92: 
1.5       misho      93:        TASK_TYPE(task) = taskUNUSE;
1.25      misho      94:        insert_task_to(task, &(TASK_ROOT(task))->root_unuse);
                     95: 
1.4       misho      96:        task = NULL;
                     97:        return task;
                     98: }
                     99: 
1.14      misho     100: /*
                    101:  * sched_taskExit() - Exit routine for scheduler task, explicit required for thread tasks
                    102:  *
                    103:  * @task = current task
                    104:  * @retcode = return code
                    105:  * return: return code
                    106:  */
1.16      misho     107: void *
1.14      misho     108: sched_taskExit(sched_task_t *task, intptr_t retcode)
                    109: {
                    110:        if (!task || !TASK_ROOT(task))
                    111:                return (void*) -1;
                    112: 
                    113:        if (TASK_ROOT(task)->root_hooks.hook_exec.exit)
                    114:                TASK_ROOT(task)->root_hooks.hook_exec.exit(task, (void*) retcode);
                    115: 
                    116:        TASK_ROOT(task)->root_ret = (void*) retcode;
                    117:        return (void*) retcode;
                    118: }
                    119: 
1.4       misho     120: 
1.1       misho     121: /*
1.2       misho     122:  * schedRead() - Add READ I/O task to scheduler queue
1.6       misho     123:  *
1.1       misho     124:  * @root = root task
                    125:  * @func = task execution function
                    126:  * @arg = 1st func argument
1.2       misho     127:  * @fd = fd handle
1.5       misho     128:  * @opt_data = Optional data
                    129:  * @opt_dlen = Optional data length
1.1       misho     130:  * return: NULL error or !=NULL new queued task
                    131:  */
                    132: sched_task_t *
1.5       misho     133: schedRead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    134:                void *opt_data, size_t opt_dlen)
1.1       misho     135: {
1.30      misho     136:        return schedReadExt(root, func, arg, fd, opt_data, opt_dlen, 0);
                    137: }
                    138: 
                    139: /*
                    140:  * schedReadExt() - Add READ I/O task to scheduler queue with custom event mask
                    141:  *
                    142:  * @root = root task
                    143:  * @func = task execution function
                    144:  * @arg = 1st func argument
                    145:  * @fd = fd handle
                    146:  * @opt_data = Optional data
                    147:  * @opt_dlen = Optional data length
                    148:  * @mask = Event mask
                    149:  * return: NULL error or !=NULL new queued task
                    150:  */
                    151: sched_task_t *
                    152: schedReadExt(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    153:                void *opt_data, size_t opt_dlen, u_long mask)
                    154: {
1.1       misho     155:        sched_task_t *task;
                    156:        void *ptr;
                    157: 
                    158:        if (!root || !func)
                    159:                return NULL;
                    160: 
                    161:        /* get new task */
1.13      misho     162:        if (!(task = sched_useTask(root)))
1.4       misho     163:                return NULL;
1.1       misho     164: 
1.25      misho     165:        TASK_FUNC(task) = func;
1.5       misho     166:        TASK_TYPE(task) = taskREAD;
                    167:        TASK_ROOT(task) = root;
1.1       misho     168: 
                    169:        TASK_ARG(task) = arg;
1.2       misho     170:        TASK_FD(task) = fd;
1.1       misho     171: 
1.5       misho     172:        TASK_DATA(task) = opt_data;
                    173:        TASK_DATLEN(task) = opt_dlen;
                    174: 
1.30      misho     175:        TASK_HARG(task) = mask;
                    176: 
1.1       misho     177:        if (root->root_hooks.hook_add.read)
1.30      misho     178:                ptr = root->root_hooks.hook_add.read(task, 
                    179:                                (void*) task->task_harg);
1.1       misho     180:        else
                    181:                ptr = NULL;
                    182: 
1.25      misho     183:        if (!ptr)
                    184:                insert_task_to(task, &root->root_read);
                    185:        else
1.13      misho     186:                task = sched_unuseTask(task);
1.1       misho     187: 
                    188:        return task;
                    189: }
                    190: 
                    191: /*
1.2       misho     192:  * schedWrite() - Add WRITE I/O task to scheduler queue
1.6       misho     193:  *
1.1       misho     194:  * @root = root task
                    195:  * @func = task execution function
                    196:  * @arg = 1st func argument
1.2       misho     197:  * @fd = fd handle
1.5       misho     198:  * @opt_data = Optional data
                    199:  * @opt_dlen = Optional data length
1.1       misho     200:  * return: NULL error or !=NULL new queued task
                    201:  */
                    202: sched_task_t *
1.5       misho     203: schedWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    204:                void *opt_data, size_t opt_dlen)
1.1       misho     205: {
1.30      misho     206:        return schedWriteExt(root, func, arg, fd, opt_data, opt_dlen, 0);
                    207: }
                    208: 
                    209: /*
                    210:  * schedWriteExt() - Add WRITE I/O task to scheduler queue with custom event mask
                    211:  *
                    212:  * @root = root task
                    213:  * @func = task execution function
                    214:  * @arg = 1st func argument
                    215:  * @fd = fd handle
                    216:  * @opt_data = Optional data
                    217:  * @opt_dlen = Optional data length
                    218:  * @mask = Event mask
                    219:  * return: NULL error or !=NULL new queued task
                    220:  */
                    221: sched_task_t *
                    222: schedWriteExt(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    223:                void *opt_data, size_t opt_dlen, u_long mask)
                    224: {
1.1       misho     225:        sched_task_t *task;
                    226:        void *ptr;
                    227: 
                    228:        if (!root || !func)
                    229:                return NULL;
                    230: 
                    231:        /* get new task */
1.13      misho     232:        if (!(task = sched_useTask(root)))
1.4       misho     233:                return NULL;
1.1       misho     234: 
1.25      misho     235:        TASK_FUNC(task) = func;
1.5       misho     236:        TASK_TYPE(task) = taskWRITE;
                    237:        TASK_ROOT(task) = root;
1.1       misho     238: 
                    239:        TASK_ARG(task) = arg;
1.2       misho     240:        TASK_FD(task) = fd;
1.1       misho     241: 
1.5       misho     242:        TASK_DATA(task) = opt_data;
                    243:        TASK_DATLEN(task) = opt_dlen;
                    244: 
1.30      misho     245:        TASK_HARG(task) = mask;
                    246: 
1.1       misho     247:        if (root->root_hooks.hook_add.write)
1.30      misho     248:                ptr = root->root_hooks.hook_add.write(task, 
                    249:                                (void*) task->task_harg);
1.1       misho     250:        else
                    251:                ptr = NULL;
                    252: 
1.25      misho     253:        if (!ptr)
                    254:                insert_task_to(task, &root->root_write);
                    255:        else
1.13      misho     256:                task = sched_unuseTask(task);
1.1       misho     257: 
                    258:        return task;
                    259: }
                    260: 
                    261: /*
1.9       misho     262:  * schedNode() - Add NODE task to scheduler queue
                    263:  *
                    264:  * @root = root task
                    265:  * @func = task execution function
                    266:  * @arg = 1st func argument
                    267:  * @fd = fd handle
                    268:  * @opt_data = Optional data
                    269:  * @opt_dlen = Optional data length
                    270:  * return: NULL error or !=NULL new queued task
                    271:  */
                    272: sched_task_t *
                    273: schedNode(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    274:                void *opt_data, size_t opt_dlen)
                    275: {
1.25      misho     276: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     277:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    278:        return NULL;
                    279: #else
1.9       misho     280:        sched_task_t *task;
                    281:        void *ptr;
                    282: 
                    283:        if (!root || !func)
                    284:                return NULL;
                    285: 
                    286:        /* get new task */
1.13      misho     287:        if (!(task = sched_useTask(root)))
1.9       misho     288:                return NULL;
                    289: 
1.25      misho     290:        TASK_FUNC(task) = func;
1.9       misho     291:        TASK_TYPE(task) = taskNODE;
                    292:        TASK_ROOT(task) = root;
                    293: 
                    294:        TASK_ARG(task) = arg;
                    295:        TASK_FD(task) = fd;
                    296: 
                    297:        TASK_DATA(task) = opt_data;
                    298:        TASK_DATLEN(task) = opt_dlen;
                    299: 
                    300:        if (root->root_hooks.hook_add.node)
                    301:                ptr = root->root_hooks.hook_add.node(task, NULL);
1.27      misho     302:        else
                    303:                ptr = NULL;
                    304: 
                    305:        if (!ptr)
                    306:                insert_task_to(task, &root->root_node);
                    307:        else
                    308:                task = sched_unuseTask(task);
                    309: 
                    310:        return task;
                    311: #endif /* KQ_SUPPORT */
                    312: }
                    313: 
                    314: /*
                    315:  * schedNode2() - Add NODE task with all events to scheduler queue
                    316:  *
                    317:  * @root = root task
                    318:  * @func = task execution function
                    319:  * @arg = 1st func argument
                    320:  * @fd = fd handle
                    321:  * @opt_data = Optional data
                    322:  * @opt_dlen = Optional data length
                    323:  * return: NULL error or !=NULL new queued task
                    324:  */
                    325: sched_task_t *
                    326: schedNode2(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    327:                void *opt_data, size_t opt_dlen)
                    328: {
                    329: #if SUP_ENABLE != KQ_SUPPORT
                    330:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    331:        return NULL;
                    332: #else
                    333:        sched_task_t *task;
                    334:        void *ptr;
                    335: 
                    336:        if (!root || !func)
                    337:                return NULL;
                    338: 
                    339:        /* get new task */
                    340:        if (!(task = sched_useTask(root)))
                    341:                return NULL;
                    342: 
                    343:        TASK_FUNC(task) = func;
                    344:        TASK_TYPE(task) = taskNODE;
                    345:        TASK_ROOT(task) = root;
                    346: 
                    347:        TASK_ARG(task) = arg;
                    348:        TASK_FD(task) = fd;
                    349: 
                    350:        TASK_DATA(task) = opt_data;
                    351:        TASK_DATLEN(task) = opt_dlen;
                    352: 
                    353:        if (root->root_hooks.hook_add.node)
1.28      misho     354: #ifdef __FreeBSD__
1.27      misho     355:                ptr = root->root_hooks.hook_add.node(task, 
                    356:                                (void*) (NOTE_READ | NOTE_CLOSE_WRITE | NOTE_CLOSE | NOTE_OPEN));
1.28      misho     357: #else
                    358:                ptr = root->root_hooks.hook_add.node(task, NULL);
                    359: #endif
1.9       misho     360:        else
                    361:                ptr = NULL;
                    362: 
1.25      misho     363:        if (!ptr)
                    364:                insert_task_to(task, &root->root_node);
                    365:        else
1.13      misho     366:                task = sched_unuseTask(task);
1.9       misho     367: 
                    368:        return task;
1.25      misho     369: #endif /* KQ_SUPPORT */
1.9       misho     370: }
                    371: 
                    372: /*
                    373:  * schedProc() - Add PROC task to scheduler queue
                    374:  *
                    375:  * @root = root task
                    376:  * @func = task execution function
                    377:  * @arg = 1st func argument
                    378:  * @pid = PID
                    379:  * @opt_data = Optional data
                    380:  * @opt_dlen = Optional data length
                    381:  * return: NULL error or !=NULL new queued task
                    382:  */
                    383: sched_task_t *
                    384: schedProc(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long pid, 
                    385:                void *opt_data, size_t opt_dlen)
                    386: {
1.25      misho     387: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     388:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    389:        return NULL;
                    390: #else
1.9       misho     391:        sched_task_t *task;
                    392:        void *ptr;
                    393: 
                    394:        if (!root || !func)
                    395:                return NULL;
                    396: 
                    397:        /* get new task */
1.13      misho     398:        if (!(task = sched_useTask(root)))
1.9       misho     399:                return NULL;
                    400: 
1.25      misho     401:        TASK_FUNC(task) = func;
1.9       misho     402:        TASK_TYPE(task) = taskPROC;
                    403:        TASK_ROOT(task) = root;
                    404: 
                    405:        TASK_ARG(task) = arg;
                    406:        TASK_VAL(task) = pid;
                    407: 
                    408:        TASK_DATA(task) = opt_data;
                    409:        TASK_DATLEN(task) = opt_dlen;
                    410: 
                    411:        if (root->root_hooks.hook_add.proc)
                    412:                ptr = root->root_hooks.hook_add.proc(task, NULL);
                    413:        else
                    414:                ptr = NULL;
                    415: 
1.25      misho     416:        if (!ptr)
                    417:                insert_task_to(task, &root->root_proc);
                    418:        else
1.13      misho     419:                task = sched_unuseTask(task);
1.9       misho     420: 
                    421:        return task;
1.25      misho     422: #endif /* KQ_SUPPORT */
1.9       misho     423: }
                    424: 
                    425: /*
                    426:  * schedUser() - Add trigger USER task to scheduler queue
                    427:  *
                    428:  * @root = root task
                    429:  * @func = task execution function
                    430:  * @arg = 1st func argument
                    431:  * @id = Trigger ID
                    432:  * @opt_data = Optional data
                    433:  * @opt_dlen = Optional user's trigger flags
                    434:  * return: NULL error or !=NULL new queued task
                    435:  */
                    436: sched_task_t *
                    437: schedUser(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long id, 
                    438:                void *opt_data, size_t opt_dlen)
                    439: {
1.25      misho     440: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     441:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    442:        return NULL;
                    443: #else
1.9       misho     444: #ifndef EVFILT_USER
                    445:        sched_SetErr(ENOTSUP, "Not supported kevent() filter");
                    446:        return NULL;
                    447: #else
                    448:        sched_task_t *task;
                    449:        void *ptr;
                    450: 
                    451:        if (!root || !func)
                    452:                return NULL;
                    453: 
                    454:        /* get new task */
1.13      misho     455:        if (!(task = sched_useTask(root)))
1.9       misho     456:                return NULL;
                    457: 
1.25      misho     458:        TASK_FUNC(task) = func;
1.9       misho     459:        TASK_TYPE(task) = taskUSER;
                    460:        TASK_ROOT(task) = root;
                    461: 
                    462:        TASK_ARG(task) = arg;
                    463:        TASK_VAL(task) = id;
                    464: 
                    465:        TASK_DATA(task) = opt_data;
                    466:        TASK_DATLEN(task) = opt_dlen;
                    467: 
                    468:        if (root->root_hooks.hook_add.user)
                    469:                ptr = root->root_hooks.hook_add.user(task, NULL);
                    470:        else
                    471:                ptr = NULL;
                    472: 
1.25      misho     473:        if (!ptr)
                    474:                insert_task_to(task, &root->root_user);
                    475:        else
1.13      misho     476:                task = sched_unuseTask(task);
1.9       misho     477: 
                    478:        return task;
1.23      misho     479: #endif /* EVFILT_USER */
1.25      misho     480: #endif /* KQ_SUPPORT */
1.9       misho     481: }
                    482: 
                    483: /*
                    484:  * schedSignal() - Add SIGNAL task to scheduler queue
                    485:  *
                    486:  * @root = root task
                    487:  * @func = task execution function
                    488:  * @arg = 1st func argument
                    489:  * @sig = Signal
                    490:  * @opt_data = Optional data
                    491:  * @opt_dlen = Optional data length
                    492:  * return: NULL error or !=NULL new queued task
                    493:  */
                    494: sched_task_t *
                    495: schedSignal(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long sig, 
                    496:                void *opt_data, size_t opt_dlen)
                    497: {
                    498:        sched_task_t *task;
                    499:        void *ptr;
                    500: 
                    501:        if (!root || !func)
                    502:                return NULL;
                    503: 
                    504:        /* get new task */
1.13      misho     505:        if (!(task = sched_useTask(root)))
1.9       misho     506:                return NULL;
                    507: 
1.25      misho     508:        TASK_FUNC(task) = func;
1.9       misho     509:        TASK_TYPE(task) = taskSIGNAL;
                    510:        TASK_ROOT(task) = root;
                    511: 
                    512:        TASK_ARG(task) = arg;
                    513:        TASK_VAL(task) = sig;
                    514: 
                    515:        TASK_DATA(task) = opt_data;
                    516:        TASK_DATLEN(task) = opt_dlen;
                    517: 
                    518:        if (root->root_hooks.hook_add.signal)
                    519:                ptr = root->root_hooks.hook_add.signal(task, NULL);
                    520:        else
                    521:                ptr = NULL;
                    522: 
1.25      misho     523:        if (!ptr)
                    524:                insert_task_to(task, &root->root_signal);
                    525:        else
1.13      misho     526:                task = sched_unuseTask(task);
1.9       misho     527: 
                    528:        return task;
                    529: }
                    530: 
                    531: /*
1.8       misho     532:  * schedAlarm() - Add ALARM task to scheduler queue
                    533:  *
                    534:  * @root = root task
                    535:  * @func = task execution function
                    536:  * @arg = 1st func argument
                    537:  * @ts = timeout argument structure, minimum alarm timer resolution is 1msec!
1.17      misho     538:  * @opt_data = Alarm timer ID
1.8       misho     539:  * @opt_dlen = Optional data length
                    540:  * return: NULL error or !=NULL new queued task
                    541:  */
                    542: sched_task_t *
                    543: schedAlarm(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts, 
                    544:                void *opt_data, size_t opt_dlen)
                    545: {
1.25      misho     546: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     547:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    548:        return NULL;
                    549: #else
1.8       misho     550:        sched_task_t *task;
                    551:        void *ptr;
                    552: 
                    553:        if (!root || !func)
                    554:                return NULL;
                    555: 
                    556:        /* get new task */
1.13      misho     557:        if (!(task = sched_useTask(root)))
1.8       misho     558:                return NULL;
                    559: 
1.25      misho     560:        TASK_FUNC(task) = func;
1.8       misho     561:        TASK_TYPE(task) = taskALARM;
                    562:        TASK_ROOT(task) = root;
                    563: 
                    564:        TASK_ARG(task) = arg;
                    565:        TASK_TS(task) = ts;
                    566: 
                    567:        TASK_DATA(task) = opt_data;
                    568:        TASK_DATLEN(task) = opt_dlen;
                    569: 
                    570:        if (root->root_hooks.hook_add.alarm)
                    571:                ptr = root->root_hooks.hook_add.alarm(task, NULL);
                    572:        else
                    573:                ptr = NULL;
                    574: 
1.25      misho     575:        if (!ptr)
                    576:                insert_task_to(task, &root->root_alarm);
                    577:        else
1.13      misho     578:                task = sched_unuseTask(task);
1.8       misho     579: 
                    580:        return task;
1.25      misho     581: #endif /* KQ_SUPPORT */
1.8       misho     582: }
                    583: 
1.11      misho     584: #ifdef AIO_SUPPORT
                    585: /*
                    586:  * schedAIO() - Add AIO task to scheduler queue
                    587:  *
                    588:  * @root = root task
                    589:  * @func = task execution function
                    590:  * @arg = 1st func argument
                    591:  * @acb = AIO cb structure address
                    592:  * @opt_data = Optional data
                    593:  * @opt_dlen = Optional data length
                    594:  * return: NULL error or !=NULL new queued task
                    595:  */
                    596: sched_task_t *
                    597: schedAIO(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, 
                    598:                struct aiocb * __restrict acb, void *opt_data, size_t opt_dlen)
                    599: {
1.25      misho     600: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     601:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    602:        return NULL;
                    603: #else
1.11      misho     604:        sched_task_t *task;
                    605:        void *ptr;
                    606: 
                    607:        if (!root || !func || !acb || !opt_dlen)
                    608:                return NULL;
                    609: 
                    610:        /* get new task */
1.13      misho     611:        if (!(task = sched_useTask(root)))
1.11      misho     612:                return NULL;
                    613: 
1.25      misho     614:        TASK_FUNC(task) = func;
1.11      misho     615:        TASK_TYPE(task) = taskAIO;
                    616:        TASK_ROOT(task) = root;
                    617: 
                    618:        TASK_ARG(task) = arg;
                    619:        TASK_VAL(task) = (u_long) acb;
                    620: 
                    621:        TASK_DATA(task) = opt_data;
                    622:        TASK_DATLEN(task) = opt_dlen;
                    623: 
                    624:        if (root->root_hooks.hook_add.aio)
                    625:                ptr = root->root_hooks.hook_add.aio(task, NULL);
                    626:        else
                    627:                ptr = NULL;
                    628: 
1.25      misho     629:        if (!ptr)
                    630:                insert_task_to(task, &root->root_aio);
                    631:        else
1.13      misho     632:                task = sched_unuseTask(task);
1.11      misho     633: 
                    634:        return task;
1.25      misho     635: #endif /* KQ_SUPPORT */
1.11      misho     636: }
                    637: 
                    638: /*
                    639:  * schedAIORead() - Add AIO read task to scheduler queue
                    640:  *
                    641:  * @root = root task
                    642:  * @func = task execution function
                    643:  * @arg = 1st func argument
                    644:  * @fd = file descriptor
                    645:  * @buffer = Buffer
                    646:  * @buflen = Buffer length
                    647:  * @offset = Offset from start of file, if =-1 from current position
                    648:  * return: NULL error or !=NULL new queued task
                    649:  */
1.16      misho     650: sched_task_t *
1.11      misho     651: schedAIORead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    652:                void *buffer, size_t buflen, off_t offset)
                    653: {
1.25      misho     654: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     655:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    656:        return NULL;
                    657: #else
1.11      misho     658:        struct aiocb *acb;
                    659:        off_t off;
                    660: 
                    661:        if (!root || !func || !buffer || !buflen)
                    662:                return NULL;
                    663: 
                    664:        if (offset == (off_t) -1) {
                    665:                off = lseek(fd, 0, SEEK_CUR);
                    666:                if (off == -1) {
                    667:                        LOGERR;
                    668:                        return NULL;
                    669:                }
                    670:        } else
                    671:                off = offset;
                    672: 
1.29      misho     673:        if (!(acb = e_malloc(sizeof(struct aiocb)))) {
1.11      misho     674:                LOGERR;
                    675:                return NULL;
                    676:        } else
                    677:                memset(acb, 0, sizeof(struct aiocb));
                    678: 
                    679:        acb->aio_fildes = fd;
                    680:        acb->aio_nbytes = buflen;
                    681:        acb->aio_buf = buffer;
                    682:        acb->aio_offset = off;
                    683:        acb->aio_sigevent.sigev_notify = SIGEV_KEVENT;
                    684:        acb->aio_sigevent.sigev_notify_kqueue = root->root_kq;
                    685:        acb->aio_sigevent.sigev_value.sival_ptr = acb;
                    686: 
                    687:        if (aio_read(acb)) {
                    688:                LOGERR;
1.29      misho     689:                e_free(acb);
1.11      misho     690:                return NULL;
                    691:        }
                    692: 
                    693:        return schedAIO(root, func, arg, acb, buffer, buflen);
1.25      misho     694: #endif /* KQ_SUPPORT */
1.11      misho     695: }
                    696: 
                    697: /*
                    698:  * schedAIOWrite() - Add AIO write task to scheduler queue
                    699:  *
                    700:  * @root = root task
                    701:  * @func = task execution function
                    702:  * @arg = 1st func argument
                    703:  * @fd = file descriptor
                    704:  * @buffer = Buffer
                    705:  * @buflen = Buffer length
                    706:  * @offset = Offset from start of file, if =-1 from current position
                    707:  * return: NULL error or !=NULL new queued task
                    708:  */
1.16      misho     709: sched_task_t *
1.11      misho     710: schedAIOWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    711:                void *buffer, size_t buflen, off_t offset)
                    712: {
1.25      misho     713: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     714:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    715:        return NULL;
                    716: #else
1.11      misho     717:        struct aiocb *acb;
                    718:        off_t off;
                    719: 
                    720:        if (!root || !func || !buffer || !buflen)
                    721:                return NULL;
                    722: 
                    723:        if (offset == (off_t) -1) {
                    724:                off = lseek(fd, 0, SEEK_CUR);
                    725:                if (off == -1) {
                    726:                        LOGERR;
                    727:                        return NULL;
                    728:                }
                    729:        } else
                    730:                off = offset;
                    731: 
1.29      misho     732:        if (!(acb = e_malloc(sizeof(struct aiocb)))) {
1.11      misho     733:                LOGERR;
                    734:                return NULL;
                    735:        } else
                    736:                memset(acb, 0, sizeof(struct aiocb));
                    737: 
                    738:        acb->aio_fildes = fd;
                    739:        acb->aio_nbytes = buflen;
                    740:        acb->aio_buf = buffer;
                    741:        acb->aio_offset = off;
                    742:        acb->aio_sigevent.sigev_notify = SIGEV_KEVENT;
                    743:        acb->aio_sigevent.sigev_notify_kqueue = root->root_kq;
                    744:        acb->aio_sigevent.sigev_value.sival_ptr = acb;
                    745: 
                    746:        if (aio_write(acb)) {
                    747:                LOGERR;
1.29      misho     748:                e_free(acb);
1.11      misho     749:                return NULL;
                    750:        }
                    751: 
                    752:        return schedAIO(root, func, arg, acb, buffer, buflen);
1.25      misho     753: #endif /* KQ_SUPPORT */
1.11      misho     754: }
                    755: 
                    756: #ifdef EVFILT_LIO
                    757: /*
                    758:  * schedLIO() - Add AIO bulk tasks to scheduler queue
                    759:  *
                    760:  * @root = root task
                    761:  * @func = task execution function
                    762:  * @arg = 1st func argument
                    763:  * @acbs = AIO cb structure addresses
                    764:  * @opt_data = Optional data
                    765:  * @opt_dlen = Optional data length
                    766:  * return: NULL error or !=NULL new queued task
                    767:  */
                    768: sched_task_t *
                    769: schedLIO(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, 
                    770:                struct aiocb ** __restrict acbs, void *opt_data, size_t opt_dlen)
                    771: {
1.25      misho     772: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     773:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    774:        return NULL;
                    775: #else
1.11      misho     776:        sched_task_t *task;
                    777:        void *ptr;
                    778: 
                    779:        if (!root || !func || !acbs || !opt_dlen)
                    780:                return NULL;
                    781: 
                    782:        /* get new task */
1.13      misho     783:        if (!(task = sched_useTask(root)))
1.11      misho     784:                return NULL;
                    785: 
1.25      misho     786:        TASK_FUNC(task) = func;
1.11      misho     787:        TASK_TYPE(task) = taskLIO;
                    788:        TASK_ROOT(task) = root;
                    789: 
                    790:        TASK_ARG(task) = arg;
                    791:        TASK_VAL(task) = (u_long) acbs;
                    792: 
                    793:        TASK_DATA(task) = opt_data;
                    794:        TASK_DATLEN(task) = opt_dlen;
                    795: 
                    796:        if (root->root_hooks.hook_add.lio)
                    797:                ptr = root->root_hooks.hook_add.lio(task, NULL);
                    798:        else
                    799:                ptr = NULL;
                    800: 
1.25      misho     801:        if (!ptr)
                    802:                insert_task_to(task, &root->root_lio);
                    803:        else
1.13      misho     804:                task = sched_unuseTask(task);
1.11      misho     805: 
                    806:        return task;
1.25      misho     807: #endif /* KQ_SUPPORT */
1.11      misho     808: }
                    809: 
                    810: /*
                    811:  * schedLIORead() - Add list of AIO read tasks to scheduler queue
                    812:  *
                    813:  * @root = root task
                    814:  * @func = task execution function
                    815:  * @arg = 1st func argument
                    816:  * @fd = file descriptor
                    817:  * @bufs = Buffer's list
                    818:  * @nbufs = Number of Buffers
                    819:  * @offset = Offset from start of file, if =-1 from current position
                    820:  * return: NULL error or !=NULL new queued task
                    821:  */
                    822: sched_task_t *
                    823: schedLIORead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    824:                struct iovec *bufs, size_t nbufs, off_t offset)
                    825: {
1.25      misho     826: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     827:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    828:        return NULL;
                    829: #else
1.11      misho     830:        struct sigevent sig;
                    831:        struct aiocb **acb;
                    832:        off_t off;
                    833:        register int i;
                    834: 
                    835:        if (!root || !func || !bufs || !nbufs)
                    836:                return NULL;
                    837: 
                    838:        if (offset == (off_t) -1) {
                    839:                off = lseek(fd, 0, SEEK_CUR);
                    840:                if (off == -1) {
                    841:                        LOGERR;
                    842:                        return NULL;
                    843:                }
                    844:        } else
                    845:                off = offset;
                    846: 
1.29      misho     847:        if (!(acb = e_calloc(sizeof(void*), nbufs))) {
1.11      misho     848:                LOGERR;
                    849:                return NULL;
                    850:        } else
                    851:                memset(acb, 0, sizeof(void*) * nbufs);
                    852:        for (i = 0; i < nbufs; off += bufs[i++].iov_len) {
1.29      misho     853:                acb[i] = e_malloc(sizeof(struct aiocb));
1.11      misho     854:                if (!acb[i]) {
                    855:                        LOGERR;
                    856:                        for (i = 0; i < nbufs; i++)
                    857:                                if (acb[i])
1.29      misho     858:                                        e_free(acb[i]);
                    859:                        e_free(acb);
1.11      misho     860:                        return NULL;
                    861:                } else
                    862:                        memset(acb[i], 0, sizeof(struct aiocb));
                    863:                acb[i]->aio_fildes = fd;
                    864:                acb[i]->aio_nbytes = bufs[i].iov_len;
                    865:                acb[i]->aio_buf = bufs[i].iov_base;
                    866:                acb[i]->aio_offset = off;
                    867:                acb[i]->aio_lio_opcode = LIO_READ;
                    868:        }
                    869:        memset(&sig, 0, sizeof sig);
                    870:        sig.sigev_notify = SIGEV_KEVENT;
                    871:        sig.sigev_notify_kqueue = root->root_kq;
                    872:        sig.sigev_value.sival_ptr = acb;
                    873: 
                    874:        if (lio_listio(LIO_NOWAIT, acb, nbufs, &sig)) {
                    875:                LOGERR;
                    876:                for (i = 0; i < nbufs; i++)
                    877:                        if (acb[i])
1.29      misho     878:                                e_free(acb[i]);
                    879:                e_free(acb);
1.11      misho     880:                return NULL;
                    881:        }
                    882: 
                    883:        return schedLIO(root, func, arg, (void*) acb, bufs, nbufs);
1.25      misho     884: #endif /* KQ_SUPPORT */
1.11      misho     885: }
                    886: 
                    887: /*
                    888:  * schedLIOWrite() - Add list of AIO write tasks to scheduler queue
                    889:  *
                    890:  * @root = root task
                    891:  * @func = task execution function
                    892:  * @arg = 1st func argument
                    893:  * @fd = file descriptor
                    894:  * @bufs = Buffer's list
                    895:  * @nbufs = Number of Buffers
                    896:  * @offset = Offset from start of file, if =-1 from current position
                    897:  * return: NULL error or !=NULL new queued task
                    898:  */
1.16      misho     899: sched_task_t *
1.11      misho     900: schedLIOWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd, 
                    901:                struct iovec *bufs, size_t nbufs, off_t offset)
                    902: {
1.25      misho     903: #if SUP_ENABLE != KQ_SUPPORT
1.23      misho     904:        sched_SetErr(ENOTSUP, "disabled kqueue support");
                    905:        return NULL;
                    906: #else
1.11      misho     907:        struct sigevent sig;
                    908:        struct aiocb **acb;
                    909:        off_t off;
                    910:        register int i;
                    911: 
                    912:        if (!root || !func || !bufs || !nbufs)
                    913:                return NULL;
                    914: 
                    915:        if (offset == (off_t) -1) {
                    916:                off = lseek(fd, 0, SEEK_CUR);
                    917:                if (off == -1) {
                    918:                        LOGERR;
                    919:                        return NULL;
                    920:                }
                    921:        } else
                    922:                off = offset;
                    923: 
1.29      misho     924:        if (!(acb = e_calloc(sizeof(void*), nbufs))) {
1.11      misho     925:                LOGERR;
                    926:                return NULL;
                    927:        } else
                    928:                memset(acb, 0, sizeof(void*) * nbufs);
                    929:        for (i = 0; i < nbufs; off += bufs[i++].iov_len) {
1.29      misho     930:                acb[i] = e_malloc(sizeof(struct aiocb));
1.11      misho     931:                if (!acb[i]) {
                    932:                        LOGERR;
                    933:                        for (i = 0; i < nbufs; i++)
                    934:                                if (acb[i])
1.29      misho     935:                                        e_free(acb[i]);
                    936:                        e_free(acb);
1.11      misho     937:                        return NULL;
                    938:                } else
                    939:                        memset(acb[i], 0, sizeof(struct aiocb));
                    940:                acb[i]->aio_fildes = fd;
                    941:                acb[i]->aio_nbytes = bufs[i].iov_len;
                    942:                acb[i]->aio_buf = bufs[i].iov_base;
                    943:                acb[i]->aio_offset = off;
                    944:                acb[i]->aio_lio_opcode = LIO_WRITE;
                    945:        }
                    946:        memset(&sig, 0, sizeof sig);
                    947:        sig.sigev_notify = SIGEV_KEVENT;
                    948:        sig.sigev_notify_kqueue = root->root_kq;
                    949:        sig.sigev_value.sival_ptr = acb;
                    950: 
                    951:        if (lio_listio(LIO_NOWAIT, acb, nbufs, &sig)) {
                    952:                LOGERR;
                    953:                for (i = 0; i < nbufs; i++)
                    954:                        if (acb[i])
1.29      misho     955:                                e_free(acb[i]);
                    956:                e_free(acb);
1.11      misho     957:                return NULL;
                    958:        }
                    959: 
                    960:        return schedLIO(root, func, arg, (void*) acb, bufs, nbufs);
1.25      misho     961: #endif /* KQ_SUPPORT */
1.11      misho     962: }
                    963: #endif /* EVFILT_LIO */
                    964: #endif /* AIO_SUPPORT */
                    965: 
1.8       misho     966: /*
1.1       misho     967:  * schedTimer() - Add TIMER task to scheduler queue
1.6       misho     968:  *
1.1       misho     969:  * @root = root task
                    970:  * @func = task execution function
                    971:  * @arg = 1st func argument
1.5       misho     972:  * @ts = timeout argument structure
                    973:  * @opt_data = Optional data
                    974:  * @opt_dlen = Optional data length
1.1       misho     975:  * return: NULL error or !=NULL new queued task
                    976:  */
                    977: sched_task_t *
1.5       misho     978: schedTimer(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts, 
                    979:                void *opt_data, size_t opt_dlen)
1.1       misho     980: {
1.9       misho     981:        sched_task_t *task, *tmp, *t = NULL;
1.1       misho     982:        void *ptr;
1.5       misho     983:        struct timespec now;
1.1       misho     984: 
                    985:        if (!root || !func)
                    986:                return NULL;
                    987: 
                    988:        /* get new task */
1.13      misho     989:        if (!(task = sched_useTask(root)))
1.4       misho     990:                return NULL;
1.1       misho     991: 
1.25      misho     992:        TASK_FUNC(task) = func;
1.5       misho     993:        TASK_TYPE(task) = taskTIMER;
                    994:        TASK_ROOT(task) = root;
1.1       misho     995: 
                    996:        TASK_ARG(task) = arg;
                    997: 
1.5       misho     998:        TASK_DATA(task) = opt_data;
                    999:        TASK_DATLEN(task) = opt_dlen;
                   1000: 
1.1       misho    1001:        /* calculate timeval structure */
1.5       misho    1002:        clock_gettime(CLOCK_MONOTONIC, &now);
                   1003:        now.tv_sec += ts.tv_sec;
                   1004:        now.tv_nsec += ts.tv_nsec;
                   1005:        if (now.tv_nsec >= 1000000000L) {
1.1       misho    1006:                now.tv_sec++;
1.5       misho    1007:                now.tv_nsec -= 1000000000L;
                   1008:        } else if (now.tv_nsec < 0) {
1.1       misho    1009:                now.tv_sec--;
1.5       misho    1010:                now.tv_nsec += 1000000000L;
1.1       misho    1011:        }
1.5       misho    1012:        TASK_TS(task) = now;
1.1       misho    1013: 
                   1014:        if (root->root_hooks.hook_add.timer)
                   1015:                ptr = root->root_hooks.hook_add.timer(task, NULL);
                   1016:        else
                   1017:                ptr = NULL;
                   1018: 
                   1019:        if (!ptr) {
1.25      misho    1020:                SCHED_QLOCK(root, taskTIMER);
1.1       misho    1021: #ifdef TIMER_WITHOUT_SORT
1.25      misho    1022:                TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
1.1       misho    1023: #else
1.9       misho    1024:                TAILQ_FOREACH_SAFE(t, &root->root_timer, task_node, tmp)
1.5       misho    1025:                        if (sched_timespeccmp(&TASK_TS(task), &TASK_TS(t), -) < 1)
1.1       misho    1026:                                break;
                   1027:                if (!t)
1.25      misho    1028:                        TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
1.1       misho    1029:                else
1.25      misho    1030:                        TAILQ_INSERT_BEFORE(t, task, task_node);
1.5       misho    1031: #endif
1.25      misho    1032:                SCHED_QUNLOCK(root, taskTIMER);
1.4       misho    1033:        } else
1.13      misho    1034:                task = sched_unuseTask(task);
1.1       misho    1035: 
                   1036:        return task;
                   1037: }
                   1038: 
                   1039: /*
                   1040:  * schedEvent() - Add EVENT task to scheduler queue
1.6       misho    1041:  *
1.1       misho    1042:  * @root = root task
                   1043:  * @func = task execution function
                   1044:  * @arg = 1st func argument
1.2       misho    1045:  * @val = additional func argument
1.5       misho    1046:  * @opt_data = Optional data
                   1047:  * @opt_dlen = Optional data length
1.1       misho    1048:  * return: NULL error or !=NULL new queued task
                   1049:  */
                   1050: sched_task_t *
1.5       misho    1051: schedEvent(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val, 
                   1052:                void *opt_data, size_t opt_dlen)
1.1       misho    1053: {
                   1054:        sched_task_t *task;
                   1055:        void *ptr;
                   1056: 
                   1057:        if (!root || !func)
                   1058:                return NULL;
                   1059: 
                   1060:        /* get new task */
1.13      misho    1061:        if (!(task = sched_useTask(root)))
1.4       misho    1062:                return NULL;
1.1       misho    1063: 
1.25      misho    1064:        TASK_FUNC(task) = func;
1.5       misho    1065:        TASK_TYPE(task) = taskEVENT;
                   1066:        TASK_ROOT(task) = root;
1.1       misho    1067: 
                   1068:        TASK_ARG(task) = arg;
1.2       misho    1069:        TASK_VAL(task) = val;
1.1       misho    1070: 
1.5       misho    1071:        TASK_DATA(task) = opt_data;
                   1072:        TASK_DATLEN(task) = opt_dlen;
                   1073: 
1.1       misho    1074:        if (root->root_hooks.hook_add.event)
                   1075:                ptr = root->root_hooks.hook_add.event(task, NULL);
                   1076:        else
                   1077:                ptr = NULL;
                   1078: 
1.25      misho    1079:        if (!ptr)
                   1080:                insert_task_to(task, &root->root_event);
                   1081:        else
1.13      misho    1082:                task = sched_unuseTask(task);
1.1       misho    1083: 
                   1084:        return task;
                   1085: }
                   1086: 
                   1087: 
                   1088: /*
1.12      misho    1089:  * schedTask() - Add regular task to scheduler queue
1.6       misho    1090:  *
1.1       misho    1091:  * @root = root task
                   1092:  * @func = task execution function
                   1093:  * @arg = 1st func argument
1.12      misho    1094:  * @prio = regular task priority, 0 is hi priority for regular tasks
1.5       misho    1095:  * @opt_data = Optional data
                   1096:  * @opt_dlen = Optional data length
1.1       misho    1097:  * return: NULL error or !=NULL new queued task
                   1098:  */
                   1099: sched_task_t *
1.12      misho    1100: schedTask(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long prio, 
1.5       misho    1101:                void *opt_data, size_t opt_dlen)
1.1       misho    1102: {
1.12      misho    1103:        sched_task_t *task, *tmp, *t = NULL;
1.1       misho    1104:        void *ptr;
                   1105: 
                   1106:        if (!root || !func)
                   1107:                return NULL;
                   1108: 
                   1109:        /* get new task */
1.13      misho    1110:        if (!(task = sched_useTask(root)))
1.4       misho    1111:                return NULL;
1.1       misho    1112: 
1.25      misho    1113:        TASK_FUNC(task) = func;
1.12      misho    1114:        TASK_TYPE(task) = taskTASK;
1.5       misho    1115:        TASK_ROOT(task) = root;
1.1       misho    1116: 
                   1117:        TASK_ARG(task) = arg;
1.12      misho    1118:        TASK_VAL(task) = prio;
1.1       misho    1119: 
1.5       misho    1120:        TASK_DATA(task) = opt_data;
                   1121:        TASK_DATLEN(task) = opt_dlen;
                   1122: 
1.12      misho    1123:        if (root->root_hooks.hook_add.task)
                   1124:                ptr = root->root_hooks.hook_add.task(task, NULL);
1.1       misho    1125:        else
                   1126:                ptr = NULL;
                   1127: 
1.5       misho    1128:        if (!ptr) {
1.25      misho    1129:                SCHED_QLOCK(root, taskTASK);
1.12      misho    1130:                TAILQ_FOREACH_SAFE(t, &root->root_task, task_node, tmp)
                   1131:                        if (TASK_VAL(task) < TASK_VAL(t))
                   1132:                                break;
                   1133:                if (!t)
1.25      misho    1134:                        TAILQ_INSERT_TAIL(&root->root_task, task, task_node);
1.12      misho    1135:                else
1.25      misho    1136:                        TAILQ_INSERT_BEFORE(t, task, task_node);
                   1137:                SCHED_QUNLOCK(root, taskTASK);
1.5       misho    1138:        } else
1.13      misho    1139:                task = sched_unuseTask(task);
1.1       misho    1140: 
                   1141:        return task;
                   1142: }
                   1143: 
                   1144: /*
1.10      misho    1145:  * schedSuspend() - Add Suspended task to scheduler queue
                   1146:  *
                   1147:  * @root = root task
                   1148:  * @func = task execution function
                   1149:  * @arg = 1st func argument
                   1150:  * @id = Trigger ID
                   1151:  * @opt_data = Optional data
                   1152:  * @opt_dlen = Optional data length
                   1153:  * return: NULL error or !=NULL new queued task
                   1154:  */
                   1155: sched_task_t *
                   1156: schedSuspend(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long id, 
                   1157:                void *opt_data, size_t opt_dlen)
                   1158: {
                   1159:        sched_task_t *task;
                   1160:        void *ptr;
                   1161: 
                   1162:        if (!root || !func)
                   1163:                return NULL;
                   1164: 
                   1165:        /* get new task */
1.13      misho    1166:        if (!(task = sched_useTask(root)))
1.10      misho    1167:                return NULL;
                   1168: 
1.25      misho    1169:        TASK_FUNC(task) = func;
1.10      misho    1170:        TASK_TYPE(task) = taskSUSPEND;
                   1171:        TASK_ROOT(task) = root;
                   1172: 
                   1173:        TASK_ARG(task) = arg;
                   1174:        TASK_VAL(task) = id;
                   1175: 
                   1176:        TASK_DATA(task) = opt_data;
                   1177:        TASK_DATLEN(task) = opt_dlen;
                   1178: 
                   1179:        if (root->root_hooks.hook_add.suspend)
                   1180:                ptr = root->root_hooks.hook_add.suspend(task, NULL);
                   1181:        else
                   1182:                ptr = NULL;
                   1183: 
1.25      misho    1184:        if (!ptr)
                   1185:                insert_task_to(task, &root->root_suspend);
                   1186:        else
1.13      misho    1187:                task = sched_unuseTask(task);
1.10      misho    1188: 
                   1189:        return task;
                   1190: }
                   1191: 
                   1192: /*
1.1       misho    1193:  * schedCallOnce() - Call once from scheduler
1.6       misho    1194:  *
1.1       misho    1195:  * @root = root task
                   1196:  * @func = task execution function
                   1197:  * @arg = 1st func argument
1.2       misho    1198:  * @val = additional func argument
1.5       misho    1199:  * @opt_data = Optional data
                   1200:  * @opt_dlen = Optional data length
1.2       misho    1201:  * return: return value from called func
1.1       misho    1202:  */
                   1203: sched_task_t *
1.5       misho    1204: schedCallOnce(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val, 
                   1205:                void *opt_data, size_t opt_dlen)
1.1       misho    1206: {
                   1207:        sched_task_t *task;
1.2       misho    1208:        void *ret;
1.1       misho    1209: 
                   1210:        if (!root || !func)
                   1211:                return NULL;
                   1212: 
                   1213:        /* get new task */
1.13      misho    1214:        if (!(task = sched_useTask(root)))
1.4       misho    1215:                return NULL;
1.1       misho    1216: 
1.25      misho    1217:        TASK_FUNC(task) = func;
1.5       misho    1218:        TASK_TYPE(task) = taskEVENT;
                   1219:        TASK_ROOT(task) = root;
1.1       misho    1220: 
                   1221:        TASK_ARG(task) = arg;
1.2       misho    1222:        TASK_VAL(task) = val;
1.1       misho    1223: 
1.5       misho    1224:        TASK_DATA(task) = opt_data;
                   1225:        TASK_DATLEN(task) = opt_dlen;
                   1226: 
1.2       misho    1227:        ret = schedCall(task);
1.1       misho    1228: 
1.13      misho    1229:        sched_unuseTask(task);
1.2       misho    1230:        return ret;
1.1       misho    1231: }
1.13      misho    1232: 
                   1233: /*
                   1234:  * schedThread() - Add thread task to scheduler queue
                   1235:  *
                   1236:  * @root = root task
                   1237:  * @func = task execution function
                   1238:  * @arg = 1st func argument
1.15      misho    1239:  * @ss = stack size
1.13      misho    1240:  * @opt_data = Optional data
                   1241:  * @opt_dlen = Optional data length
                   1242:  * return: NULL error or !=NULL new queued task
                   1243:  */
                   1244: sched_task_t *
1.21      misho    1245: schedThread(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, 
1.15      misho    1246:                size_t ss, void *opt_data, size_t opt_dlen)
1.13      misho    1247: {
                   1248: #ifndef HAVE_LIBPTHREAD
                   1249:        sched_SetErr(ENOTSUP, "Not supported thread tasks");
                   1250:        return NULL;
                   1251: #endif
                   1252:        sched_task_t *task;
                   1253:        pthread_attr_t attr;
1.25      misho    1254:        void *ptr;
1.13      misho    1255: 
                   1256:        if (!root || !func)
                   1257:                return NULL;
                   1258: 
                   1259:        /* get new task */
1.25      misho    1260:        if (!(task = sched_useTask(root)))
1.13      misho    1261:                return NULL;
                   1262: 
1.25      misho    1263:        TASK_FUNC(task) = func;
1.13      misho    1264:        TASK_TYPE(task) = taskTHREAD;
                   1265:        TASK_ROOT(task) = root;
                   1266: 
                   1267:        TASK_ARG(task) = arg;
                   1268: 
                   1269:        TASK_DATA(task) = opt_data;
                   1270:        TASK_DATLEN(task) = opt_dlen;
                   1271: 
                   1272:        pthread_attr_init(&attr);
1.25      misho    1273:        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1.15      misho    1274:        if (ss && (errno = pthread_attr_setstacksize(&attr, ss))) {
                   1275:                LOGERR;
                   1276:                pthread_attr_destroy(&attr);
                   1277:                return sched_unuseTask(task);
                   1278:        }
                   1279:        if ((errno = pthread_attr_getstacksize(&attr, &ss))) {
                   1280:                LOGERR;
                   1281:                pthread_attr_destroy(&attr);
                   1282:                return sched_unuseTask(task);
                   1283:        } else
1.21      misho    1284:                TASK_FLAG(task) = ss;
1.25      misho    1285: 
1.15      misho    1286: #ifdef SCHED_RR
                   1287:        pthread_attr_setschedpolicy(&attr, SCHED_RR);
                   1288: #else
                   1289:        pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
                   1290: #endif
1.21      misho    1291: 
1.25      misho    1292:        if (root->root_hooks.hook_add.thread)
                   1293:                ptr = root->root_hooks.hook_add.thread(task, &attr);
                   1294:        else
                   1295:                ptr = NULL;
                   1296: 
                   1297:        if (!ptr)
                   1298:                insert_task_to(task, &root->root_thread);
                   1299:        else
                   1300:                task = sched_unuseTask(task);
1.21      misho    1301: 
1.13      misho    1302:        pthread_attr_destroy(&attr);
                   1303:        return task;
                   1304: }
                   1305: 
1.17      misho    1306: /*
                   1307:  * schedRTC() - Add RTC task to scheduler queue
                   1308:  *
                   1309:  * @root = root task
                   1310:  * @func = task execution function
                   1311:  * @arg = 1st func argument
                   1312:  * @ts = timeout argument structure, minimum alarm timer resolution is 1msec!
                   1313:  * @opt_data = Optional RTC ID
1.18      misho    1314:  * @opt_dlen = Optional data length
1.17      misho    1315:  * return: NULL error or !=NULL new queued task
                   1316:  */
                   1317: sched_task_t *
                   1318: schedRTC(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts, 
                   1319:                void *opt_data, size_t opt_dlen)
                   1320: {
1.26      misho    1321: #if defined(HAVE_LIBRT) && defined(HAVE_TIMER_CREATE) && \
                   1322:        defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
1.17      misho    1323:        sched_task_t *task;
                   1324:        void *ptr;
                   1325: 
                   1326:        if (!root || !func)
                   1327:                return NULL;
                   1328: 
                   1329:        /* get new task */
                   1330:        if (!(task = sched_useTask(root)))
                   1331:                return NULL;
                   1332: 
1.25      misho    1333:        TASK_FUNC(task) = func;
1.17      misho    1334:        TASK_TYPE(task) = taskRTC;
                   1335:        TASK_ROOT(task) = root;
                   1336: 
                   1337:        TASK_ARG(task) = arg;
                   1338:        TASK_TS(task) = ts;
                   1339: 
                   1340:        TASK_DATA(task) = opt_data;
                   1341:        TASK_DATLEN(task) = opt_dlen;
                   1342: 
                   1343:        if (root->root_hooks.hook_add.rtc)
                   1344:                ptr = root->root_hooks.hook_add.rtc(task, NULL);
                   1345:        else
                   1346:                ptr = NULL;
                   1347: 
1.25      misho    1348:        if (!ptr)
                   1349:                insert_task_to(task, &root->root_rtc);
                   1350:        else
1.17      misho    1351:                task = sched_unuseTask(task);
                   1352: 
                   1353:        return task;
                   1354: #else
                   1355:        sched_SetErr(ENOTSUP, "Not supported realtime clock extensions");
                   1356:        return NULL;
                   1357: #endif
                   1358: }

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