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.23.2.1 2014/01/27 16:52:56 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, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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: /* Init and prepare scheduler functions */
86:
87: /*
88: * schedRegisterHooks() - Register IO handles and bind tasks to it
89: *
90: * @root = root task
91: * return: -1 error or 0 ok
92: */
93: int
94: schedRegisterHooks(sched_root_task_t * __restrict root)
95: {
96: assert(root);
97:
98: if (root->root_hooks.hook_root.fini)
99: root->root_hooks.hook_root.fini(root, NULL);
100: memset(&root->root_hooks, 0, sizeof root->root_hooks);
101:
102: root->root_hooks.hook_add.read = sched_hook_read;
103: root->root_hooks.hook_add.write = sched_hook_write;
104: root->root_hooks.hook_add.alarm = sched_hook_alarm;
105: #if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
106: root->root_hooks.hook_add.rtc = sched_hook_rtc;
107: #endif
108: root->root_hooks.hook_add.node = sched_hook_node;
109: root->root_hooks.hook_add.proc = sched_hook_proc;
110: root->root_hooks.hook_add.signal = sched_hook_signal;
111: #ifdef EVFILT_USER
112: root->root_hooks.hook_add.user = sched_hook_user;
113: #endif
114: #ifdef HAVE_LIBPTHREAD
115: root->root_hooks.hook_add.thread = sched_hook_thread;
116: #endif
117:
118: root->root_hooks.hook_exec.cancel = sched_hook_cancel;
119: root->root_hooks.hook_exec.fetch = sched_hook_fetch;
120: root->root_hooks.hook_exec.exception = sched_hook_exception;
121:
122: root->root_hooks.hook_root.init = sched_hook_init;
123: root->root_hooks.hook_root.fini = sched_hook_fini;
124: return 0;
125: }
126:
127: /*
128: * schedInit() - Init scheduler
129: *
130: * @data = optional data if !=NULL
131: * @datlen = data len if data is set
132: * return: allocated root task if ok or NULL error
133: */
134: sched_root_task_t *
135: schedInit(void ** __restrict data, size_t datlen)
136: {
137: sched_root_task_t *root = NULL;
138: int (*func)(sched_root_task_t *);
139: #ifdef HAVE_LIBPTHREAD
140: register int i;
141: #endif
142:
143: root = malloc(sizeof(sched_root_task_t));
144: if (!root) {
145: LOGERR;
146: } else {
147: memset(root, 0, sizeof(sched_root_task_t));
148:
149: /* set default maximum regular task hit misses */
150: root->root_miss = MAX_TASK_MISS;
151:
152: /* INFINIT polling period by default */
153: #ifndef KQ_DISABLE
154: sched_timespecinf(&root->root_poll);
155: #else
156: sched_timevalinf(&root->root_poll);
157: #endif
158:
159: #ifdef HAVE_LIBPTHREAD
160: for (i = 0; i < taskMAX; i++)
161: if ((errno = pthread_mutex_init(&root->root_mtx[i], NULL))) {
162: LOGERR;
163: while (i)
164: pthread_mutex_destroy(&root->root_mtx[--i]);
165: free(root);
166: return NULL;
167: }
168:
169: for (i = 0; i < taskMAX; i++)
170: pthread_mutex_lock(&root->root_mtx[i]);
171: #endif
172:
173: TAILQ_INIT(&root->root_read);
174: TAILQ_INIT(&root->root_write);
175: TAILQ_INIT(&root->root_timer);
176: TAILQ_INIT(&root->root_alarm);
177: TAILQ_INIT(&root->root_rtc);
178: TAILQ_INIT(&root->root_node);
179: TAILQ_INIT(&root->root_proc);
180: TAILQ_INIT(&root->root_signal);
181: TAILQ_INIT(&root->root_aio);
182: TAILQ_INIT(&root->root_lio);
183: TAILQ_INIT(&root->root_user);
184: TAILQ_INIT(&root->root_event);
185: TAILQ_INIT(&root->root_task);
186: TAILQ_INIT(&root->root_suspend);
187: TAILQ_INIT(&root->root_ready);
188: TAILQ_INIT(&root->root_unuse);
189: TAILQ_INIT(&root->root_thread);
190:
191: #ifdef HAVE_LIBPTHREAD
192: for (i = 0; i < taskMAX; i++)
193: pthread_mutex_unlock(&root->root_mtx[i]);
194: #endif
195:
196: if (data && *data) {
197: if (datlen) {
198: root->root_data.iov_base = *data;
199: root->root_data.iov_len = datlen;
200: } else { /* if datlen == 0, switch to callbacks init mode */
201: /* little hack :) for correct initialization of scheduler */
202: func = (int(*)(sched_root_task_t*)) data;
203: func(root);
204: }
205: }
206:
207: if (root->root_hooks.hook_root.init)
208: root->root_hooks.hook_root.init(root, NULL);
209: }
210:
211: return root;
212: }
213:
214: /*
215: * schedEnd() - End scheduler & free all resources
216: *
217: * @root = root task
218: * return: -1 error or 0 ok
219: */
220: int
221: schedEnd(sched_root_task_t ** __restrict root)
222: {
223: sched_task_t *task, *tmp;
224: #ifdef HAVE_LIBPTHREAD
225: register int i;
226: #endif
227:
228: if (!root || !*root)
229: return -1;
230:
231: TAILQ_FOREACH_SAFE(task, &(*root)->root_read, task_node, tmp)
232: schedCancel(task);
233: TAILQ_FOREACH_SAFE(task, &(*root)->root_write, task_node, tmp)
234: schedCancel(task);
235: TAILQ_FOREACH_SAFE(task, &(*root)->root_timer, task_node, tmp)
236: schedCancel(task);
237: TAILQ_FOREACH_SAFE(task, &(*root)->root_alarm, task_node, tmp)
238: schedCancel(task);
239: TAILQ_FOREACH_SAFE(task, &(*root)->root_rtc, task_node, tmp)
240: schedCancel(task);
241: TAILQ_FOREACH_SAFE(task, &(*root)->root_node, task_node, tmp)
242: schedCancel(task);
243: TAILQ_FOREACH_SAFE(task, &(*root)->root_proc, task_node, tmp)
244: schedCancel(task);
245: TAILQ_FOREACH_SAFE(task, &(*root)->root_signal, task_node, tmp)
246: schedCancel(task);
247: TAILQ_FOREACH_SAFE(task, &(*root)->root_aio, task_node, tmp)
248: schedCancel(task);
249: TAILQ_FOREACH_SAFE(task, &(*root)->root_lio, task_node, tmp)
250: schedCancel(task);
251: TAILQ_FOREACH_SAFE(task, &(*root)->root_user, task_node, tmp)
252: schedCancel(task);
253: TAILQ_FOREACH_SAFE(task, &(*root)->root_event, task_node, tmp)
254: schedCancel(task);
255: TAILQ_FOREACH_SAFE(task, &(*root)->root_suspend, task_node, tmp)
256: schedCancel(task);
257: TAILQ_FOREACH_SAFE(task, &(*root)->root_ready, task_node, tmp)
258: schedCancel(task);
259: TAILQ_FOREACH_SAFE(task, &(*root)->root_thread, task_node, tmp)
260: schedCancel(task);
261: TAILQ_FOREACH_SAFE(task, &(*root)->root_task, task_node, tmp)
262: schedCancel(task);
263:
264: #ifdef HAVE_LIBPTHREAD
265: pthread_mutex_lock(&(*root)->root_mtx[taskUNUSE]);
266: #endif
267: TAILQ_FOREACH_SAFE(task, &(*root)->root_unuse, task_node, tmp) {
268: TAILQ_REMOVE(&(*root)->root_unuse, task, task_node);
269: free(task);
270: }
271: #ifdef HAVE_LIBPTHREAD
272: pthread_mutex_unlock(&(*root)->root_mtx[taskUNUSE]);
273: #endif
274:
275: if ((*root)->root_hooks.hook_root.fini)
276: (*root)->root_hooks.hook_root.fini(*root, NULL);
277:
278: #ifdef HAVE_LIBPTHREAD
279: for (i = 0; i < taskMAX; i++)
280: pthread_mutex_destroy(&(*root)->root_mtx[i]);
281: #endif
282:
283: free(*root);
284: *root = NULL;
285: return 0;
286: }
287:
288: /*
289: * schedCall() - Call task execution function
290: *
291: * @task = current task
292: * return: !=NULL error or =NULL ok
293: */
294: void *
295: schedCall(sched_task_t * __restrict task)
296: {
297: void *ptr = (void*) -1;
298:
299: if (!task)
300: return ptr;
301:
302: if (!TASK_ISLOCKED(task))
303: TASK_LOCK(task);
304:
305: ptr = task->task_func(task);
306:
307: TASK_UNLOCK(task);
308: return ptr;
309: }
310:
311: /*
312: * schedFetch() - Fetch ready task
313: *
314: * @root = root task
315: * return: =NULL error or !=NULL ready task
316: */
317: void *
318: schedFetch(sched_root_task_t * __restrict root)
319: {
320: void *ptr;
321:
322: if (!root)
323: return NULL;
324:
325: if (root->root_hooks.hook_exec.fetch)
326: ptr = root->root_hooks.hook_exec.fetch(root, NULL);
327: else
328: ptr = NULL;
329:
330: return ptr;
331: }
332:
333: /*
334: * schedTrigger() - Triggering USER task
335: *
336: * @task = task
337: * return: -1 error or 0 ok
338: */
339: int
340: schedTrigger(sched_task_t * __restrict task)
341: {
342: #ifndef EVFILT_USER
343: sched_SetErr(ENOTSUP, "Not supported kevent() filter");
344: return -1;
345: #else
346: struct kevent chg[1];
347: struct timespec timeout = { 0, 0 };
348:
349: if (!task || !TASK_ROOT(task))
350: return -1;
351:
352: #ifdef __NetBSD__
353: EV_SET(chg, TASK_VAL(task), EVFILT_USER, 0, NOTE_TRIGGER, 0, (intptr_t) TASK_VAL(task));
354: #else
355: EV_SET(chg, TASK_VAL(task), EVFILT_USER, 0, NOTE_TRIGGER, 0, (void*) TASK_VAL(task));
356: #endif
357: if (kevent(TASK_ROOT(task)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
358: LOGERR;
359: return -1;
360: }
361:
362: return 0;
363: #endif
364: }
365:
366: /*
367: * schedQuery() - Query task in scheduler
368: *
369: * @task = task
370: * return: -1 error, 0 found and 1 not found
371: */
372: int
373: schedQuery(sched_task_t * __restrict task)
374: {
375: sched_queue_t *queue;
376: sched_task_t *t;
377:
378: if (!task || !TASK_ROOT(task))
379: return -1; /* error */
380:
381: switch (TASK_TYPE(task)) {
382: case taskREAD:
383: queue = &TASK_ROOT(task)->root_read;
384: break;
385: case taskWRITE:
386: queue = &TASK_ROOT(task)->root_write;
387: break;
388: case taskTIMER:
389: queue = &TASK_ROOT(task)->root_timer;
390: break;
391: case taskALARM:
392: queue = &TASK_ROOT(task)->root_alarm;
393: break;
394: case taskRTC:
395: queue = &TASK_ROOT(task)->root_rtc;
396: break;
397: case taskNODE:
398: queue = &TASK_ROOT(task)->root_node;
399: break;
400: case taskPROC:
401: queue = &TASK_ROOT(task)->root_proc;
402: break;
403: case taskSIGNAL:
404: queue = &TASK_ROOT(task)->root_signal;
405: break;
406: case taskAIO:
407: queue = &TASK_ROOT(task)->root_aio;
408: break;
409: case taskLIO:
410: queue = &TASK_ROOT(task)->root_lio;
411: break;
412: case taskUSER:
413: queue = &TASK_ROOT(task)->root_user;
414: break;
415: case taskEVENT:
416: queue = &TASK_ROOT(task)->root_event;
417: break;
418: case taskTASK:
419: queue = &TASK_ROOT(task)->root_task;
420: break;
421: case taskSUSPEND:
422: queue = &TASK_ROOT(task)->root_suspend;
423: break;
424: case taskREADY:
425: queue = &TASK_ROOT(task)->root_ready;
426: break;
427: case taskTHREAD:
428: queue = &TASK_ROOT(task)->root_thread;
429: break;
430: default:
431: return 1; /* not in queue */
432: }
433: if (queue)
434: TAILQ_FOREACH(t, queue, task_node)
435: if (TASK_ID(t) == TASK_ID(task))
436: return 0; /* found */
437:
438: return 1; /* not in queue */
439: }
440:
441: /*
442: * schedQueryby() - Query task in scheduler by criteria
443: *
444: * @root = root task
445: * @type = query from queue type, if =taskMAX query same task from all queues
446: * @criteria = find task by criteria
447: * [ CRITERIA_ANY|CRITERIA_CALL|CRITERIA_ARG|CRITERIA_FD|CRITERIA_VAL|
448: * CRITERIA_ID|CRITERIA_TS|CRITERIA_DATA|CRITERIA_DATLEN ]
449: * @param = search parameter
450: * return: -1 error, 0 found or 1 not found
451: */
452: int
453: schedQueryby(sched_root_task_t * __restrict root, sched_task_type_t type,
454: u_char criteria, void *param)
455: {
456: sched_task_t *task;
457: sched_queue_t *queue;
458: register int flg = 0;
459:
460: if (!root)
461: return -1;
462: /* if type == taskMAX check in all queues */
463: if (type == taskMAX) {
464: if ((flg = schedQueryby(root, taskREAD, criteria, param)) < 1)
465: return flg;
466: if ((flg = schedQueryby(root, taskWRITE, criteria, param)) < 1)
467: return flg;
468: if ((flg = schedQueryby(root, taskTIMER, criteria, param)) < 1)
469: return flg;
470: if ((flg = schedQueryby(root, taskALARM, criteria, param)) < 1)
471: return flg;
472: if ((flg = schedQueryby(root, taskRTC, criteria, param)) < 1)
473: return flg;
474: if ((flg = schedQueryby(root, taskNODE, criteria, param)) < 1)
475: return flg;
476: if ((flg = schedQueryby(root, taskPROC, criteria, param)) < 1)
477: return flg;
478: if ((flg = schedQueryby(root, taskSIGNAL, criteria, param)) < 1)
479: return flg;
480: if ((flg = schedQueryby(root, taskAIO, criteria, param)) < 1)
481: return flg;
482: if ((flg = schedQueryby(root, taskLIO, criteria, param)) < 1)
483: return flg;
484: if ((flg = schedQueryby(root, taskUSER, criteria, param)) < 1)
485: return flg;
486: if ((flg = schedQueryby(root, taskEVENT, criteria, param)) < 1)
487: return flg;
488: if ((flg = schedQueryby(root, taskTASK, criteria, param)) < 1)
489: return flg;
490: if ((flg = schedQueryby(root, taskSUSPEND, criteria, param)) < 1)
491: return flg;
492: if ((flg = schedQueryby(root, taskREADY, criteria, param)) < 1)
493: return flg;
494: if ((flg = schedQueryby(root, taskTHREAD, criteria, param)) < 1)
495: return flg;
496: return 1; /* not found */
497: }
498: /* choosen queue */
499: switch (type) {
500: case taskREAD:
501: queue = &root->root_read;
502: break;
503: case taskWRITE:
504: queue = &root->root_write;
505: break;
506: case taskTIMER:
507: queue = &root->root_timer;
508: break;
509: case taskALARM:
510: queue = &root->root_alarm;
511: break;
512: case taskRTC:
513: queue = &root->root_rtc;
514: break;
515: case taskNODE:
516: queue = &root->root_node;
517: break;
518: case taskPROC:
519: queue = &root->root_proc;
520: break;
521: case taskSIGNAL:
522: queue = &root->root_signal;
523: break;
524: case taskAIO:
525: queue = &root->root_aio;
526: break;
527: case taskLIO:
528: queue = &root->root_lio;
529: break;
530: case taskUSER:
531: queue = &root->root_user;
532: break;
533: case taskEVENT:
534: queue = &root->root_event;
535: break;
536: case taskTASK:
537: queue = &root->root_task;
538: break;
539: case taskSUSPEND:
540: queue = &root->root_suspend;
541: break;
542: case taskREADY:
543: queue = &root->root_ready;
544: break;
545: case taskTHREAD:
546: queue = &root->root_thread;
547: break;
548: default:
549: return 1; /* not found */
550: }
551:
552: TAILQ_FOREACH(task, queue, task_node) {
553: switch (criteria) {
554: case CRITERIA_ANY:
555: return 0; /* found */
556: case CRITERIA_CALL:
557: if (TASK_FUNC(task) == (sched_task_func_t) param)
558: return 0; /* found */
559: break;
560: case CRITERIA_ARG:
561: if (TASK_ARG(task) == param)
562: return 0; /* found */
563: break;
564: case CRITERIA_FD:
565: if (TASK_FD(task) == (intptr_t) param)
566: return 0; /* found */
567: break;
568: case CRITERIA_ID:
569: case CRITERIA_VAL:
570: if (TASK_VAL(task) == (u_long) param)
571: return 0; /* found */
572: break;
573: case CRITERIA_TS:
574: if (!sched_timespeccmp(&TASK_TS(task),
575: (struct timespec*) param, -))
576: return 0; /* found */
577: break;
578: case CRITERIA_DATA:
579: if (TASK_DATA(task) == param)
580: return 0; /* found */
581: break;
582: case CRITERIA_DATLEN:
583: if (TASK_DATLEN(task) == (size_t) param)
584: return 0; /* found */
585: break;
586: default:
587: sched_SetErr(EINVAL, "Invalid parameter criteria %d",
588: criteria);
589: return 1; /* not found */
590: }
591: }
592:
593: return 1; /* not found */
594: }
595:
596: /*
597: * schedCancel() - Cancel task from scheduler
598: *
599: * @task = task
600: * return: -1 error or 0 ok
601: */
602: int
603: schedCancel(sched_task_t * __restrict task)
604: {
605: sched_queue_t *queue;
606:
607: if (!task || !TASK_ROOT(task))
608: return -1;
609:
610: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel)
611: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel(task, NULL))
612: return -1;
613:
614: switch (TASK_TYPE(task)) {
615: case taskREAD:
616: queue = &TASK_ROOT(task)->root_read;
617: break;
618: case taskWRITE:
619: queue = &TASK_ROOT(task)->root_write;
620: break;
621: case taskTIMER:
622: queue = &TASK_ROOT(task)->root_timer;
623: break;
624: case taskALARM:
625: queue = &TASK_ROOT(task)->root_alarm;
626: break;
627: case taskRTC:
628: queue = &TASK_ROOT(task)->root_rtc;
629: break;
630: case taskNODE:
631: queue = &TASK_ROOT(task)->root_node;
632: break;
633: case taskPROC:
634: queue = &TASK_ROOT(task)->root_proc;
635: break;
636: case taskSIGNAL:
637: queue = &TASK_ROOT(task)->root_signal;
638: break;
639: case taskAIO:
640: queue = &TASK_ROOT(task)->root_aio;
641: break;
642: case taskLIO:
643: queue = &TASK_ROOT(task)->root_lio;
644: break;
645: case taskUSER:
646: queue = &TASK_ROOT(task)->root_user;
647: break;
648: case taskEVENT:
649: queue = &TASK_ROOT(task)->root_event;
650: break;
651: case taskTASK:
652: queue = &TASK_ROOT(task)->root_task;
653: break;
654: case taskSUSPEND:
655: queue = &TASK_ROOT(task)->root_suspend;
656: break;
657: case taskREADY:
658: queue = &TASK_ROOT(task)->root_ready;
659: break;
660: case taskTHREAD:
661: queue = &TASK_ROOT(task)->root_thread;
662: break;
663: default:
664: queue = NULL;
665: }
666: if (queue) {
667: #ifdef HAVE_LIBPTHREAD
668: pthread_mutex_lock(&TASK_ROOT(task)->root_mtx[TASK_TYPE(task)]);
669: #endif
670: TAILQ_REMOVE(queue, TASK_ID(task), task_node);
671: #ifdef HAVE_LIBPTHREAD
672: pthread_mutex_unlock(&TASK_ROOT(task)->root_mtx[TASK_TYPE(task)]);
673: #endif
674: }
675: if (TASK_TYPE(task) != taskUNUSE)
676: sched_unuseTask(task);
677:
678: return 0;
679: }
680:
681: /*
682: * schedCancelby() - Cancel task from scheduler by criteria
683: *
684: * @root = root task
685: * @type = cancel from queue type, if =taskMAX cancel same task from all queues
686: * @criteria = find task by criteria
687: * [ CRITERIA_ANY|CRITERIA_CALL|CRITERIA_ARG|CRITERIA_FD|CRITERIA_VAL|
688: * CRITERIA_ID|CRITERIA_TS|CRITERIA_DATA|CRITERIA_DATLEN ]
689: * @param = search parameter
690: * @hook = custom cleanup hook function, may be NULL
691: * return: -1 error, -2 error in sub-stage cancel execution, -3 error from custom hook or 0 ok
692: */
693: int
694: schedCancelby(sched_root_task_t * __restrict root, sched_task_type_t type,
695: u_char criteria, void *param, sched_hook_func_t hook)
696: {
697: sched_task_t *task, *tmp;
698: sched_queue_t *queue;
699: register int flg = 0;
700:
701: if (!root)
702: return -1;
703: /* if type == taskMAX check in all queues */
704: if (type == taskMAX) {
705: if (schedCancelby(root, taskREAD, criteria, param, hook))
706: return -2;
707: if (schedCancelby(root, taskWRITE, criteria, param, hook))
708: return -2;
709: if (schedCancelby(root, taskTIMER, criteria, param, hook))
710: return -2;
711: if (schedCancelby(root, taskALARM, criteria, param, hook))
712: return -2;
713: if (schedCancelby(root, taskRTC, criteria, param, hook))
714: return -2;
715: if (schedCancelby(root, taskNODE, criteria, param, hook))
716: return -2;
717: if (schedCancelby(root, taskPROC, criteria, param, hook))
718: return -2;
719: if (schedCancelby(root, taskSIGNAL, criteria, param, hook))
720: return -2;
721: if (schedCancelby(root, taskAIO, criteria, param, hook))
722: return -2;
723: if (schedCancelby(root, taskLIO, criteria, param, hook))
724: return -2;
725: if (schedCancelby(root, taskUSER, criteria, param, hook))
726: return -2;
727: if (schedCancelby(root, taskEVENT, criteria, param, hook))
728: return -2;
729: if (schedCancelby(root, taskTASK, criteria, param, hook))
730: return -2;
731: if (schedCancelby(root, taskSUSPEND, criteria, param, hook))
732: return -2;
733: if (schedCancelby(root, taskREADY, criteria, param, hook))
734: return -2;
735: if (schedCancelby(root, taskTHREAD, criteria, param, hook))
736: return -2;
737: return 0;
738: }
739: /* choosen queue */
740: switch (type) {
741: case taskREAD:
742: queue = &root->root_read;
743: break;
744: case taskWRITE:
745: queue = &root->root_write;
746: break;
747: case taskTIMER:
748: queue = &root->root_timer;
749: break;
750: case taskALARM:
751: queue = &root->root_alarm;
752: break;
753: case taskRTC:
754: queue = &root->root_rtc;
755: break;
756: case taskNODE:
757: queue = &root->root_node;
758: break;
759: case taskPROC:
760: queue = &root->root_proc;
761: break;
762: case taskSIGNAL:
763: queue = &root->root_signal;
764: break;
765: case taskAIO:
766: queue = &root->root_aio;
767: break;
768: case taskLIO:
769: queue = &root->root_lio;
770: break;
771: case taskUSER:
772: queue = &root->root_user;
773: break;
774: case taskEVENT:
775: queue = &root->root_event;
776: break;
777: case taskTASK:
778: queue = &root->root_task;
779: break;
780: case taskSUSPEND:
781: queue = &root->root_suspend;
782: break;
783: case taskREADY:
784: queue = &root->root_ready;
785: break;
786: case taskTHREAD:
787: queue = &root->root_thread;
788: break;
789: default:
790: return 0;
791: }
792:
793: #ifdef HAVE_LIBPTHREAD
794: pthread_mutex_lock(&root->root_mtx[type]);
795: #endif
796: TAILQ_FOREACH_SAFE(task, queue, task_node, tmp) {
797: flg ^= flg;
798: switch (criteria) {
799: case CRITERIA_ANY:
800: flg = 1;
801: break;
802: case CRITERIA_CALL:
803: if (TASK_FUNC(task) == (sched_task_func_t) param)
804: flg = 1;
805: break;
806: case CRITERIA_ARG:
807: if (TASK_ARG(task) == param)
808: flg = 1;
809: break;
810: case CRITERIA_FD:
811: if (TASK_FD(task) == (intptr_t) param)
812: flg = 1;
813: break;
814: case CRITERIA_ID:
815: case CRITERIA_VAL:
816: if (TASK_VAL(task) == (u_long) param)
817: flg = 1;
818: break;
819: case CRITERIA_TS:
820: if (!sched_timespeccmp(&TASK_TS(task), (struct timespec*) param, -))
821: flg = 1;
822: break;
823: case CRITERIA_DATA:
824: if (TASK_DATA(task) == param)
825: flg = 1;
826: break;
827: case CRITERIA_DATLEN:
828: if (TASK_DATLEN(task) == (size_t) param)
829: flg = 1;
830: break;
831: default:
832: sched_SetErr(EINVAL, "Invalid parameter criteria %d", criteria);
833: flg = -1;
834: }
835: if (flg < 0) /* error */
836: break;
837: /* cancel choosen task */
838: if (flg > 0) {
839: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel)
840: if (TASK_ROOT(task)->root_hooks.hook_exec.cancel(task, NULL)) {
841: flg = -1;
842: break;
843: }
844: /* custom hook */
845: if (hook)
846: if (hook(task, NULL)) {
847: flg = -3;
848: break;
849: }
850:
851: TAILQ_REMOVE(queue, task, task_node);
852: if (TASK_TYPE(task) != taskUNUSE)
853: sched_unuseTask(task);
854:
855: flg ^= flg; /* ok */
856: }
857: }
858: #ifdef HAVE_LIBPTHREAD
859: pthread_mutex_unlock(&root->root_mtx[type]);
860: #endif
861: return flg;
862: }
863:
864: /*
865: * schedRun() - Scheduler *run loop*
866: *
867: * @root = root task
868: * @killState = kill condition variable, if !=0 stop scheduler loop
869: * return: -1 error or 0 ok
870: */
871: int
872: schedRun(sched_root_task_t *root, volatile intptr_t * __restrict killState)
873: {
874: sched_task_t *task;
875:
876: if (!root)
877: return -1;
878:
879: if (root->root_hooks.hook_exec.run)
880: if (root->root_hooks.hook_exec.run(root, NULL))
881: return -1;
882:
883: if (killState) {
884: if (root->root_hooks.hook_exec.condition)
885: /* condition scheduler loop */
886: while (root && root->root_hooks.hook_exec.fetch &&
887: root->root_hooks.hook_exec.condition &&
888: root->root_hooks.hook_exec.condition(root, (void*) killState)) {
889: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
890: root->root_ret = schedCall(task);
891: }
892: else
893: /* trigger scheduler loop */
894: while (!*killState && root && root->root_hooks.hook_exec.fetch) {
895: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
896: root->root_ret = schedCall(task);
897: }
898: } else
899: /* infinite scheduler loop */
900: while (root && root->root_hooks.hook_exec.fetch)
901: if ((task = root->root_hooks.hook_exec.fetch(root, NULL)))
902: root->root_ret = schedCall(task);
903:
904: return 0;
905: }
906:
907: /*
908: * schedPolling() - Polling timeout period if no timer task is present
909: *
910: * @root = root task
911: * @ts = timeout polling period, if ==NULL INFINIT timeout
912: * @tsold = old timeout polling if !=NULL
913: * return: -1 error or 0 ok
914: */
915: int
916: schedPolling(sched_root_task_t * __restrict root, struct timespec * __restrict ts,
917: struct timespec * __restrict tsold)
918: {
919: if (!root)
920: return -1;
921:
922: #ifndef KQ_DISABLE
923: if (tsold)
924: *tsold = root->root_poll;
925:
926: if (!ts)
927: sched_timespecinf(&root->root_poll);
928: else
929: root->root_poll = *ts;
930: #else
931: if (tsold)
932: sched_timeval2spec(&root->root_poll, tsold);
933:
934: if (!ts)
935: sched_timevalinf(&root->root_poll);
936: else
937: sched_timespec2val(ts, &root->root_poll);
938: #endif
939:
940: return 0;
941: }
942:
943: /*
944: * schedTermCondition() - Activate hook for scheduler condition kill
945: *
946: * @root = root task
947: * @condValue = condition value, kill schedRun() if condValue == killState
948: * return: -1 error or 0 ok
949: */
950: int
951: schedTermCondition(sched_root_task_t * __restrict root, intptr_t condValue)
952: {
953: if (!root)
954: return -1;
955:
956: root->root_cond = condValue;
957: root->root_hooks.hook_exec.condition = sched_hook_condition;
958: return 0;
959: }
960:
961: /*
962: * schedResumeby() - Resume suspended task
963: *
964: * @root = root task
965: * @criteria = find task by criteria
966: * [CRITERIA_ANY|CRITERIA_ID|CRITERIA_VAL|CRITERIA_DATA]
967: * @param = search parameter (sched_task_t *task| unsigned long id)
968: * return: -1 error or 0 resumed ok
969: */
970: int
971: schedResumeby(sched_root_task_t * __restrict root, u_char criteria, void *param)
972: {
973: sched_task_t *task, *tmp;
974: register int flg = 0;
975:
976: if (!root)
977: return -1;
978:
979: #ifdef HAVE_LIBPTHREAD
980: pthread_mutex_lock(&root->root_mtx[taskSUSPEND]);
981: #endif
982: TAILQ_FOREACH_SAFE(task, &root->root_suspend, task_node, tmp) {
983: flg ^= flg;
984: switch (criteria) {
985: case CRITERIA_ANY:
986: flg = 1;
987: break;
988: case CRITERIA_ID:
989: case CRITERIA_VAL:
990: if (TASK_VAL(task) == (u_long) param)
991: flg = 1;
992: break;
993: case CRITERIA_DATA:
994: if (TASK_ID(task) == (sched_task_t*) param)
995: flg = 1;
996: break;
997: default:
998: sched_SetErr(EINVAL, "Invalid parameter criteria %d", criteria);
999: flg = -1;
1000: }
1001: if (flg < 0)
1002: break;
1003: /* resume choosen task */
1004: if (flg > 0) {
1005: if (root->root_hooks.hook_exec.resume)
1006: if (root->root_hooks.hook_exec.resume(task, NULL)) {
1007: flg = -1;
1008: break;
1009: }
1010:
1011: TAILQ_REMOVE(&root->root_suspend, task, task_node);
1012:
1013: task->task_type = taskREADY;
1014: #ifdef HAVE_LIBPTHREAD
1015: pthread_mutex_lock(&root->root_mtx[taskREADY]);
1016: #endif
1017: TAILQ_INSERT_TAIL(&root->root_ready, task, task_node);
1018: #ifdef HAVE_LIBPTHREAD
1019: pthread_mutex_unlock(&root->root_mtx[taskREADY]);
1020: #endif
1021:
1022: flg ^= flg; /* ok */
1023: }
1024: }
1025: #ifdef HAVE_LIBPTHREAD
1026: pthread_mutex_unlock(&root->root_mtx[taskSUSPEND]);
1027: #endif
1028:
1029: return flg;
1030: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>