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