![]() ![]() | ![]() |
epoll support fixed select/epoll and kqueue
1: /************************************************************************* 2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com> 3: * by Michael Pounov <misho@openbsd-bg.org> 4: * 5: * $Author: misho $ 6: * $Id: aitsched.c,v 1.25.2.6 2014/06/03 20:39:54 misho Exp $ 7: * 8: ************************************************************************** 9: The ELWIX and AITNET software is distributed under the following 10: terms: 11: 12: All of the documentation and software included in the ELWIX and AITNET 13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> 14: 15: Copyright 2004 - 2014 16: by Michael Pounov <misho@elwix.org>. All rights reserved. 17: 18: Redistribution and use in source and binary forms, with or without 19: modification, are permitted provided that the following conditions 20: are met: 21: 1. Redistributions of source code must retain the above copyright 22: notice, this list of conditions and the following disclaimer. 23: 2. Redistributions in binary form must reproduce the above copyright 24: notice, this list of conditions and the following disclaimer in the 25: documentation and/or other materials provided with the distribution. 26: 3. All advertising materials mentioning features or use of this software 27: must display the following acknowledgement: 28: This product includes software developed by Michael Pounov <misho@elwix.org> 29: ELWIX - Embedded LightWeight unIX and its contributors. 30: 4. Neither the name of AITNET nor the names of its contributors 31: may be used to endorse or promote products derived from this software 32: without specific prior written permission. 33: 34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND 35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44: SUCH DAMAGE. 45: */ 46: #include "global.h" 47: #include "hooks.h" 48: 49: 50: #pragma GCC visibility push(hidden) 51: 52: int sched_Errno; 53: char sched_Error[STRSIZ]; 54: 55: #pragma GCC visibility pop 56: 57: 58: // sched_GetErrno() Get error code of last operation 59: int 60: sched_GetErrno() 61: { 62: return sched_Errno; 63: } 64: 65: // sched_GetError() Get error text of last operation 66: const char * 67: sched_GetError() 68: { 69: return sched_Error; 70: } 71: 72: // sched_SetErr() Set error to variables for internal use!!! 73: void 74: sched_SetErr(int eno, char *estr, ...) 75: { 76: va_list lst; 77: 78: sched_Errno = eno; 79: memset(sched_Error, 0, sizeof sched_Error); 80: va_start(lst, estr); 81: vsnprintf(sched_Error, sizeof sched_Error, estr, lst); 82: va_end(lst); 83: } 84: 85: 86: /* string support functions directly imported from OpenBSD */ 87: 88: #ifndef HAVE_STRLCAT 89: /* 90: * Appends src to string dst of size siz (unlike strncat, siz is the 91: * full size of dst, not space left). At most siz-1 characters 92: * will be copied. Always NUL terminates (unless siz <= strlen(dst)). 93: * Returns strlen(src) + MIN(siz, strlen(initial dst)). 94: * If retval >= siz, truncation occurred. 95: */ 96: size_t 97: strlcat(char * __restrict dst, const char * __restrict src, size_t siz) 98: { 99: char *d = dst; 100: const char *s = src; 101: size_t n = siz; 102: size_t dlen; 103: 104: /* Find the end of dst and adjust bytes left but don't go past end */ 105: while (n-- != 0 && *d != '\0') 106: d++; 107: dlen = d - dst; 108: n = siz - dlen; 109: 110: if (n == 0) 111: return(dlen + strlen(s)); 112: while (*s != '\0') { 113: if (n != 1) { 114: *d++ = *s; 115: n--; 116: } 117: s++; 118: } 119: *d = '\0'; 120: 121: return(dlen + (s - src)); /* count does not include NUL */ 122: } 123: #endif 124: #ifndef HAVE_STRLCPY 125: /* 126: * Copy src to string dst of size siz. At most siz-1 characters 127: * will be copied. Always NUL terminates (unless siz == 0). 128: * Returns strlen(src); if retval >= siz, truncation occurred. 129: */ 130: size_t 131: strlcpy(char * __restrict dst, const char * __restrict src, size_t siz) 132: { 133: char *d = dst; 134: const char *s = src; 135: size_t n = siz; 136: 137: /* Copy as many bytes as will fit */ 138: if (n != 0) { 139: while (--n != 0) { 140: if ((*d++ = *s++) == '\0') 141: break; 142: } 143: } 144: 145: /* Not enough room in dst, add NUL and traverse rest of src */ 146: if (n == 0) { 147: if (siz != 0) 148: *d = '\0'; /* NUL-terminate dst */ 149: while (*s++) 150: ; 151: } 152: 153: return(s - src - 1); /* count does not include NUL */ 154: } 155: #endif 156: 157: 158: /* Init and prepare scheduler functions */ 159: 160: /* 161: * schedRegisterHooks() - Register IO handles and bind tasks to it 162: * 163: * @root = root task 164: * return: -1 error or 0 ok 165: */ 166: int 167: schedRegisterHooks(sched_root_task_t * __restrict root) 168: { 169: assert(root); 170: 171: if (root->root_hooks.hook_root.fini) 172: root->root_hooks.hook_root.fini(root, NULL); 173: memset(&root->root_hooks, 0, sizeof root->root_hooks); 174: 175: root->root_hooks.hook_add.read = sched_hook_read; 176: root->root_hooks.hook_add.write = sched_hook_write; 177: #if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE) 178: root->root_hooks.hook_add.rtc = sched_hook_rtc; 179: #endif 180: #if SUP_ENABLE == KQ_SUPPORT 181: root->root_hooks.hook_add.alarm = sched_hook_alarm; 182: root->root_hooks.hook_add.node = sched_hook_node; 183: root->root_hooks.hook_add.proc = sched_hook_proc; 184: root->root_hooks.hook_add.signal = sched_hook_signal; 185: #ifdef EVFILT_USER 186: root->root_hooks.hook_add.user = sched_hook_user; 187: #endif 188: #endif /* KQ_SUPPORT */ 189: #ifdef HAVE_LIBPTHREAD 190: root->root_hooks.hook_add.thread = sched_hook_thread; 191: #endif 192: 193: root->root_hooks.hook_exec.cancel = sched_hook_cancel; 194: root->root_hooks.hook_exec.fetch = sched_hook_fetch; 195: root->root_hooks.hook_exec.exception = sched_hook_exception; 196: 197: root->root_hooks.hook_root.init = sched_hook_init; 198: root->root_hooks.hook_root.fini = sched_hook_fini; 199: return 0; 200: } 201: 202: /* 203: * schedInit() - Init scheduler 204: * 205: * @data = optional data if !=NULL 206: * @datlen = data len if data is set 207: * return: allocated root task if ok or NULL error 208: */ 209: sched_root_task_t * 210: schedInit(void ** __restrict data, size_t datlen) 211: { 212: sched_root_task_t *root = NULL; 213: int (*func)(sched_root_task_t *); 214: #ifdef HAVE_LIBPTHREAD 215: register int i; 216: #endif 217: 218: root = malloc(sizeof(sched_root_task_t)); 219: if (!root) { 220: LOGERR; 221: } else { 222: memset(root, 0, sizeof(sched_root_task_t)); 223: 224: /* set default maximum regular task hit misses */ 225: root->root_miss = MAX_TASK_MISS; 226: 227: /* INFINIT polling period by default */ 228: sched_timespecinf(&root->root_poll); 229: 230: #ifdef HAVE_LIBPTHREAD 231: for (i = 0; i < taskMAX; i++) 232: if ((errno = pthread_mutex_init(&root->root_mtx[i], NULL))) { 233: LOGERR; 234: while (i) 235: pthread_mutex_destroy(&root->root_mtx[--i]); 236: free(root); 237: return NULL; 238: } 239: 240: for (i = 0; i < taskMAX; i++) 241: pthread_mutex_lock(&root->root_mtx[i]); 242: #endif 243: 244: TAILQ_INIT(&root->root_read); 245: TAILQ_INIT(&root->root_write); 246: TAILQ_INIT(&root->root_timer); 247: TAILQ_INIT(&root->root_alarm); 248: TAILQ_INIT(&root->root_rtc); 249: TAILQ_INIT(&root->root_node); 250: TAILQ_INIT(&root->root_proc); 251: TAILQ_INIT(&root->root_signal); 252: TAILQ_INIT(&root->root_aio); 253: TAILQ_INIT(&root->root_lio); 254: TAILQ_INIT(&root->root_user); 255: TAILQ_INIT(&root->root_event); 256: TAILQ_INIT(&root->root_task); 257: TAILQ_INIT(&root->root_suspend); 258: TAILQ_INIT(&root->root_ready); 259: TAILQ_INIT(&root->root_unuse); 260: TAILQ_INIT(&root->root_thread); 261: 262: #ifdef HAVE_LIBPTHREAD 263: for (i = 0; i < taskMAX; i++) 264: pthread_mutex_unlock(&root->root_mtx[i]); 265: #endif 266: 267: if (data && *data) { 268: if (datlen) { 269: root->root_data.iov_base = *data; 270: root->root_data.iov_len = datlen; 271: } else { /* if datlen == 0, switch to callbacks init mode */ 272: /* little hack :) for correct initialization of scheduler */ 273: func = (int(*)(sched_root_task_t*)) data; 274: func(root); 275: } 276: } 277: 278: if (root->root_hooks.hook_root.init) 279: root->root_hooks.hook_root.init(root, NULL); 280: } 281: 282: return root; 283: } 284: 285: /* 286: * schedEnd() - End scheduler & free all resources 287: * 288: * @root = root task 289: * return: -1 error or 0 ok 290: */ 291: int 292: schedEnd(sched_root_task_t ** __restrict root) 293: { 294: sched_task_t *task, *tmp; 295: #ifdef HAVE_LIBPTHREAD 296: register int i; 297: #endif 298: 299: if (!root || !*root) 300: return -1; 301: 302: #if 0 303: TAILQ_FOREACH_SAFE(task, &(*root)->root_read, task_node, tmp) 304: printf("read=%p\n", task); 305: TAILQ_FOREACH_SAFE(task, &(*root)->root_write, task_node, tmp) 306: printf("write=%p\n", task); 307: TAILQ_FOREACH_SAFE(task, &(*root)->root_timer, task_node, tmp) 308: printf("timer=%p\n", task); 309: TAILQ_FOREACH_SAFE(task, &(*root)->root_alarm, task_node, tmp) 310: printf("alarm=%p\n", task); 311: TAILQ_FOREACH_SAFE(task, &(*root)->root_rtc, task_node, tmp) 312: printf("rtc=%p\n", task); 313: TAILQ_FOREACH_SAFE(task, &(*root)->root_node, task_node, tmp) 314: printf("node=%p\n", task); 315: TAILQ_FOREACH_SAFE(task, &(*root)->root_proc, task_node, tmp) 316: printf("proc=%p\n", task); 317: TAILQ_FOREACH_SAFE(task, &(*root)->root_signal, task_node, tmp) 318: printf("signal=%p\n", task); 319: TAILQ_FOREACH_SAFE(task, &(*root)->root_aio, task_node, tmp) 320: printf("aio=%p\n", task); 321: TAILQ_FOREACH_SAFE(task, &(*root)->root_lio, task_node, tmp) 322: printf("lio=%p\n", task); 323: TAILQ_FOREACH_SAFE(task, &(*root)->root_user, task_node, tmp) 324: printf("user=%p\n", task); 325: TAILQ_FOREACH_SAFE(task, &(*root)->root_event, task_node, tmp) 326: printf("event=%p\n", task); 327: TAILQ_FOREACH_SAFE(task, &(*root)->root_suspend, task_node, tmp) 328: printf("suspend=%p\n", task); 329: TAILQ_FOREACH_SAFE(task, &(*root)->root_ready, task_node, tmp) 330: printf("ready=%p\n", task); 331: TAILQ_FOREACH_SAFE(task, &(*root)->root_thread, task_node, tmp) 332: printf("thread=%p\n", task); 333: TAILQ_FOREACH_SAFE(task, &(*root)->root_task, task_node, tmp) 334: printf("task=%p\n", task); 335: TAILQ_FOREACH_SAFE(task, &(*root)->root_unuse, task_node, tmp) 336: printf("unuse=%p\n", task); 337: fflush(stdout); 338: #endif 339: 340: TAILQ_FOREACH_SAFE(task, &(*root)->root_read, task_node, tmp) 341: schedCancel(task); 342: TAILQ_FOREACH_SAFE(task, &(*root)->root_write, task_node, tmp) 343: schedCancel(task); 344: TAILQ_FOREACH_SAFE(task, &(*root)->root_timer, task_node, tmp) 345: schedCancel(task); 346: TAILQ_FOREACH_SAFE(task, &(*root)->root_alarm, task_node, tmp) 347: schedCancel(task); 348: TAILQ_FOREACH_SAFE(task, &(*root)->root_rtc, task_node, tmp) 349: schedCancel(task); 350: TAILQ_FOREACH_SAFE(task, &(*root)->root_node, task_node, tmp) 351: schedCancel(task); 352: TAILQ_FOREACH_SAFE(task, &(*root)->root_proc, task_node, tmp) 353: schedCancel(task); 354: TAILQ_FOREACH_SAFE(task, &(*root)->root_signal, task_node, tmp) 355: schedCancel(task); 356: TAILQ_FOREACH_SAFE(task, &(*root)->root_aio, task_node, tmp) 357: schedCancel(task); 358: TAILQ_FOREACH_SAFE(task, &(*root)->root_lio, task_node, tmp) 359: schedCancel(task); 360: TAILQ_FOREACH_SAFE(task, &(*root)->root_user, task_node, tmp) 361: schedCancel(task); 362: TAILQ_FOREACH_SAFE(task, &(*root)->root_event, task_node, tmp) 363: schedCancel(task); 364: TAILQ_FOREACH_SAFE(task, &(*root)->root_suspend, task_node, tmp) 365: schedCancel(task); 366: TAILQ_FOREACH_SAFE(task, &(*root)->root_ready, task_node, tmp) 367: schedCancel(task); 368: TAILQ_FOREACH_SAFE(task, &(*root)->root_thread, task_node, tmp) 369: schedCancel(task); 370: TAILQ_FOREACH_SAFE(task, &(*root)->root_task, task_node, tmp) 371: schedCancel(task); 372: 373: SCHED_QLOCK((*root), taskUNUSE); 374: TAILQ_FOREACH_SAFE(task, &(*root)->root_unuse, task_node, tmp) { 375: TAILQ_REMOVE(&(*root)->root_unuse, task, task_node); 376: free(task); 377: } 378: SCHED_QUNLOCK((*root), taskUNUSE); 379: 380: if ((*root)->root_hooks.hook_root.fini) 381: (*root)->root_hooks.hook_root.fini(*root, NULL); 382: 383: #ifdef HAVE_LIBPTHREAD 384: for (i = 0; i < taskMAX; i++) { 385: SCHED_QUNLOCK(*root, i); 386: pthread_mutex_destroy(&(*root)->root_mtx[i]); 387: } 388: #endif 389: 390: free(*root); 391: *root = NULL; 392: return 0; 393: } 394: 395: /* 396: * schedCall() - Call task execution function 397: * 398: * @task = current task 399: * return: !=NULL error or =NULL ok 400: */ 401: void * 402: schedCall(sched_task_t * __restrict task) 403: { 404: void *ptr = (void*) -1; 405: 406: if (!task) 407: return ptr; 408: 409: if (!TASK_ISLOCKED(task)) 410: TASK_LOCK(task); 411: 412: ptr = task->task_func(task); 413: 414: TASK_UNLOCK(task); 415: return ptr; 416: } 417: 418: /* 419: * schedFetch() - Fetch ready task 420: * 421: * @root = root task 422: * return: =NULL error or !=NULL ready task 423: */ 424: void * 425: schedFetch(sched_root_task_t * __restrict root) 426: { 427: void *ptr; 428: 429: if (!root) 430: return NULL; 431: 432: if (root->root_hooks.hook_exec.fetch) 433: ptr = root->root_hooks.hook_exec.fetch(root, NULL); 434: else 435: ptr = NULL; 436: 437: return ptr; 438: } 439: 440: /* 441: * schedTrigger() - Triggering USER task 442: * 443: * @task = task 444: * return: -1 error or 0 ok 445: */ 446: int 447: schedTrigger(sched_task_t * __restrict task) 448: { 449: #if SUP_ENABLE != KQ_SUPPORT 450: sched_SetErr(ENOTSUP, "disabled kqueue support"); 451: return -1; 452: #else 453: #ifndef EVFILT_USER 454: sched_SetErr(ENOTSUP, "Not supported kevent() filter"); 455: return -1; 456: #else 457: struct kevent chg[1]; 458: struct timespec timeout = { 0, 0 }; 459: 460: if (!task || !TASK_ROOT(task)) 461: return -1; 462: 463: #ifdef __NetBSD__ 464: EV_SET(chg, TASK_VAL(task), EVFILT_USER, 0, NOTE_TRIGGER, 0, (intptr_t) TASK_VAL(task)); 465: #else 466: EV_SET(chg, TASK_VAL(task), EVFILT_USER, 0, NOTE_TRIGGER, 0, (void*) TASK_VAL(task)); 467: #endif 468: if (kevent(TASK_ROOT(task)->root_kq, chg, 1, NULL, 0, &timeout) == -1) { 469: LOGERR; 470: return -1; 471: } 472: 473: return 0; 474: #endif 475: #endif /* KQ_SUPPORT */ 476: } 477: 478: /* 479: * schedQuery() - Query task in scheduler 480: * 481: * @task = task 482: * return: -1 error, 0 found and 1 not found 483: */ 484: int 485: schedQuery(sched_task_t * __restrict task) 486: { 487: sched_queue_t *queue; 488: sched_task_t *t; 489: 490: if (!task || !TASK_ROOT(task)) 491: return -1; /* error */ 492: 493: switch (TASK_TYPE(task)) { 494: case taskREAD: 495: queue = &TASK_ROOT(task)->root_read; 496: break; 497: case taskWRITE: 498: queue = &TASK_ROOT(task)->root_write; 499: break; 500: case taskTIMER: 501: queue = &TASK_ROOT(task)->root_timer; 502: break; 503: case taskALARM: 504: queue = &TASK_ROOT(task)->root_alarm; 505: break; 506: case taskRTC: 507: queue = &TASK_ROOT(task)->root_rtc; 508: break; 509: case taskNODE: 510: queue = &TASK_ROOT(task)->root_node; 511: break; 512: case taskPROC: 513: queue = &TASK_ROOT(task)->root_proc; 514: break; 515: case taskSIGNAL: 516: queue = &TASK_ROOT(task)->root_signal; 517: break; 518: case taskAIO: 519: queue = &TASK_ROOT(task)->root_aio; 520: break; 521: case taskLIO: 522: queue = &TASK_ROOT(task)->root_lio; 523: break; 524: case taskUSER: 525: queue = &TASK_ROOT(task)->root_user; 526: break; 527: case taskEVENT: 528: queue = &TASK_ROOT(task)->root_event; 529: break; 530: case taskTASK: 531: queue = &TASK_ROOT(task)->root_task; 532: break; 533: case taskSUSPEND: 534: queue = &TASK_ROOT(task)->root_suspend; 535: break; 536: case taskREADY: 537: queue = &TASK_ROOT(task)->root_ready; 538: break; 539: case taskTHREAD: 540: queue = &TASK_ROOT(task)->root_thread; 541: break; 542: default: 543: return 1; /* not in queue */ 544: } 545: if (queue) 546: TAILQ_FOREACH(t, queue, task_node) 547: if (TASK_ID(t) == TASK_ID(task)) 548: return 0; /* found */ 549: 550: return 1; /* not in queue */ 551: } 552: 553: /* 554: * schedQueryby() - Query task in scheduler by criteria 555: * 556: * @root = root task 557: * @type = query from queue type, if =taskMAX query same task from all queues 558: * @criteria = find task by criteria 559: * [ CRITERIA_ANY|CRITERIA_CALL|CRITERIA_ARG|CRITERIA_FD|CRITERIA_VAL| 560: * CRITERIA_ID|CRITERIA_TS|CRITERIA_DATA|CRITERIA_DATLEN ] 561: * @param = search parameter 562: * return: -1 error, 0 found or 1 not found 563: */ 564: int 565: schedQueryby(sched_root_task_t * __restrict root, sched_task_type_t type, 566: u_char criteria, void *param) 567: { 568: sched_task_t *task; 569: sched_queue_t *queue; 570: register int flg = 0; 571: 572: if (!root) 573: return -1; 574: /* if type == taskMAX check in all queues */ 575: if (type == taskMAX) { 576: if ((flg = schedQueryby(root, taskREAD, criteria, param)) < 1) 577: return flg; 578: if ((flg = schedQueryby(root, taskWRITE, criteria, param)) < 1) 579: return flg; 580: if ((flg = schedQueryby(root, taskTIMER, criteria, param)) < 1) 581: return flg; 582: if ((flg = schedQueryby(root, taskALARM, criteria, param)) < 1) 583: return flg; 584: if ((flg = schedQueryby(root, taskRTC, criteria, param)) < 1) 585: return flg; 586: if ((flg = schedQueryby(root, taskNODE, criteria, param)) < 1) 587: return flg; 588: if ((flg = schedQueryby(root, taskPROC, criteria, param)) < 1) 589: return flg; 590: if ((flg = schedQueryby(root, taskSIGNAL, criteria, param)) < 1) 591: return flg; 592: if ((flg = schedQueryby(root, taskAIO, criteria, param)) < 1) 593: return flg; 594: if ((flg = schedQueryby(root, taskLIO, criteria, param)) < 1) 595: return flg; 596: if ((flg = schedQueryby(root, taskUSER, criteria, param)) < 1) 597: return flg; 598: if ((flg = schedQueryby(root, taskEVENT, criteria, param)) < 1) 599: return flg; 600: if ((flg = schedQueryby(root, taskTASK, criteria, param)) < 1) 601: return flg; 602: if ((flg = schedQueryby(root, taskSUSPEND, criteria, param)) < 1) 603: return flg; 604: if ((flg = schedQueryby(root, taskREADY, criteria, param)) < 1) 605: return flg; 606: if ((flg = schedQueryby(root, taskTHREAD, criteria, param)) < 1) 607: return flg; 608: return 1; /* not found */ 609: } 610: /* choosen queue */ 611: switch (type) { 612: case taskREAD: 613: queue = &root->root_read; 614: break; 615: case taskWRITE: 616: queue = &root->root_write; 617: break; 618: case taskTIMER: 619: queue = &root->root_timer; 620: break; 621: case taskALARM: 622: queue = &root->root_alarm; 623: break; 624: case taskRTC: 625: queue = &root->root_rtc; 626: break; 627: case taskNODE: 628: queue = &root->root_node; 629: break; 630: case taskPROC: 631: queue = &root->root_proc; 632: break; 633: case taskSIGNAL: 634: queue = &root->root_signal; 635: break; 636: case taskAIO: 637: queue = &root->root_aio; 638: break; 639: case taskLIO: 640: queue = &root->root_lio; 641: break; 642: case taskUSER: 643: queue = &root->root_user; 644: break; 645: case taskEVENT: 646: queue = &root->root_event; 647: break; 648: case taskTASK: 649: queue = &root->root_task; 650: break; 651: case taskSUSPEND: 652: queue = &root->root_suspend; 653: break; 654: case taskREADY: 655: queue = &root->root_ready; 656: break; 657: case taskTHREAD: 658: queue = &root->root_thread; 659: break; 660: default: 661: return 1; /* not found */ 662: } 663: 664: TAILQ_FOREACH(task, queue, task_node) { 665: switch (criteria) { 666: case CRITERIA_ANY: 667: return 0; /* found */ 668: case CRITERIA_CALL: 669: if (TASK_FUNC(task) == (sched_task_func_t) param) 670: return 0; /* found */ 671: break; 672: case CRITERIA_ARG: 673: if (TASK_ARG(task) == param) 674: return 0; /* found */ 675: break; 676: case CRITERIA_FD: 677: if (TASK_FD(task) == (intptr_t) param) 678: return 0; /* found */ 679: break; 680: case CRITERIA_ID: 681: case CRITERIA_VAL: 682: if (TASK_VAL(task) == (u_long) param) 683: return 0; /* found */ 684: break; 685: case CRITERIA_TS: 686: if (!sched_timespeccmp(&TASK_TS(task), 687: (struct timespec*) param, -)) 688: return 0; /* found */ 689: break; 690: case CRITERIA_DATA: 691: if (TASK_DATA(task) == param) 692: return 0; /* found */ 693: break; 694: case CRITERIA_DATLEN: 695: if (TASK_DATLEN(task) == (size_t) param) 696: return 0; /* found */ 697: break; 698: default: 699: sched_SetErr(EINVAL, "Invalid parameter criteria %d", 700: criteria); 701: return 1; /* not found */ 702: } 703: } 704: 705: return 1; /* not found */ 706: } 707: 708: /* 709: * schedCancel() - Cancel task from scheduler 710: * 711: * @task = task 712: * return: -1 error or 0 ok 713: */ 714: int 715: schedCancel(sched_task_t * __restrict task) 716: { 717: sched_queue_t *queue; 718: 719: if (!task || !TASK_ROOT(task)) 720: return -1; 721: 722: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel) 723: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel(task, NULL)) 724: return -1; 725: 726: switch (TASK_TYPE(task)) { 727: case taskREAD: 728: queue = &TASK_ROOT(task)->root_read; 729: break; 730: case taskWRITE: 731: queue = &TASK_ROOT(task)->root_write; 732: break; 733: case taskTIMER: 734: queue = &TASK_ROOT(task)->root_timer; 735: break; 736: case taskALARM: 737: queue = &TASK_ROOT(task)->root_alarm; 738: break; 739: case taskRTC: 740: queue = &TASK_ROOT(task)->root_rtc; 741: break; 742: case taskNODE: 743: queue = &TASK_ROOT(task)->root_node; 744: break; 745: case taskPROC: 746: queue = &TASK_ROOT(task)->root_proc; 747: break; 748: case taskSIGNAL: 749: queue = &TASK_ROOT(task)->root_signal; 750: break; 751: case taskAIO: 752: queue = &TASK_ROOT(task)->root_aio; 753: break; 754: case taskLIO: 755: queue = &TASK_ROOT(task)->root_lio; 756: break; 757: case taskUSER: 758: queue = &TASK_ROOT(task)->root_user; 759: break; 760: case taskEVENT: 761: queue = &TASK_ROOT(task)->root_event; 762: break; 763: case taskTASK: 764: queue = &TASK_ROOT(task)->root_task; 765: break; 766: case taskSUSPEND: 767: queue = &TASK_ROOT(task)->root_suspend; 768: break; 769: case taskREADY: 770: queue = &TASK_ROOT(task)->root_ready; 771: break; 772: case taskTHREAD: 773: queue = &TASK_ROOT(task)->root_thread; 774: break; 775: default: 776: queue = NULL; 777: } 778: if (queue) 779: remove_task_from(task, queue); 780: if (TASK_TYPE(task) != taskUNUSE) 781: sched_unuseTask(task); 782: 783: return 0; 784: } 785: 786: /* 787: * schedCancelby() - Cancel task from scheduler by criteria 788: * 789: * @root = root task 790: * @type = cancel from queue type, if =taskMAX cancel same task from all queues 791: * @criteria = find task by criteria 792: * [ CRITERIA_ANY|CRITERIA_CALL|CRITERIA_ARG|CRITERIA_FD|CRITERIA_VAL| 793: * CRITERIA_ID|CRITERIA_TS|CRITERIA_DATA|CRITERIA_DATLEN ] 794: * @param = search parameter 795: * @hook = custom cleanup hook function, may be NULL 796: * return: -1 error, -2 error in sub-stage cancel execution, -3 error from custom hook or 0 ok 797: */ 798: int 799: schedCancelby(sched_root_task_t * __restrict root, sched_task_type_t type, 800: u_char criteria, void *param, sched_hook_func_t hook) 801: { 802: sched_task_t *task, *tmp; 803: sched_queue_t *queue; 804: register int flg = 0; 805: 806: if (!root) 807: return -1; 808: /* if type == taskMAX check in all queues */ 809: if (type == taskMAX) { 810: if (schedCancelby(root, taskREAD, criteria, param, hook)) 811: return -2; 812: if (schedCancelby(root, taskWRITE, criteria, param, hook)) 813: return -2; 814: if (schedCancelby(root, taskTIMER, criteria, param, hook)) 815: return -2; 816: if (schedCancelby(root, taskALARM, criteria, param, hook)) 817: return -2; 818: if (schedCancelby(root, taskRTC, criteria, param, hook)) 819: return -2; 820: if (schedCancelby(root, taskNODE, criteria, param, hook)) 821: return -2; 822: if (schedCancelby(root, taskPROC, criteria, param, hook)) 823: return -2; 824: if (schedCancelby(root, taskSIGNAL, criteria, param, hook)) 825: return -2; 826: if (schedCancelby(root, taskAIO, criteria, param, hook)) 827: return -2; 828: if (schedCancelby(root, taskLIO, criteria, param, hook)) 829: return -2; 830: if (schedCancelby(root, taskUSER, criteria, param, hook)) 831: return -2; 832: if (schedCancelby(root, taskEVENT, criteria, param, hook)) 833: return -2; 834: if (schedCancelby(root, taskTASK, criteria, param, hook)) 835: return -2; 836: if (schedCancelby(root, taskSUSPEND, criteria, param, hook)) 837: return -2; 838: if (schedCancelby(root, taskREADY, criteria, param, hook)) 839: return -2; 840: if (schedCancelby(root, taskTHREAD, criteria, param, hook)) 841: return -2; 842: return 0; 843: } 844: /* choosen queue */ 845: switch (type) { 846: case taskREAD: 847: queue = &root->root_read; 848: break; 849: case taskWRITE: 850: queue = &root->root_write; 851: break; 852: case taskTIMER: 853: queue = &root->root_timer; 854: break; 855: case taskALARM: 856: queue = &root->root_alarm; 857: break; 858: case taskRTC: 859: queue = &root->root_rtc; 860: break; 861: case taskNODE: 862: queue = &root->root_node; 863: break; 864: case taskPROC: 865: queue = &root->root_proc; 866: break; 867: case taskSIGNAL: 868: queue = &root->root_signal; 869: break; 870: case taskAIO: 871: queue = &root->root_aio; 872: break; 873: case taskLIO: 874: queue = &root->root_lio; 875: break; 876: case taskUSER: 877: queue = &root->root_user; 878: break; 879: case taskEVENT: 880: queue = &root->root_event; 881: break; 882: case taskTASK: 883: queue = &root->root_task; 884: break; 885: case taskSUSPEND: 886: queue = &root->root_suspend; 887: break; 888: case taskREADY: 889: queue = &root->root_ready; 890: break; 891: case taskTHREAD: 892: queue = &root->root_thread; 893: break; 894: default: 895: return 0; 896: } 897: 898: SCHED_QLOCK(root, type); 899: TAILQ_FOREACH_SAFE(task, queue, task_node, tmp) { 900: flg ^= flg; 901: switch (criteria) { 902: case CRITERIA_ANY: 903: flg = 1; 904: break; 905: case CRITERIA_CALL: 906: if (TASK_FUNC(task) == (sched_task_func_t) param) 907: flg = 1; 908: break; 909: case CRITERIA_ARG: 910: if (TASK_ARG(task) == param) 911: flg = 1; 912: break; 913: case CRITERIA_FD: 914: if (TASK_FD(task) == (intptr_t) param) 915: flg = 1; 916: break; 917: case CRITERIA_ID: 918: case CRITERIA_VAL: 919: if (TASK_VAL(task) == (u_long) param) 920: flg = 1; 921: break; 922: case CRITERIA_TS: 923: if (!sched_timespeccmp(&TASK_TS(task), (struct timespec*) param, -)) 924: flg = 1; 925: break; 926: case CRITERIA_DATA: 927: if (TASK_DATA(task) == param) 928: flg = 1; 929: break; 930: case CRITERIA_DATLEN: 931: if (TASK_DATLEN(task) == (size_t) param) 932: flg = 1; 933: break; 934: default: 935: sched_SetErr(EINVAL, "Invalid parameter criteria %d", criteria); 936: flg = -1; 937: } 938: if (flg < 0) /* error */ 939: break; 940: /* cancel choosen task */ 941: if (flg > 0) { 942: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel) 943: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel(task, NULL)) { 944: flg = -1; 945: break; 946: } 947: /* custom hook */ 948: if (hook) 949: if (hook(task, NULL)) { 950: flg = -3; 951: break; 952: } 953: 954: TAILQ_REMOVE(queue, task, task_node); 955: if (TASK_TYPE(task) != taskUNUSE) 956: sched_unuseTask(task); 957: 958: flg ^= flg; /* ok */ 959: } 960: } 961: SCHED_QUNLOCK(root, type); 962: 963: return flg; 964: } 965: 966: /* 967: * schedRun() - Scheduler *run loop* 968: * 969: * @root = root task 970: * @killState = kill condition variable, if !=0 stop scheduler loop 971: * return: -1 error or 0 ok 972: */ 973: int 974: schedRun(sched_root_task_t *root, volatile intptr_t * __restrict killState) 975: { 976: sched_task_t *task; 977: 978: if (!root) 979: return -1; 980: 981: if (root->root_hooks.hook_exec.run) 982: if (root->root_hooks.hook_exec.run(root, NULL)) 983: return -1; 984: 985: if (killState) { 986: if (root->root_hooks.hook_exec.condition) 987: /* condition scheduler loop */ 988: while (root && root->root_hooks.hook_exec.fetch && 989: root->root_hooks.hook_exec.condition && 990: root->root_hooks.hook_exec.condition(root, (void*) killState)) { 991: if ((task = root->root_hooks.hook_exec.fetch(root, NULL))) 992: root->root_ret = schedCall(task); 993: } 994: else 995: /* trigger scheduler loop */ 996: while (!*killState && root && root->root_hooks.hook_exec.fetch) { 997: if ((task = root->root_hooks.hook_exec.fetch(root, NULL))) 998: root->root_ret = schedCall(task); 999: } 1000: } else 1001: /* infinite scheduler loop */ 1002: while (root && root->root_hooks.hook_exec.fetch) 1003: if ((task = root->root_hooks.hook_exec.fetch(root, NULL))) 1004: root->root_ret = schedCall(task); 1005: 1006: return 0; 1007: } 1008: 1009: /* 1010: * schedPolling() - Polling timeout period if no timer task is present 1011: * 1012: * @root = root task 1013: * @ts = timeout polling period, if ==NULL INFINIT timeout 1014: * @tsold = old timeout polling if !=NULL 1015: * return: -1 error or 0 ok 1016: */ 1017: int 1018: schedPolling(sched_root_task_t * __restrict root, struct timespec * __restrict ts, 1019: struct timespec * __restrict tsold) 1020: { 1021: if (!root) 1022: return -1; 1023: 1024: if (tsold) 1025: *tsold = root->root_poll; 1026: 1027: if (!ts) 1028: sched_timespecinf(&root->root_poll); 1029: else 1030: root->root_poll = *ts; 1031: 1032: return 0; 1033: } 1034: 1035: /* 1036: * schedTermCondition() - Activate hook for scheduler condition kill 1037: * 1038: * @root = root task 1039: * @condValue = condition value, kill schedRun() if condValue == killState 1040: * return: -1 error or 0 ok 1041: */ 1042: int 1043: schedTermCondition(sched_root_task_t * __restrict root, intptr_t * __restrict condValue) 1044: { 1045: if (!root && !condValue) 1046: return -1; 1047: 1048: *root->root_cond = *condValue; 1049: root->root_hooks.hook_exec.condition = sched_hook_condition; 1050: return 0; 1051: } 1052: 1053: /* 1054: * schedResumeby() - Resume suspended task 1055: * 1056: * @root = root task 1057: * @criteria = find task by criteria 1058: * [CRITERIA_ANY|CRITERIA_ID|CRITERIA_VAL|CRITERIA_DATA] 1059: * @param = search parameter (sched_task_t *task| unsigned long id) 1060: * return: -1 error or 0 resumed ok 1061: */ 1062: int 1063: schedResumeby(sched_root_task_t * __restrict root, u_char criteria, void *param) 1064: { 1065: sched_task_t *task, *tmp; 1066: register int flg = 0; 1067: 1068: if (!root) 1069: return -1; 1070: 1071: SCHED_QLOCK(root, taskSUSPEND); 1072: TAILQ_FOREACH_SAFE(task, &root->root_suspend, task_node, tmp) { 1073: flg ^= flg; 1074: switch (criteria) { 1075: case CRITERIA_ANY: 1076: flg = 1; 1077: break; 1078: case CRITERIA_ID: 1079: case CRITERIA_VAL: 1080: if (TASK_VAL(task) == (u_long) param) 1081: flg = 1; 1082: break; 1083: case CRITERIA_DATA: 1084: if (TASK_ID(task) == (sched_task_t*) param) 1085: flg = 1; 1086: break; 1087: default: 1088: sched_SetErr(EINVAL, "Invalid parameter criteria %d", criteria); 1089: flg = -1; 1090: } 1091: if (flg < 0) 1092: break; 1093: /* resume choosen task */ 1094: if (flg > 0) { 1095: if (root->root_hooks.hook_exec.resume) 1096: if (root->root_hooks.hook_exec.resume(task, NULL)) { 1097: flg = -1; 1098: break; 1099: } 1100: 1101: TAILQ_REMOVE(&root->root_suspend, task, task_node); 1102: 1103: task->task_type = taskREADY; 1104: insert_task_to(task, &root->root_ready); 1105: 1106: flg ^= flg; /* ok */ 1107: } 1108: } 1109: SCHED_QUNLOCK(root, taskSUSPEND); 1110: 1111: return flg; 1112: }