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