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