Annotation of libaitsched/src/aitsched.c, revision 1.32
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.32 ! misho 6: * $Id: aitsched.c,v 1.31.2.2 2023/07/27 20:47:12 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.30 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: #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
1.18 misho 59: int
1.1 misho 60: sched_GetErrno()
61: {
62: return sched_Errno;
63: }
64:
65: // sched_GetError() Get error text of last operation
1.18 misho 66: const char *
1.1 misho 67: sched_GetError()
68: {
69: return sched_Error;
70: }
71:
72: // sched_SetErr() Set error to variables for internal use!!!
1.18 misho 73: void
1.1 misho 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:
1.26 misho 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:
1.1 misho 158: /* Init and prepare scheduler functions */
159:
160: /*
1.2 misho 161: * schedRegisterHooks() - Register IO handles and bind tasks to it
1.6 misho 162: *
1.2 misho 163: * @root = root task
164: * return: -1 error or 0 ok
165: */
166: int
167: schedRegisterHooks(sched_root_task_t * __restrict root)
168: {
1.7 misho 169: assert(root);
1.2 misho 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;
1.25 misho 177: #if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
1.19 misho 178: root->root_hooks.hook_add.rtc = sched_hook_rtc;
179: #endif
1.26 misho 180: #if SUP_ENABLE == KQ_SUPPORT
181: root->root_hooks.hook_add.alarm = sched_hook_alarm;
1.10 misho 182: root->root_hooks.hook_add.node = sched_hook_node;
183: root->root_hooks.hook_add.proc = sched_hook_proc;
184: #ifdef EVFILT_USER
185: root->root_hooks.hook_add.user = sched_hook_user;
186: #endif
1.26 misho 187: #endif /* KQ_SUPPORT */
1.15 misho 188: #ifdef HAVE_LIBPTHREAD
189: root->root_hooks.hook_add.thread = sched_hook_thread;
190: #endif
1.31 misho 191: root->root_hooks.hook_add.signal = sched_hook_signal;
1.2 misho 192:
193: root->root_hooks.hook_exec.cancel = sched_hook_cancel;
194: root->root_hooks.hook_exec.fetch = sched_hook_fetch;
1.3 misho 195: root->root_hooks.hook_exec.exception = sched_hook_exception;
1.2 misho 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: /*
1.1 misho 203: * schedInit() - Init scheduler
1.6 misho 204: *
1.1 misho 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 *);
1.32 ! misho 214: sigset_t ss;
1.5 misho 215: #ifdef HAVE_LIBPTHREAD
216: register int i;
217: #endif
1.1 misho 218:
1.29 misho 219: root = e_malloc(sizeof(sched_root_task_t));
1.2 misho 220: if (!root) {
221: LOGERR;
222: } else {
1.1 misho 223: memset(root, 0, sizeof(sched_root_task_t));
1.5 misho 224:
1.13 misho 225: /* set default maximum regular task hit misses */
226: root->root_miss = MAX_TASK_MISS;
227:
1.5 misho 228: /* INFINIT polling period by default */
229: sched_timespecinf(&root->root_poll);
230:
231: #ifdef HAVE_LIBPTHREAD
1.31 misho 232: if (pthread_mutex_init(&root->root_sigmtx, NULL)) {
233: LOGERR;
234: e_free(root);
235: return NULL;
236: }
237:
1.5 misho 238: for (i = 0; i < taskMAX; i++)
1.17 misho 239: if ((errno = pthread_mutex_init(&root->root_mtx[i], NULL))) {
1.5 misho 240: LOGERR;
241: while (i)
242: pthread_mutex_destroy(&root->root_mtx[--i]);
1.29 misho 243: e_free(root);
1.5 misho 244: return NULL;
245: }
246:
247: for (i = 0; i < taskMAX; i++)
248: pthread_mutex_lock(&root->root_mtx[i]);
249: #endif
250:
1.2 misho 251: TAILQ_INIT(&root->root_read);
252: TAILQ_INIT(&root->root_write);
1.10 misho 253: TAILQ_INIT(&root->root_timer);
1.9 misho 254: TAILQ_INIT(&root->root_alarm);
1.19 misho 255: TAILQ_INIT(&root->root_rtc);
1.10 misho 256: TAILQ_INIT(&root->root_node);
257: TAILQ_INIT(&root->root_proc);
1.12 misho 258: TAILQ_INIT(&root->root_signal);
259: TAILQ_INIT(&root->root_aio);
260: TAILQ_INIT(&root->root_lio);
1.10 misho 261: TAILQ_INIT(&root->root_user);
1.2 misho 262: TAILQ_INIT(&root->root_event);
1.13 misho 263: TAILQ_INIT(&root->root_task);
1.11 misho 264: TAILQ_INIT(&root->root_suspend);
1.2 misho 265: TAILQ_INIT(&root->root_ready);
266: TAILQ_INIT(&root->root_unuse);
1.15 misho 267: TAILQ_INIT(&root->root_thread);
1.1 misho 268:
1.5 misho 269: #ifdef HAVE_LIBPTHREAD
270: for (i = 0; i < taskMAX; i++)
271: pthread_mutex_unlock(&root->root_mtx[i]);
1.32 ! misho 272:
! 273: sigfillset(&ss);
! 274: pthread_sigmask(SIG_BLOCK, &ss, &root->root_oldset);
! 275: #else
! 276: sigprocmask(SIG_BLOCK, &ss, &root->root_oldset);
1.5 misho 277: #endif
278:
1.1 misho 279: if (data && *data) {
280: if (datlen) {
281: root->root_data.iov_base = *data;
282: root->root_data.iov_len = datlen;
1.3 misho 283: } else { /* if datlen == 0, switch to callbacks init mode */
284: /* little hack :) for correct initialization of scheduler */
1.2 misho 285: func = (int(*)(sched_root_task_t*)) data;
1.1 misho 286: func(root);
287: }
288: }
1.2 misho 289:
290: if (root->root_hooks.hook_root.init)
291: root->root_hooks.hook_root.init(root, NULL);
1.1 misho 292: }
293:
294: return root;
295: }
296:
297: /*
298: * schedEnd() - End scheduler & free all resources
1.6 misho 299: *
1.1 misho 300: * @root = root task
301: * return: -1 error or 0 ok
302: */
303: int
1.2 misho 304: schedEnd(sched_root_task_t ** __restrict root)
1.1 misho 305: {
1.7 misho 306: sched_task_t *task, *tmp;
1.5 misho 307: #ifdef HAVE_LIBPTHREAD
308: register int i;
309: #endif
1.1 misho 310:
1.2 misho 311: if (!root || !*root)
1.1 misho 312: return -1;
313:
1.26 misho 314: #if 0
315: TAILQ_FOREACH_SAFE(task, &(*root)->root_read, task_node, tmp)
316: printf("read=%p\n", task);
317: TAILQ_FOREACH_SAFE(task, &(*root)->root_write, task_node, tmp)
318: printf("write=%p\n", task);
319: TAILQ_FOREACH_SAFE(task, &(*root)->root_timer, task_node, tmp)
320: printf("timer=%p\n", task);
321: TAILQ_FOREACH_SAFE(task, &(*root)->root_alarm, task_node, tmp)
322: printf("alarm=%p\n", task);
323: TAILQ_FOREACH_SAFE(task, &(*root)->root_rtc, task_node, tmp)
324: printf("rtc=%p\n", task);
325: TAILQ_FOREACH_SAFE(task, &(*root)->root_node, task_node, tmp)
326: printf("node=%p\n", task);
327: TAILQ_FOREACH_SAFE(task, &(*root)->root_proc, task_node, tmp)
328: printf("proc=%p\n", task);
329: TAILQ_FOREACH_SAFE(task, &(*root)->root_signal, task_node, tmp)
330: printf("signal=%p\n", task);
331: TAILQ_FOREACH_SAFE(task, &(*root)->root_aio, task_node, tmp)
332: printf("aio=%p\n", task);
333: TAILQ_FOREACH_SAFE(task, &(*root)->root_lio, task_node, tmp)
334: printf("lio=%p\n", task);
335: TAILQ_FOREACH_SAFE(task, &(*root)->root_user, task_node, tmp)
336: printf("user=%p\n", task);
337: TAILQ_FOREACH_SAFE(task, &(*root)->root_event, task_node, tmp)
338: printf("event=%p\n", task);
339: TAILQ_FOREACH_SAFE(task, &(*root)->root_suspend, task_node, tmp)
340: printf("suspend=%p\n", task);
341: TAILQ_FOREACH_SAFE(task, &(*root)->root_ready, task_node, tmp)
342: printf("ready=%p\n", task);
343: TAILQ_FOREACH_SAFE(task, &(*root)->root_thread, task_node, tmp)
344: printf("thread=%p\n", task);
345: TAILQ_FOREACH_SAFE(task, &(*root)->root_task, task_node, tmp)
346: printf("task=%p\n", task);
347: TAILQ_FOREACH_SAFE(task, &(*root)->root_unuse, task_node, tmp)
348: printf("unuse=%p\n", task);
349: fflush(stdout);
350: #endif
351:
1.10 misho 352: TAILQ_FOREACH_SAFE(task, &(*root)->root_read, task_node, tmp)
353: schedCancel(task);
354: TAILQ_FOREACH_SAFE(task, &(*root)->root_write, task_node, tmp)
1.1 misho 355: schedCancel(task);
1.10 misho 356: TAILQ_FOREACH_SAFE(task, &(*root)->root_timer, task_node, tmp)
357: schedCancel(task);
358: TAILQ_FOREACH_SAFE(task, &(*root)->root_alarm, task_node, tmp)
359: schedCancel(task);
1.19 misho 360: TAILQ_FOREACH_SAFE(task, &(*root)->root_rtc, task_node, tmp)
361: schedCancel(task);
1.10 misho 362: TAILQ_FOREACH_SAFE(task, &(*root)->root_node, task_node, tmp)
363: schedCancel(task);
364: TAILQ_FOREACH_SAFE(task, &(*root)->root_proc, task_node, tmp)
1.1 misho 365: schedCancel(task);
1.12 misho 366: TAILQ_FOREACH_SAFE(task, &(*root)->root_signal, task_node, tmp)
367: schedCancel(task);
368: TAILQ_FOREACH_SAFE(task, &(*root)->root_aio, task_node, tmp)
369: schedCancel(task);
370: TAILQ_FOREACH_SAFE(task, &(*root)->root_lio, task_node, tmp)
371: schedCancel(task);
1.10 misho 372: TAILQ_FOREACH_SAFE(task, &(*root)->root_user, task_node, tmp)
1.9 misho 373: schedCancel(task);
1.10 misho 374: TAILQ_FOREACH_SAFE(task, &(*root)->root_event, task_node, tmp)
1.1 misho 375: schedCancel(task);
1.11 misho 376: TAILQ_FOREACH_SAFE(task, &(*root)->root_suspend, task_node, tmp)
377: schedCancel(task);
1.10 misho 378: TAILQ_FOREACH_SAFE(task, &(*root)->root_ready, task_node, tmp)
1.1 misho 379: schedCancel(task);
1.15 misho 380: TAILQ_FOREACH_SAFE(task, &(*root)->root_thread, task_node, tmp)
381: schedCancel(task);
1.16 misho 382: TAILQ_FOREACH_SAFE(task, &(*root)->root_task, task_node, tmp)
383: schedCancel(task);
1.1 misho 384:
1.26 misho 385: SCHED_QLOCK((*root), taskUNUSE);
1.10 misho 386: TAILQ_FOREACH_SAFE(task, &(*root)->root_unuse, task_node, tmp) {
1.2 misho 387: TAILQ_REMOVE(&(*root)->root_unuse, task, task_node);
1.29 misho 388: e_free(task);
1.1 misho 389: }
1.26 misho 390: SCHED_QUNLOCK((*root), taskUNUSE);
1.1 misho 391:
1.2 misho 392: if ((*root)->root_hooks.hook_root.fini)
393: (*root)->root_hooks.hook_root.fini(*root, NULL);
1.1 misho 394:
1.5 misho 395: #ifdef HAVE_LIBPTHREAD
1.26 misho 396: for (i = 0; i < taskMAX; i++) {
1.28 misho 397: SCHED_QTRYLOCK(*root, i);
1.26 misho 398: SCHED_QUNLOCK(*root, i);
1.5 misho 399: pthread_mutex_destroy(&(*root)->root_mtx[i]);
1.26 misho 400: }
1.31 misho 401:
402: if ((*root)->root_sigthr) {
403: pthread_cancel((*root)->root_sigthr);
404: #ifdef __linux__
405: (*root)->root_sigthr = 0L;
406: #else
407: (*root)->root_sigthr = NULL;
408: #endif
409: pthread_sigmask(SIG_SETMASK, &(*root)->root_oldset, NULL);
410: pthread_mutex_unlock(&(*root)->root_sigmtx);
411: }
412: pthread_mutex_destroy(&(*root)->root_sigmtx);
1.32 ! misho 413: #else
! 414: sigprocmask(SIG_SETMASK, &(*root)->root_oldset, NULL);
1.5 misho 415: #endif
416:
1.29 misho 417: e_free(*root);
1.2 misho 418: *root = NULL;
1.1 misho 419: return 0;
420: }
421:
422: /*
423: * schedCall() - Call task execution function
1.6 misho 424: *
1.1 misho 425: * @task = current task
426: * return: !=NULL error or =NULL ok
427: */
1.18 misho 428: void *
1.1 misho 429: schedCall(sched_task_t * __restrict task)
430: {
1.4 misho 431: void *ptr = (void*) -1;
432:
1.1 misho 433: if (!task)
1.4 misho 434: return ptr;
435:
436: if (!TASK_ISLOCKED(task))
437: TASK_LOCK(task);
1.1 misho 438:
1.4 misho 439: ptr = task->task_func(task);
440:
441: TASK_UNLOCK(task);
442: return ptr;
1.1 misho 443: }
444:
445: /*
446: * schedFetch() - Fetch ready task
1.6 misho 447: *
1.1 misho 448: * @root = root task
449: * return: =NULL error or !=NULL ready task
450: */
1.18 misho 451: void *
1.1 misho 452: schedFetch(sched_root_task_t * __restrict root)
453: {
454: void *ptr;
455:
456: if (!root)
457: return NULL;
458:
459: if (root->root_hooks.hook_exec.fetch)
460: ptr = root->root_hooks.hook_exec.fetch(root, NULL);
461: else
462: ptr = NULL;
463:
464: return ptr;
465: }
466:
467: /*
1.10 misho 468: * schedTrigger() - Triggering USER task
469: *
470: * @task = task
471: * return: -1 error or 0 ok
472: */
473: int
474: schedTrigger(sched_task_t * __restrict task)
475: {
1.26 misho 476: #if SUP_ENABLE != KQ_SUPPORT
1.24 misho 477: sched_SetErr(ENOTSUP, "disabled kqueue support");
478: return -1;
479: #else
1.10 misho 480: #ifndef EVFILT_USER
481: sched_SetErr(ENOTSUP, "Not supported kevent() filter");
482: return -1;
483: #else
484: struct kevent chg[1];
485: struct timespec timeout = { 0, 0 };
486:
487: if (!task || !TASK_ROOT(task))
488: return -1;
489:
490: #ifdef __NetBSD__
491: EV_SET(chg, TASK_VAL(task), EVFILT_USER, 0, NOTE_TRIGGER, 0, (intptr_t) TASK_VAL(task));
492: #else
493: EV_SET(chg, TASK_VAL(task), EVFILT_USER, 0, NOTE_TRIGGER, 0, (void*) TASK_VAL(task));
494: #endif
495: if (kevent(TASK_ROOT(task)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
496: LOGERR;
497: return -1;
498: }
499:
500: return 0;
501: #endif
1.26 misho 502: #endif /* KQ_SUPPORT */
1.10 misho 503: }
504:
505: /*
1.20 misho 506: * schedQuery() - Query task in scheduler
507: *
508: * @task = task
509: * return: -1 error, 0 found and 1 not found
510: */
511: int
512: schedQuery(sched_task_t * __restrict task)
513: {
514: sched_queue_t *queue;
515: sched_task_t *t;
516:
517: if (!task || !TASK_ROOT(task))
518: return -1; /* error */
519:
520: switch (TASK_TYPE(task)) {
521: case taskREAD:
522: queue = &TASK_ROOT(task)->root_read;
523: break;
524: case taskWRITE:
525: queue = &TASK_ROOT(task)->root_write;
526: break;
527: case taskTIMER:
528: queue = &TASK_ROOT(task)->root_timer;
529: break;
530: case taskALARM:
531: queue = &TASK_ROOT(task)->root_alarm;
532: break;
533: case taskRTC:
534: queue = &TASK_ROOT(task)->root_rtc;
535: break;
536: case taskNODE:
537: queue = &TASK_ROOT(task)->root_node;
538: break;
539: case taskPROC:
540: queue = &TASK_ROOT(task)->root_proc;
541: break;
542: case taskSIGNAL:
543: queue = &TASK_ROOT(task)->root_signal;
544: break;
545: case taskAIO:
546: queue = &TASK_ROOT(task)->root_aio;
547: break;
548: case taskLIO:
549: queue = &TASK_ROOT(task)->root_lio;
550: break;
551: case taskUSER:
552: queue = &TASK_ROOT(task)->root_user;
553: break;
554: case taskEVENT:
555: queue = &TASK_ROOT(task)->root_event;
556: break;
557: case taskTASK:
558: queue = &TASK_ROOT(task)->root_task;
559: break;
560: case taskSUSPEND:
561: queue = &TASK_ROOT(task)->root_suspend;
562: break;
563: case taskREADY:
564: queue = &TASK_ROOT(task)->root_ready;
565: break;
566: case taskTHREAD:
567: queue = &TASK_ROOT(task)->root_thread;
568: break;
569: default:
570: return 1; /* not in queue */
571: }
572: if (queue)
573: TAILQ_FOREACH(t, queue, task_node)
574: if (TASK_ID(t) == TASK_ID(task))
575: return 0; /* found */
576:
577: return 1; /* not in queue */
578: }
579:
580: /*
581: * schedQueryby() - Query task in scheduler by criteria
582: *
583: * @root = root task
584: * @type = query from queue type, if =taskMAX query same task from all queues
585: * @criteria = find task by criteria
586: * [ CRITERIA_ANY|CRITERIA_CALL|CRITERIA_ARG|CRITERIA_FD|CRITERIA_VAL|
1.23 misho 587: * CRITERIA_ID|CRITERIA_TS|CRITERIA_DATA|CRITERIA_DATLEN ]
1.20 misho 588: * @param = search parameter
1.30 misho 589: * return: NULL not found or !=NULL task
1.20 misho 590: */
1.30 misho 591: sched_task_t *
1.20 misho 592: schedQueryby(sched_root_task_t * __restrict root, sched_task_type_t type,
593: u_char criteria, void *param)
594: {
1.21 misho 595: sched_task_t *task;
1.20 misho 596: sched_queue_t *queue;
597:
598: if (!root)
1.30 misho 599: return NULL;
1.20 misho 600: /* if type == taskMAX check in all queues */
601: if (type == taskMAX) {
1.30 misho 602: if ((task = schedQueryby(root, taskREAD, criteria, param)))
603: return task;
604: if ((task = schedQueryby(root, taskWRITE, criteria, param)))
605: return task;
606: if ((task = schedQueryby(root, taskTIMER, criteria, param)))
607: return task;
608: if ((task = schedQueryby(root, taskALARM, criteria, param)))
609: return task;
610: if ((task = schedQueryby(root, taskRTC, criteria, param)))
611: return task;
612: if ((task = schedQueryby(root, taskNODE, criteria, param)))
613: return task;
614: if ((task = schedQueryby(root, taskPROC, criteria, param)))
615: return task;
616: if ((task = schedQueryby(root, taskSIGNAL, criteria, param)))
617: return task;
618: if ((task = schedQueryby(root, taskAIO, criteria, param)))
619: return task;
620: if ((task = schedQueryby(root, taskLIO, criteria, param)))
621: return task;
622: if ((task = schedQueryby(root, taskUSER, criteria, param)))
623: return task;
624: if ((task = schedQueryby(root, taskEVENT, criteria, param)))
625: return task;
626: if ((task = schedQueryby(root, taskTASK, criteria, param)))
627: return task;
628: if ((task = schedQueryby(root, taskSUSPEND, criteria, param)))
629: return task;
630: if ((task = schedQueryby(root, taskREADY, criteria, param)))
631: return task;
632: if ((task = schedQueryby(root, taskTHREAD, criteria, param)))
633: return task;
634: return NULL; /* not found */
1.20 misho 635: }
636: /* choosen queue */
637: switch (type) {
638: case taskREAD:
639: queue = &root->root_read;
640: break;
641: case taskWRITE:
642: queue = &root->root_write;
643: break;
644: case taskTIMER:
645: queue = &root->root_timer;
646: break;
647: case taskALARM:
648: queue = &root->root_alarm;
649: break;
650: case taskRTC:
651: queue = &root->root_rtc;
652: break;
653: case taskNODE:
654: queue = &root->root_node;
655: break;
656: case taskPROC:
657: queue = &root->root_proc;
658: break;
659: case taskSIGNAL:
660: queue = &root->root_signal;
661: break;
662: case taskAIO:
663: queue = &root->root_aio;
664: break;
665: case taskLIO:
666: queue = &root->root_lio;
667: break;
668: case taskUSER:
669: queue = &root->root_user;
670: break;
671: case taskEVENT:
672: queue = &root->root_event;
673: break;
674: case taskTASK:
675: queue = &root->root_task;
676: break;
677: case taskSUSPEND:
678: queue = &root->root_suspend;
679: break;
680: case taskREADY:
681: queue = &root->root_ready;
682: break;
683: case taskTHREAD:
684: queue = &root->root_thread;
685: break;
686: default:
1.30 misho 687: return NULL; /* not found */
1.20 misho 688: }
689:
690: TAILQ_FOREACH(task, queue, task_node) {
691: switch (criteria) {
692: case CRITERIA_ANY:
1.30 misho 693: return task; /* found */
1.20 misho 694: case CRITERIA_CALL:
695: if (TASK_FUNC(task) == (sched_task_func_t) param)
1.30 misho 696: return task; /* found */
1.20 misho 697: break;
698: case CRITERIA_ARG:
699: if (TASK_ARG(task) == param)
1.30 misho 700: return task; /* found */
1.20 misho 701: break;
702: case CRITERIA_FD:
703: if (TASK_FD(task) == (intptr_t) param)
1.30 misho 704: return task; /* found */
1.20 misho 705: break;
706: case CRITERIA_ID:
707: case CRITERIA_VAL:
708: if (TASK_VAL(task) == (u_long) param)
1.30 misho 709: return task; /* found */
1.20 misho 710: break;
711: case CRITERIA_TS:
712: if (!sched_timespeccmp(&TASK_TS(task),
713: (struct timespec*) param, -))
1.30 misho 714: return task; /* found */
1.20 misho 715: break;
716: case CRITERIA_DATA:
717: if (TASK_DATA(task) == param)
1.30 misho 718: return task; /* found */
1.20 misho 719: break;
1.23 misho 720: case CRITERIA_DATLEN:
721: if (TASK_DATLEN(task) == (size_t) param)
1.30 misho 722: return task; /* found */
1.23 misho 723: break;
1.20 misho 724: default:
725: sched_SetErr(EINVAL, "Invalid parameter criteria %d",
726: criteria);
1.30 misho 727: return NULL; /* not found */
1.20 misho 728: }
729: }
730:
1.30 misho 731: return NULL; /* not found */
1.20 misho 732: }
733:
734: /*
1.1 misho 735: * schedCancel() - Cancel task from scheduler
1.6 misho 736: *
1.1 misho 737: * @task = task
738: * return: -1 error or 0 ok
739: */
740: int
741: schedCancel(sched_task_t * __restrict task)
742: {
743: sched_queue_t *queue;
744:
1.5 misho 745: if (!task || !TASK_ROOT(task))
1.1 misho 746: return -1;
747:
1.5 misho 748: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel)
749: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel(task, NULL))
1.1 misho 750: return -1;
751:
1.5 misho 752: switch (TASK_TYPE(task)) {
1.1 misho 753: case taskREAD:
1.5 misho 754: queue = &TASK_ROOT(task)->root_read;
1.1 misho 755: break;
756: case taskWRITE:
1.5 misho 757: queue = &TASK_ROOT(task)->root_write;
1.1 misho 758: break;
1.10 misho 759: case taskTIMER:
760: queue = &TASK_ROOT(task)->root_timer;
761: break;
1.9 misho 762: case taskALARM:
763: queue = &TASK_ROOT(task)->root_alarm;
764: break;
1.19 misho 765: case taskRTC:
766: queue = &TASK_ROOT(task)->root_rtc;
767: break;
1.10 misho 768: case taskNODE:
769: queue = &TASK_ROOT(task)->root_node;
770: break;
771: case taskPROC:
772: queue = &TASK_ROOT(task)->root_proc;
773: break;
1.12 misho 774: case taskSIGNAL:
775: queue = &TASK_ROOT(task)->root_signal;
776: break;
777: case taskAIO:
778: queue = &TASK_ROOT(task)->root_aio;
779: break;
780: case taskLIO:
781: queue = &TASK_ROOT(task)->root_lio;
782: break;
1.10 misho 783: case taskUSER:
784: queue = &TASK_ROOT(task)->root_user;
785: break;
1.1 misho 786: case taskEVENT:
1.5 misho 787: queue = &TASK_ROOT(task)->root_event;
788: break;
1.13 misho 789: case taskTASK:
790: queue = &TASK_ROOT(task)->root_task;
1.1 misho 791: break;
1.11 misho 792: case taskSUSPEND:
793: queue = &TASK_ROOT(task)->root_suspend;
794: break;
1.1 misho 795: case taskREADY:
1.5 misho 796: queue = &TASK_ROOT(task)->root_ready;
1.1 misho 797: break;
1.15 misho 798: case taskTHREAD:
799: queue = &TASK_ROOT(task)->root_thread;
800: break;
1.1 misho 801: default:
802: queue = NULL;
803: }
1.26 misho 804: if (queue)
805: remove_task_from(task, queue);
1.5 misho 806: if (TASK_TYPE(task) != taskUNUSE)
1.15 misho 807: sched_unuseTask(task);
1.1 misho 808:
809: return 0;
810: }
811:
812: /*
813: * schedCancelby() - Cancel task from scheduler by criteria
1.6 misho 814: *
1.1 misho 815: * @root = root task
1.5 misho 816: * @type = cancel from queue type, if =taskMAX cancel same task from all queues
1.10 misho 817: * @criteria = find task by criteria
1.20 misho 818: * [ CRITERIA_ANY|CRITERIA_CALL|CRITERIA_ARG|CRITERIA_FD|CRITERIA_VAL|
1.23 misho 819: * CRITERIA_ID|CRITERIA_TS|CRITERIA_DATA|CRITERIA_DATLEN ]
1.1 misho 820: * @param = search parameter
821: * @hook = custom cleanup hook function, may be NULL
1.3 misho 822: * return: -1 error, -2 error in sub-stage cancel execution, -3 error from custom hook or 0 ok
1.1 misho 823: */
824: int
1.5 misho 825: schedCancelby(sched_root_task_t * __restrict root, sched_task_type_t type,
1.1 misho 826: u_char criteria, void *param, sched_hook_func_t hook)
827: {
1.8 misho 828: sched_task_t *task, *tmp;
1.5 misho 829: sched_queue_t *queue;
1.8 misho 830: register int flg = 0;
1.1 misho 831:
832: if (!root)
833: return -1;
1.10 misho 834: /* if type == taskMAX check in all queues */
1.5 misho 835: if (type == taskMAX) {
836: if (schedCancelby(root, taskREAD, criteria, param, hook))
1.1 misho 837: return -2;
1.5 misho 838: if (schedCancelby(root, taskWRITE, criteria, param, hook))
1.1 misho 839: return -2;
1.10 misho 840: if (schedCancelby(root, taskTIMER, criteria, param, hook))
841: return -2;
1.9 misho 842: if (schedCancelby(root, taskALARM, criteria, param, hook))
843: return -2;
1.19 misho 844: if (schedCancelby(root, taskRTC, criteria, param, hook))
845: return -2;
1.10 misho 846: if (schedCancelby(root, taskNODE, criteria, param, hook))
847: return -2;
848: if (schedCancelby(root, taskPROC, criteria, param, hook))
849: return -2;
1.12 misho 850: if (schedCancelby(root, taskSIGNAL, criteria, param, hook))
851: return -2;
852: if (schedCancelby(root, taskAIO, criteria, param, hook))
853: return -2;
854: if (schedCancelby(root, taskLIO, criteria, param, hook))
855: return -2;
1.10 misho 856: if (schedCancelby(root, taskUSER, criteria, param, hook))
857: return -2;
1.5 misho 858: if (schedCancelby(root, taskEVENT, criteria, param, hook))
1.1 misho 859: return -2;
1.13 misho 860: if (schedCancelby(root, taskTASK, criteria, param, hook))
1.1 misho 861: return -2;
1.11 misho 862: if (schedCancelby(root, taskSUSPEND, criteria, param, hook))
863: return -2;
1.5 misho 864: if (schedCancelby(root, taskREADY, criteria, param, hook))
1.1 misho 865: return -2;
1.15 misho 866: if (schedCancelby(root, taskTHREAD, criteria, param, hook))
867: return -2;
1.1 misho 868: return 0;
869: }
1.10 misho 870: /* choosen queue */
1.5 misho 871: switch (type) {
872: case taskREAD:
873: queue = &root->root_read;
874: break;
875: case taskWRITE:
876: queue = &root->root_write;
877: break;
1.10 misho 878: case taskTIMER:
879: queue = &root->root_timer;
880: break;
1.9 misho 881: case taskALARM:
882: queue = &root->root_alarm;
883: break;
1.19 misho 884: case taskRTC:
885: queue = &root->root_rtc;
886: break;
1.10 misho 887: case taskNODE:
888: queue = &root->root_node;
889: break;
890: case taskPROC:
891: queue = &root->root_proc;
892: break;
1.12 misho 893: case taskSIGNAL:
894: queue = &root->root_signal;
895: break;
896: case taskAIO:
897: queue = &root->root_aio;
898: break;
899: case taskLIO:
900: queue = &root->root_lio;
901: break;
1.10 misho 902: case taskUSER:
903: queue = &root->root_user;
904: break;
1.5 misho 905: case taskEVENT:
906: queue = &root->root_event;
907: break;
1.13 misho 908: case taskTASK:
909: queue = &root->root_task;
1.5 misho 910: break;
1.11 misho 911: case taskSUSPEND:
912: queue = &root->root_suspend;
913: break;
1.5 misho 914: case taskREADY:
915: queue = &root->root_ready;
916: break;
1.15 misho 917: case taskTHREAD:
918: queue = &root->root_thread;
919: break;
1.5 misho 920: default:
921: return 0;
922: }
1.1 misho 923:
1.26 misho 924: SCHED_QLOCK(root, type);
1.8 misho 925: TAILQ_FOREACH_SAFE(task, queue, task_node, tmp) {
926: flg ^= flg;
927: switch (criteria) {
1.10 misho 928: case CRITERIA_ANY:
929: flg = 1;
930: break;
1.8 misho 931: case CRITERIA_CALL:
932: if (TASK_FUNC(task) == (sched_task_func_t) param)
933: flg = 1;
1.1 misho 934: break;
1.8 misho 935: case CRITERIA_ARG:
936: if (TASK_ARG(task) == param)
937: flg = 1;
1.1 misho 938: break;
1.8 misho 939: case CRITERIA_FD:
940: if (TASK_FD(task) == (intptr_t) param)
941: flg = 1;
1.1 misho 942: break;
1.11 misho 943: case CRITERIA_ID:
1.8 misho 944: case CRITERIA_VAL:
945: if (TASK_VAL(task) == (u_long) param)
946: flg = 1;
1.1 misho 947: break;
1.8 misho 948: case CRITERIA_TS:
949: if (!sched_timespeccmp(&TASK_TS(task), (struct timespec*) param, -))
950: flg = 1;
1.1 misho 951: break;
1.10 misho 952: case CRITERIA_DATA:
953: if (TASK_DATA(task) == param)
954: flg = 1;
955: break;
1.23 misho 956: case CRITERIA_DATLEN:
957: if (TASK_DATLEN(task) == (size_t) param)
958: flg = 1;
959: break;
1.8 misho 960: default:
961: sched_SetErr(EINVAL, "Invalid parameter criteria %d", criteria);
962: flg = -1;
963: }
1.10 misho 964: if (flg < 0) /* error */
1.8 misho 965: break;
966: /* cancel choosen task */
967: if (flg > 0) {
968: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel)
969: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel(task, NULL)) {
970: flg = -1;
971: break;
972: }
973: /* custom hook */
974: if (hook)
975: if (hook(task, NULL)) {
976: flg = -3;
977: break;
978: }
979:
980: TAILQ_REMOVE(queue, task, task_node);
981: if (TASK_TYPE(task) != taskUNUSE)
1.15 misho 982: sched_unuseTask(task);
1.8 misho 983:
984: flg ^= flg; /* ok */
1.1 misho 985: }
1.8 misho 986: }
1.26 misho 987: SCHED_QUNLOCK(root, type);
988:
1.8 misho 989: return flg;
1.1 misho 990: }
991:
992: /*
993: * schedRun() - Scheduler *run loop*
1.6 misho 994: *
1.1 misho 995: * @root = root task
1.2 misho 996: * @killState = kill condition variable, if !=0 stop scheduler loop
1.1 misho 997: * return: -1 error or 0 ok
998: */
999: int
1.7 misho 1000: schedRun(sched_root_task_t *root, volatile intptr_t * __restrict killState)
1.1 misho 1001: {
1002: sched_task_t *task;
1003:
1004: if (!root)
1005: return -1;
1006:
1007: if (root->root_hooks.hook_exec.run)
1008: if (root->root_hooks.hook_exec.run(root, NULL))
1009: return -1;
1.7 misho 1010:
1011: if (killState) {
1012: if (root->root_hooks.hook_exec.condition)
1013: /* condition scheduler loop */
1014: while (root && root->root_hooks.hook_exec.fetch &&
1015: root->root_hooks.hook_exec.condition &&
1016: root->root_hooks.hook_exec.condition(root, (void*) killState)) {
1017: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
1.12 misho 1018: root->root_ret = schedCall(task);
1.7 misho 1019: }
1020: else
1021: /* trigger scheduler loop */
1022: while (!*killState && root && root->root_hooks.hook_exec.fetch) {
1023: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
1.12 misho 1024: root->root_ret = schedCall(task);
1.7 misho 1025: }
1026: } else
1027: /* infinite scheduler loop */
1028: while (root && root->root_hooks.hook_exec.fetch)
1029: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
1.12 misho 1030: root->root_ret = schedCall(task);
1.1 misho 1031:
1032: return 0;
1033: }
1.5 misho 1034:
1035: /*
1036: * schedPolling() - Polling timeout period if no timer task is present
1.6 misho 1037: *
1.5 misho 1038: * @root = root task
1039: * @ts = timeout polling period, if ==NULL INFINIT timeout
1040: * @tsold = old timeout polling if !=NULL
1041: * return: -1 error or 0 ok
1042: */
1.18 misho 1043: int
1.5 misho 1044: schedPolling(sched_root_task_t * __restrict root, struct timespec * __restrict ts,
1045: struct timespec * __restrict tsold)
1046: {
1047: if (!root)
1048: return -1;
1049:
1050: if (tsold)
1051: *tsold = root->root_poll;
1052:
1053: if (!ts)
1054: sched_timespecinf(&root->root_poll);
1055: else
1056: root->root_poll = *ts;
1057:
1058: return 0;
1059: }
1.6 misho 1060:
1061: /*
1062: * schedTermCondition() - Activate hook for scheduler condition kill
1063: *
1064: * @root = root task
1065: * @condValue = condition value, kill schedRun() if condValue == killState
1.13 misho 1066: * return: -1 error or 0 ok
1.6 misho 1067: */
1.18 misho 1068: int
1.26 misho 1069: schedTermCondition(sched_root_task_t * __restrict root, intptr_t * __restrict condValue)
1.6 misho 1070: {
1.26 misho 1071: if (!root && !condValue)
1.6 misho 1072: return -1;
1073:
1.26 misho 1074: *root->root_cond = *condValue;
1.6 misho 1075: root->root_hooks.hook_exec.condition = sched_hook_condition;
1076: return 0;
1077: }
1.11 misho 1078:
1079: /*
1080: * schedResumeby() - Resume suspended task
1081: *
1082: * @root = root task
1083: * @criteria = find task by criteria
1.23 misho 1084: * [CRITERIA_ANY|CRITERIA_ID|CRITERIA_VAL|CRITERIA_DATA]
1.20 misho 1085: * @param = search parameter (sched_task_t *task| unsigned long id)
1.11 misho 1086: * return: -1 error or 0 resumed ok
1087: */
1088: int
1089: schedResumeby(sched_root_task_t * __restrict root, u_char criteria, void *param)
1090: {
1091: sched_task_t *task, *tmp;
1092: register int flg = 0;
1093:
1094: if (!root)
1095: return -1;
1096:
1.26 misho 1097: SCHED_QLOCK(root, taskSUSPEND);
1.11 misho 1098: TAILQ_FOREACH_SAFE(task, &root->root_suspend, task_node, tmp) {
1099: flg ^= flg;
1100: switch (criteria) {
1101: case CRITERIA_ANY:
1102: flg = 1;
1103: break;
1104: case CRITERIA_ID:
1.23 misho 1105: case CRITERIA_VAL:
1.11 misho 1106: if (TASK_VAL(task) == (u_long) param)
1107: flg = 1;
1108: break;
1109: case CRITERIA_DATA:
1110: if (TASK_ID(task) == (sched_task_t*) param)
1111: flg = 1;
1112: break;
1113: default:
1114: sched_SetErr(EINVAL, "Invalid parameter criteria %d", criteria);
1115: flg = -1;
1116: }
1117: if (flg < 0)
1118: break;
1119: /* resume choosen task */
1120: if (flg > 0) {
1121: if (root->root_hooks.hook_exec.resume)
1122: if (root->root_hooks.hook_exec.resume(task, NULL)) {
1123: flg = -1;
1124: break;
1125: }
1126:
1127: TAILQ_REMOVE(&root->root_suspend, task, task_node);
1128:
1129: task->task_type = taskREADY;
1.26 misho 1130: insert_task_to(task, &root->root_ready);
1.11 misho 1131:
1132: flg ^= flg; /* ok */
1133: }
1134: }
1.26 misho 1135: SCHED_QUNLOCK(root, taskSUSPEND);
1.11 misho 1136:
1137: return flg;
1138: }
1.31 misho 1139:
1140: static void *
1141: _sched_sigDisp(void *arg)
1142: {
1143: sched_root_task_t *root = arg;
1144: sched_task_t *task, *tmp;
1145: int sig, flg;
1146: sigset_t ss;
1147:
1148: sigfillset(&ss);
1149: while (root->root_sigthr) {
1150: if (sigwait(&ss, &sig))
1151: continue;
1152:
1153: pthread_mutex_lock(&root->root_sigmtx);
1154: if (!sigismember(&root->root_sigset, sig)) {
1155: pthread_mutex_unlock(&root->root_sigmtx);
1156: continue;
1157: }
1158:
1159: flg = 0;
1160: TAILQ_FOREACH_SAFE(task, &root->root_signal, task_node, tmp) {
1161: if (TASK_VAL(task) == (uintptr_t) sig) {
1162: if (!flg) {
1163: TASK_RET(task) = 0;
1164: TASK_FLAG(task) = 0;
1165:
1166: /* remove signal handle */
1167: transit_task2ready(task, &root->root_signal);
1168: }
1169: flg++;
1170: }
1171: }
1172: if (flg < 2)
1173: sigdelset(&root->root_sigset, sig);
1174:
1175: pthread_mutex_unlock(&root->root_sigmtx);
1176: }
1177:
1178: return NULL;
1179: }
1180:
1181: /*
1182: * schedSignalDispatch() - Activate or Deactivate signal dispatcher
1183: *
1184: * @root = root task
1185: * @on = Activate or =0 deactivate
1186: * return: -1 error or 0 ok
1187: */
1188: int
1189: schedSignalDispatch(sched_root_task_t * __restrict root, int on)
1190: {
1.32 ! misho 1191: struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
1.31 misho 1192: #ifndef HAVE_LIBPTHREAD
1193: sched_SetErr(ENOTSUP, "Library has not support pthreads");
1194: return -1;
1195: #else
1196: pthread_attr_t attr;
1197: #endif
1198:
1199: #if SUP_ENABLE == KQ_SUPPORT
1200: return 0;
1201: #endif
1202:
1203: if (!on) {
1204: pthread_cancel(root->root_sigthr);
1205: #ifdef __linux__
1206: root->root_sigthr = 0L;
1207: #else
1208: root->root_sigthr = NULL;
1209: #endif
1210: return 0;
1211: }
1212:
1.32 ! misho 1213: /* if we have not using polling, then we must turn on */
! 1214: if (sched_timespecisinf(&root->root_poll))
! 1215: schedPolling(root, &ts, NULL);
! 1216:
1.31 misho 1217: pthread_attr_init(&attr);
1218: pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1219: #ifdef SCHED_RR
1220: pthread_attr_setschedpolicy(&attr, SCHED_RR);
1221: #else
1222: pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
1223: #endif
1224:
1225: if (pthread_create(&root->root_sigthr, &attr, _sched_sigDisp, root)) {
1226: sched_SetErr(errno, "pthread_create(SignalDispatch) #%d - %s",
1227: errno, strerror(errno));
1228: #ifdef __linux__
1229: root->root_sigthr = 0L;
1230: #else
1231: root->root_sigthr = NULL;
1232: #endif
1233: return -1;
1234: }
1235:
1236: return 0;
1237: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>