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