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.26.2.1 2015/07/02 22:43:30 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 - 2015
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 = 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: 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: 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_QUNLOCK(*root, i);
386: pthread_mutex_destroy(&(*root)->root_mtx[i]);
387: }
388: #endif
389:
390: free(*root);
391: *root = NULL;
392: return 0;
393: }
394:
395: /*
396: * schedCall() - Call task execution function
397: *
398: * @task = current task
399: * return: !=NULL error or =NULL ok
400: */
401: void *
402: schedCall(sched_task_t * __restrict task)
403: {
404: void *ptr = (void*) -1;
405:
406: if (!task)
407: return ptr;
408:
409: if (!TASK_ISLOCKED(task))
410: TASK_LOCK(task);
411:
412: ptr = task->task_func(task);
413:
414: TASK_UNLOCK(task);
415: return ptr;
416: }
417:
418: /*
419: * schedFetch() - Fetch ready task
420: *
421: * @root = root task
422: * return: =NULL error or !=NULL ready task
423: */
424: void *
425: schedFetch(sched_root_task_t * __restrict root)
426: {
427: void *ptr;
428:
429: if (!root)
430: return NULL;
431:
432: if (root->root_hooks.hook_exec.fetch)
433: ptr = root->root_hooks.hook_exec.fetch(root, NULL);
434: else
435: ptr = NULL;
436:
437: return ptr;
438: }
439:
440: /*
441: * schedTrigger() - Triggering USER task
442: *
443: * @task = task
444: * return: -1 error or 0 ok
445: */
446: int
447: schedTrigger(sched_task_t * __restrict task)
448: {
449: #if SUP_ENABLE != KQ_SUPPORT
450: sched_SetErr(ENOTSUP, "disabled kqueue support");
451: return -1;
452: #else
453: #ifndef EVFILT_USER
454: sched_SetErr(ENOTSUP, "Not supported kevent() filter");
455: return -1;
456: #else
457: struct kevent chg[1];
458: struct timespec timeout = { 0, 0 };
459:
460: if (!task || !TASK_ROOT(task))
461: return -1;
462:
463: #ifdef __NetBSD__
464: EV_SET(chg, TASK_VAL(task), EVFILT_USER, 0, NOTE_TRIGGER, 0, (intptr_t) TASK_VAL(task));
465: #else
466: EV_SET(chg, TASK_VAL(task), EVFILT_USER, 0, NOTE_TRIGGER, 0, (void*) TASK_VAL(task));
467: #endif
468: if (kevent(TASK_ROOT(task)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
469: LOGERR;
470: return -1;
471: }
472:
473: return 0;
474: #endif
475: #endif /* KQ_SUPPORT */
476: }
477:
478: /*
479: * schedQuery() - Query task in scheduler
480: *
481: * @task = task
482: * return: -1 error, 0 found and 1 not found
483: */
484: int
485: schedQuery(sched_task_t * __restrict task)
486: {
487: sched_queue_t *queue;
488: sched_task_t *t;
489:
490: if (!task || !TASK_ROOT(task))
491: return -1; /* error */
492:
493: switch (TASK_TYPE(task)) {
494: case taskREAD:
495: queue = &TASK_ROOT(task)->root_read;
496: break;
497: case taskWRITE:
498: queue = &TASK_ROOT(task)->root_write;
499: break;
500: case taskTIMER:
501: queue = &TASK_ROOT(task)->root_timer;
502: break;
503: case taskALARM:
504: queue = &TASK_ROOT(task)->root_alarm;
505: break;
506: case taskRTC:
507: queue = &TASK_ROOT(task)->root_rtc;
508: break;
509: case taskNODE:
510: queue = &TASK_ROOT(task)->root_node;
511: break;
512: case taskPROC:
513: queue = &TASK_ROOT(task)->root_proc;
514: break;
515: case taskSIGNAL:
516: queue = &TASK_ROOT(task)->root_signal;
517: break;
518: case taskAIO:
519: queue = &TASK_ROOT(task)->root_aio;
520: break;
521: case taskLIO:
522: queue = &TASK_ROOT(task)->root_lio;
523: break;
524: case taskUSER:
525: queue = &TASK_ROOT(task)->root_user;
526: break;
527: case taskEVENT:
528: queue = &TASK_ROOT(task)->root_event;
529: break;
530: case taskTASK:
531: queue = &TASK_ROOT(task)->root_task;
532: break;
533: case taskSUSPEND:
534: queue = &TASK_ROOT(task)->root_suspend;
535: break;
536: case taskREADY:
537: queue = &TASK_ROOT(task)->root_ready;
538: break;
539: case taskTHREAD:
540: queue = &TASK_ROOT(task)->root_thread;
541: break;
542: default:
543: return 1; /* not in queue */
544: }
545: if (queue)
546: TAILQ_FOREACH(t, queue, task_node)
547: if (TASK_ID(t) == TASK_ID(task))
548: return 0; /* found */
549:
550: return 1; /* not in queue */
551: }
552:
553: /*
554: * schedQueryby() - Query task in scheduler by criteria
555: *
556: * @root = root task
557: * @type = query from queue type, if =taskMAX query same task from all queues
558: * @criteria = find task by criteria
559: * [ CRITERIA_ANY|CRITERIA_CALL|CRITERIA_ARG|CRITERIA_FD|CRITERIA_VAL|
560: * CRITERIA_ID|CRITERIA_TS|CRITERIA_DATA|CRITERIA_DATLEN ]
561: * @param = search parameter
562: * return: -1 error, 0 found or 1 not found
563: */
564: int
565: schedQueryby(sched_root_task_t * __restrict root, sched_task_type_t type,
566: u_char criteria, void *param)
567: {
568: sched_task_t *task;
569: sched_queue_t *queue;
570: register int flg = 0;
571:
572: if (!root)
573: return -1;
574: /* if type == taskMAX check in all queues */
575: if (type == taskMAX) {
576: if ((flg = schedQueryby(root, taskREAD, criteria, param)) < 1)
577: return flg;
578: if ((flg = schedQueryby(root, taskWRITE, criteria, param)) < 1)
579: return flg;
580: if ((flg = schedQueryby(root, taskTIMER, criteria, param)) < 1)
581: return flg;
582: if ((flg = schedQueryby(root, taskALARM, criteria, param)) < 1)
583: return flg;
584: if ((flg = schedQueryby(root, taskRTC, criteria, param)) < 1)
585: return flg;
586: if ((flg = schedQueryby(root, taskNODE, criteria, param)) < 1)
587: return flg;
588: if ((flg = schedQueryby(root, taskPROC, criteria, param)) < 1)
589: return flg;
590: if ((flg = schedQueryby(root, taskSIGNAL, criteria, param)) < 1)
591: return flg;
592: if ((flg = schedQueryby(root, taskAIO, criteria, param)) < 1)
593: return flg;
594: if ((flg = schedQueryby(root, taskLIO, criteria, param)) < 1)
595: return flg;
596: if ((flg = schedQueryby(root, taskUSER, criteria, param)) < 1)
597: return flg;
598: if ((flg = schedQueryby(root, taskEVENT, criteria, param)) < 1)
599: return flg;
600: if ((flg = schedQueryby(root, taskTASK, criteria, param)) < 1)
601: return flg;
602: if ((flg = schedQueryby(root, taskSUSPEND, criteria, param)) < 1)
603: return flg;
604: if ((flg = schedQueryby(root, taskREADY, criteria, param)) < 1)
605: return flg;
606: if ((flg = schedQueryby(root, taskTHREAD, criteria, param)) < 1)
607: return flg;
608: return 1; /* not found */
609: }
610: /* choosen queue */
611: switch (type) {
612: case taskREAD:
613: queue = &root->root_read;
614: break;
615: case taskWRITE:
616: queue = &root->root_write;
617: break;
618: case taskTIMER:
619: queue = &root->root_timer;
620: break;
621: case taskALARM:
622: queue = &root->root_alarm;
623: break;
624: case taskRTC:
625: queue = &root->root_rtc;
626: break;
627: case taskNODE:
628: queue = &root->root_node;
629: break;
630: case taskPROC:
631: queue = &root->root_proc;
632: break;
633: case taskSIGNAL:
634: queue = &root->root_signal;
635: break;
636: case taskAIO:
637: queue = &root->root_aio;
638: break;
639: case taskLIO:
640: queue = &root->root_lio;
641: break;
642: case taskUSER:
643: queue = &root->root_user;
644: break;
645: case taskEVENT:
646: queue = &root->root_event;
647: break;
648: case taskTASK:
649: queue = &root->root_task;
650: break;
651: case taskSUSPEND:
652: queue = &root->root_suspend;
653: break;
654: case taskREADY:
655: queue = &root->root_ready;
656: break;
657: case taskTHREAD:
658: queue = &root->root_thread;
659: break;
660: default:
661: return 1; /* not found */
662: }
663:
664: TAILQ_FOREACH(task, queue, task_node) {
665: switch (criteria) {
666: case CRITERIA_ANY:
667: return 0; /* found */
668: case CRITERIA_CALL:
669: if (TASK_FUNC(task) == (sched_task_func_t) param)
670: return 0; /* found */
671: break;
672: case CRITERIA_ARG:
673: if (TASK_ARG(task) == param)
674: return 0; /* found */
675: break;
676: case CRITERIA_FD:
677: if (TASK_FD(task) == (intptr_t) param)
678: return 0; /* found */
679: break;
680: case CRITERIA_ID:
681: case CRITERIA_VAL:
682: if (TASK_VAL(task) == (u_long) param)
683: return 0; /* found */
684: break;
685: case CRITERIA_TS:
686: if (!sched_timespeccmp(&TASK_TS(task),
687: (struct timespec*) param, -))
688: return 0; /* found */
689: break;
690: case CRITERIA_DATA:
691: if (TASK_DATA(task) == param)
692: return 0; /* found */
693: break;
694: case CRITERIA_DATLEN:
695: if (TASK_DATLEN(task) == (size_t) param)
696: return 0; /* found */
697: break;
698: default:
699: sched_SetErr(EINVAL, "Invalid parameter criteria %d",
700: criteria);
701: return 1; /* not found */
702: }
703: }
704:
705: return 1; /* not found */
706: }
707:
708: /*
709: * schedCancel() - Cancel task from scheduler
710: *
711: * @task = task
712: * return: -1 error or 0 ok
713: */
714: int
715: schedCancel(sched_task_t * __restrict task)
716: {
717: sched_queue_t *queue;
718:
719: if (!task || !TASK_ROOT(task))
720: return -1;
721:
722: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel)
723: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel(task, NULL))
724: return -1;
725:
726: switch (TASK_TYPE(task)) {
727: case taskREAD:
728: queue = &TASK_ROOT(task)->root_read;
729: break;
730: case taskWRITE:
731: queue = &TASK_ROOT(task)->root_write;
732: break;
733: case taskTIMER:
734: queue = &TASK_ROOT(task)->root_timer;
735: break;
736: case taskALARM:
737: queue = &TASK_ROOT(task)->root_alarm;
738: break;
739: case taskRTC:
740: queue = &TASK_ROOT(task)->root_rtc;
741: break;
742: case taskNODE:
743: queue = &TASK_ROOT(task)->root_node;
744: break;
745: case taskPROC:
746: queue = &TASK_ROOT(task)->root_proc;
747: break;
748: case taskSIGNAL:
749: queue = &TASK_ROOT(task)->root_signal;
750: break;
751: case taskAIO:
752: queue = &TASK_ROOT(task)->root_aio;
753: break;
754: case taskLIO:
755: queue = &TASK_ROOT(task)->root_lio;
756: break;
757: case taskUSER:
758: queue = &TASK_ROOT(task)->root_user;
759: break;
760: case taskEVENT:
761: queue = &TASK_ROOT(task)->root_event;
762: break;
763: case taskTASK:
764: queue = &TASK_ROOT(task)->root_task;
765: break;
766: case taskSUSPEND:
767: queue = &TASK_ROOT(task)->root_suspend;
768: break;
769: case taskREADY:
770: queue = &TASK_ROOT(task)->root_ready;
771: break;
772: case taskTHREAD:
773: queue = &TASK_ROOT(task)->root_thread;
774: break;
775: default:
776: queue = NULL;
777: }
778: if (queue)
779: remove_task_from(task, queue);
780: if (TASK_TYPE(task) != taskUNUSE)
781: sched_unuseTask(task);
782:
783: return 0;
784: }
785:
786: /*
787: * schedCancelby() - Cancel task from scheduler by criteria
788: *
789: * @root = root task
790: * @type = cancel from queue type, if =taskMAX cancel same task from all queues
791: * @criteria = find task by criteria
792: * [ CRITERIA_ANY|CRITERIA_CALL|CRITERIA_ARG|CRITERIA_FD|CRITERIA_VAL|
793: * CRITERIA_ID|CRITERIA_TS|CRITERIA_DATA|CRITERIA_DATLEN ]
794: * @param = search parameter
795: * @hook = custom cleanup hook function, may be NULL
796: * return: -1 error, -2 error in sub-stage cancel execution, -3 error from custom hook or 0 ok
797: */
798: int
799: schedCancelby(sched_root_task_t * __restrict root, sched_task_type_t type,
800: u_char criteria, void *param, sched_hook_func_t hook)
801: {
802: sched_task_t *task, *tmp;
803: sched_queue_t *queue;
804: register int flg = 0;
805:
806: if (!root)
807: return -1;
808: /* if type == taskMAX check in all queues */
809: if (type == taskMAX) {
810: if (schedCancelby(root, taskREAD, criteria, param, hook))
811: return -2;
812: if (schedCancelby(root, taskWRITE, criteria, param, hook))
813: return -2;
814: if (schedCancelby(root, taskTIMER, criteria, param, hook))
815: return -2;
816: if (schedCancelby(root, taskALARM, criteria, param, hook))
817: return -2;
818: if (schedCancelby(root, taskRTC, criteria, param, hook))
819: return -2;
820: if (schedCancelby(root, taskNODE, criteria, param, hook))
821: return -2;
822: if (schedCancelby(root, taskPROC, criteria, param, hook))
823: return -2;
824: if (schedCancelby(root, taskSIGNAL, criteria, param, hook))
825: return -2;
826: if (schedCancelby(root, taskAIO, criteria, param, hook))
827: return -2;
828: if (schedCancelby(root, taskLIO, criteria, param, hook))
829: return -2;
830: if (schedCancelby(root, taskUSER, criteria, param, hook))
831: return -2;
832: if (schedCancelby(root, taskEVENT, criteria, param, hook))
833: return -2;
834: if (schedCancelby(root, taskTASK, criteria, param, hook))
835: return -2;
836: if (schedCancelby(root, taskSUSPEND, criteria, param, hook))
837: return -2;
838: if (schedCancelby(root, taskREADY, criteria, param, hook))
839: return -2;
840: if (schedCancelby(root, taskTHREAD, criteria, param, hook))
841: return -2;
842: return 0;
843: }
844: /* choosen queue */
845: switch (type) {
846: case taskREAD:
847: queue = &root->root_read;
848: break;
849: case taskWRITE:
850: queue = &root->root_write;
851: break;
852: case taskTIMER:
853: queue = &root->root_timer;
854: break;
855: case taskALARM:
856: queue = &root->root_alarm;
857: break;
858: case taskRTC:
859: queue = &root->root_rtc;
860: break;
861: case taskNODE:
862: queue = &root->root_node;
863: break;
864: case taskPROC:
865: queue = &root->root_proc;
866: break;
867: case taskSIGNAL:
868: queue = &root->root_signal;
869: break;
870: case taskAIO:
871: queue = &root->root_aio;
872: break;
873: case taskLIO:
874: queue = &root->root_lio;
875: break;
876: case taskUSER:
877: queue = &root->root_user;
878: break;
879: case taskEVENT:
880: queue = &root->root_event;
881: break;
882: case taskTASK:
883: queue = &root->root_task;
884: break;
885: case taskSUSPEND:
886: queue = &root->root_suspend;
887: break;
888: case taskREADY:
889: queue = &root->root_ready;
890: break;
891: case taskTHREAD:
892: queue = &root->root_thread;
893: break;
894: default:
895: return 0;
896: }
897:
898: SCHED_QLOCK(root, type);
899: TAILQ_FOREACH_SAFE(task, queue, task_node, tmp) {
900: flg ^= flg;
901: switch (criteria) {
902: case CRITERIA_ANY:
903: flg = 1;
904: break;
905: case CRITERIA_CALL:
906: if (TASK_FUNC(task) == (sched_task_func_t) param)
907: flg = 1;
908: break;
909: case CRITERIA_ARG:
910: if (TASK_ARG(task) == param)
911: flg = 1;
912: break;
913: case CRITERIA_FD:
914: if (TASK_FD(task) == (intptr_t) param)
915: flg = 1;
916: break;
917: case CRITERIA_ID:
918: case CRITERIA_VAL:
919: if (TASK_VAL(task) == (u_long) param)
920: flg = 1;
921: break;
922: case CRITERIA_TS:
923: if (!sched_timespeccmp(&TASK_TS(task), (struct timespec*) param, -))
924: flg = 1;
925: break;
926: case CRITERIA_DATA:
927: if (TASK_DATA(task) == param)
928: flg = 1;
929: break;
930: case CRITERIA_DATLEN:
931: if (TASK_DATLEN(task) == (size_t) param)
932: flg = 1;
933: break;
934: default:
935: sched_SetErr(EINVAL, "Invalid parameter criteria %d", criteria);
936: flg = -1;
937: }
938: if (flg < 0) /* error */
939: break;
940: /* cancel choosen task */
941: if (flg > 0) {
942: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel)
943: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel(task, NULL)) {
944: flg = -1;
945: break;
946: }
947: /* custom hook */
948: if (hook)
949: if (hook(task, NULL)) {
950: flg = -3;
951: break;
952: }
953:
954: TAILQ_REMOVE(queue, task, task_node);
955: if (TASK_TYPE(task) != taskUNUSE)
956: sched_unuseTask(task);
957:
958: flg ^= flg; /* ok */
959: }
960: }
961: SCHED_QUNLOCK(root, type);
962:
963: return flg;
964: }
965:
966: /*
967: * schedRun() - Scheduler *run loop*
968: *
969: * @root = root task
970: * @killState = kill condition variable, if !=0 stop scheduler loop
971: * return: -1 error or 0 ok
972: */
973: int
974: schedRun(sched_root_task_t *root, volatile intptr_t * __restrict killState)
975: {
976: sched_task_t *task;
977:
978: if (!root)
979: return -1;
980:
981: if (root->root_hooks.hook_exec.run)
982: if (root->root_hooks.hook_exec.run(root, NULL))
983: return -1;
984:
985: if (killState) {
986: if (root->root_hooks.hook_exec.condition)
987: /* condition scheduler loop */
988: while (root && root->root_hooks.hook_exec.fetch &&
989: root->root_hooks.hook_exec.condition &&
990: root->root_hooks.hook_exec.condition(root, (void*) killState)) {
991: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
992: root->root_ret = schedCall(task);
993: }
994: else
995: /* trigger scheduler loop */
996: while (!*killState && root && root->root_hooks.hook_exec.fetch) {
997: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
998: root->root_ret = schedCall(task);
999: }
1000: } else
1001: /* infinite scheduler loop */
1002: while (root && root->root_hooks.hook_exec.fetch)
1003: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
1004: root->root_ret = schedCall(task);
1005:
1006: return 0;
1007: }
1008:
1009: /*
1010: * schedPolling() - Polling timeout period if no timer task is present
1011: *
1012: * @root = root task
1013: * @ts = timeout polling period, if ==NULL INFINIT timeout
1014: * @tsold = old timeout polling if !=NULL
1015: * return: -1 error or 0 ok
1016: */
1017: int
1018: schedPolling(sched_root_task_t * __restrict root, struct timespec * __restrict ts,
1019: struct timespec * __restrict tsold)
1020: {
1021: if (!root)
1022: return -1;
1023:
1024: if (tsold)
1025: *tsold = root->root_poll;
1026:
1027: if (!ts)
1028: sched_timespecinf(&root->root_poll);
1029: else
1030: root->root_poll = *ts;
1031:
1032: return 0;
1033: }
1034:
1035: /*
1036: * schedTermCondition() - Activate hook for scheduler condition kill
1037: *
1038: * @root = root task
1039: * @condValue = condition value, kill schedRun() if condValue == killState
1040: * return: -1 error or 0 ok
1041: */
1042: int
1043: schedTermCondition(sched_root_task_t * __restrict root, intptr_t * __restrict condValue)
1044: {
1045: if (!root && !condValue)
1046: return -1;
1047:
1048: *root->root_cond = *condValue;
1049: root->root_hooks.hook_exec.condition = sched_hook_condition;
1050: return 0;
1051: }
1052:
1053: /*
1054: * schedResumeby() - Resume suspended task
1055: *
1056: * @root = root task
1057: * @criteria = find task by criteria
1058: * [CRITERIA_ANY|CRITERIA_ID|CRITERIA_VAL|CRITERIA_DATA]
1059: * @param = search parameter (sched_task_t *task| unsigned long id)
1060: * return: -1 error or 0 resumed ok
1061: */
1062: int
1063: schedResumeby(sched_root_task_t * __restrict root, u_char criteria, void *param)
1064: {
1065: sched_task_t *task, *tmp;
1066: register int flg = 0;
1067:
1068: if (!root)
1069: return -1;
1070:
1071: SCHED_QLOCK(root, taskSUSPEND);
1072: TAILQ_FOREACH_SAFE(task, &root->root_suspend, task_node, tmp) {
1073: flg ^= flg;
1074: switch (criteria) {
1075: case CRITERIA_ANY:
1076: flg = 1;
1077: break;
1078: case CRITERIA_ID:
1079: case CRITERIA_VAL:
1080: if (TASK_VAL(task) == (u_long) param)
1081: flg = 1;
1082: break;
1083: case CRITERIA_DATA:
1084: if (TASK_ID(task) == (sched_task_t*) param)
1085: flg = 1;
1086: break;
1087: default:
1088: sched_SetErr(EINVAL, "Invalid parameter criteria %d", criteria);
1089: flg = -1;
1090: }
1091: if (flg < 0)
1092: break;
1093: /* resume choosen task */
1094: if (flg > 0) {
1095: if (root->root_hooks.hook_exec.resume)
1096: if (root->root_hooks.hook_exec.resume(task, NULL)) {
1097: flg = -1;
1098: break;
1099: }
1100:
1101: TAILQ_REMOVE(&root->root_suspend, task, task_node);
1102:
1103: task->task_type = taskREADY;
1104: insert_task_to(task, &root->root_ready);
1105:
1106: flg ^= flg; /* ok */
1107: }
1108: }
1109: SCHED_QUNLOCK(root, taskSUSPEND);
1110:
1111: return flg;
1112: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>