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