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