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: hooks.c,v 1.24 2013/11/14 21:37:27 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: /*
51: * sched_hook_init() - Default INIT hook
52: *
53: * @root = root task
54: * @arg = unused
55: * return: <0 errors and 0 ok
56: */
57: void *
58: sched_hook_init(void *root, void *arg __unused)
59: {
60: sched_root_task_t *r = root;
61:
62: if (!r)
63: return (void*) -1;
64:
65: r->root_kq = kqueue();
66: if (r->root_kq == -1) {
67: LOGERR;
68: return (void*) -1;
69: }
70:
71: return NULL;
72: }
73:
74: /*
75: * sched_hook_fini() - Default FINI hook
76: *
77: * @root = root task
78: * @arg = unused
79: * return: <0 errors and 0 ok
80: */
81: void *
82: sched_hook_fini(void *root, void *arg __unused)
83: {
84: sched_root_task_t *r = root;
85:
86: if (!r)
87: return (void*) -1;
88:
89: if (r->root_kq > 2) {
90: close(r->root_kq);
91: r->root_kq = 0;
92: }
93:
94: return NULL;
95: }
96:
97: /*
98: * sched_hook_cancel() - Default CANCEL hook
99: *
100: * @task = current task
101: * @arg = unused
102: * return: <0 errors and 0 ok
103: */
104: void *
105: sched_hook_cancel(void *task, void *arg __unused)
106: {
107: sched_task_t *t = task;
108: struct kevent chg[1];
109: struct timespec timeout = { 0, 0 };
110: #ifdef AIO_SUPPORT
111: struct aiocb *acb;
112: #ifdef EVFILT_LIO
113: register int i = 0;
114: struct aiocb **acbs;
115: #endif /* EVFILT_LIO */
116: #endif /* AIO_SUPPORT */
117:
118: if (!t || !TASK_ROOT(t))
119: return (void*) -1;
120:
121: switch (TASK_TYPE(t)) {
122: case taskREAD:
123: #ifdef __NetBSD__
124: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
125: #else
126: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (void*) TASK_FD(t));
127: #endif
128: break;
129: case taskWRITE:
130: #ifdef __NetBSD__
131: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
132: #else
133: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
134: #endif
135: break;
136: case taskALARM:
137: #ifdef __NetBSD__
138: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE,
139: 0, 0, (intptr_t) TASK_DATA(t));
140: #else
141: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE,
142: 0, 0, (void*) TASK_DATA(t));
143: #endif
144: break;
145: case taskNODE:
146: #ifdef __NetBSD__
147: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
148: #else
149: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
150: #endif
151: break;
152: case taskPROC:
153: #ifdef __NetBSD__
154: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
155: #else
156: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
157: #endif
158: break;
159: case taskSIGNAL:
160: #ifdef __NetBSD__
161: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
162: #else
163: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
164: #endif
165: /* restore signal */
166: signal(TASK_VAL(t), SIG_DFL);
167: break;
168: #ifdef AIO_SUPPORT
169: case taskAIO:
170: #ifdef __NetBSD__
171: EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
172: #else
173: EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
174: #endif
175: acb = (struct aiocb*) TASK_VAL(t);
176: if (acb) {
177: if (aio_cancel(acb->aio_fildes, acb) == AIO_CANCELED)
178: aio_return(acb);
179: free(acb);
180: TASK_VAL(t) = 0;
181: }
182: break;
183: #ifdef EVFILT_LIO
184: case taskLIO:
185: #ifdef __NetBSD__
186: EV_SET(&chg[0], TASK_VAL(t), EVFILT_LIO, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
187: #else
188: EV_SET(&chg[0], TASK_VAL(t), EVFILT_LIO, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
189: #endif
190: acbs = (struct aiocb**) TASK_VAL(t);
191: if (acbs) {
192: for (i = 0; i < TASK_DATLEN(t); i++) {
193: if (aio_cancel(acbs[i]->aio_fildes, acbs[i]) == AIO_CANCELED)
194: aio_return(acbs[i]);
195: free(acbs[i]);
196: }
197: free(acbs);
198: TASK_VAL(t) = 0;
199: }
200: break;
201: #endif /* EVFILT_LIO */
202: #endif /* AIO_SUPPORT */
203: #ifdef EVFILT_USER
204: case taskUSER:
205: #ifdef __NetBSD__
206: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
207: #else
208: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
209: #endif
210: break;
211: #endif /* EVFILT_USER */
212: case taskTHREAD:
213: #ifdef HAVE_LIBPTHREAD
214: pthread_cancel((pthread_t) TASK_VAL(t));
215: #endif
216: return NULL;
217: #if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
218: case taskRTC:
219: timer_delete((timer_t) TASK_FLAG(t));
220: schedCancel((sched_task_t*) TASK_RET(t));
221: return NULL;
222: #endif /* HAVE_TIMER_CREATE */
223: default:
224: return NULL;
225: }
226:
227: kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout);
228: return NULL;
229: }
230:
231: #ifdef HAVE_LIBPTHREAD
232: /*
233: * sched_hook_thread() - Default THREAD hook
234: *
235: * @task = current task
236: * @arg = pthread attributes
237: * return: <0 errors and 0 ok
238: */
239: void *
240: sched_hook_thread(void *task, void *arg)
241: {
242: sched_task_t *t = task;
243: pthread_t tid;
244: sigset_t s, o;
245:
246: if (!t || !TASK_ROOT(t))
247: return (void*) -1;
248:
249: sigfillset(&s);
250: pthread_sigmask(SIG_BLOCK, &s, &o);
251: if ((errno = pthread_create(&tid, (pthread_attr_t*) arg,
252: (void *(*)(void*)) _sched_threadWrapper, t))) {
253: LOGERR;
254: pthread_sigmask(SIG_SETMASK, &o, NULL);
255: return (void*) -1;
256: } else
257: TASK_VAL(t) = (u_long) tid;
258:
259: if (!TASK_ISLOCKED(t))
260: TASK_LOCK(t);
261:
262: pthread_sigmask(SIG_SETMASK, &o, NULL);
263: return NULL;
264: }
265: #endif
266:
267: /*
268: * sched_hook_read() - Default READ hook
269: *
270: * @task = current task
271: * @arg = unused
272: * return: <0 errors and 0 ok
273: */
274: void *
275: sched_hook_read(void *task, void *arg __unused)
276: {
277: sched_task_t *t = task;
278: struct kevent chg[1];
279: struct timespec timeout = { 0, 0 };
280:
281: if (!t || !TASK_ROOT(t))
282: return (void*) -1;
283:
284: #ifdef __NetBSD__
285: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
286: #else
287: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
288: #endif
289: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
290: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
291: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
292: else
293: LOGERR;
294: return (void*) -1;
295: }
296:
297: return NULL;
298: }
299:
300: /*
301: * sched_hook_write() - Default WRITE hook
302: *
303: * @task = current task
304: * @arg = unused
305: * return: <0 errors and 0 ok
306: */
307: void *
308: sched_hook_write(void *task, void *arg __unused)
309: {
310: sched_task_t *t = task;
311: struct kevent chg[1];
312: struct timespec timeout = { 0, 0 };
313:
314: if (!t || !TASK_ROOT(t))
315: return (void*) -1;
316:
317: #ifdef __NetBSD__
318: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
319: #else
320: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
321: #endif
322: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
323: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
324: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
325: else
326: LOGERR;
327: return (void*) -1;
328: }
329:
330: return NULL;
331: }
332:
333: /*
334: * sched_hook_alarm() - Default ALARM hook
335: *
336: * @task = current task
337: * @arg = unused
338: * return: <0 errors and 0 ok
339: */
340: void *
341: sched_hook_alarm(void *task, void *arg __unused)
342: {
343: sched_task_t *t = task;
344: struct kevent chg[1];
345: struct timespec timeout = { 0, 0 };
346:
347: if (!t || !TASK_ROOT(t))
348: return (void*) -1;
349:
350: #ifdef __NetBSD__
351: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_CLEAR, 0,
352: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
353: (intptr_t) TASK_DATA(t));
354: #else
355: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_CLEAR, 0,
356: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
357: (void*) TASK_DATA(t));
358: #endif
359: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
360: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
361: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
362: else
363: LOGERR;
364: return (void*) -1;
365: }
366:
367: return NULL;
368: }
369:
370: /*
371: * sched_hook_node() - Default NODE hook
372: *
373: * @task = current task
374: * @arg = unused
375: * return: <0 errors and 0 ok
376: */
377: void *
378: sched_hook_node(void *task, void *arg __unused)
379: {
380: sched_task_t *t = task;
381: struct kevent chg[1];
382: struct timespec timeout = { 0, 0 };
383:
384: if (!t || !TASK_ROOT(t))
385: return (void*) -1;
386:
387: #ifdef __NetBSD__
388: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
389: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
390: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (intptr_t) TASK_FD(t));
391: #else
392: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
393: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
394: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (void*) TASK_FD(t));
395: #endif
396: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
397: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
398: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
399: else
400: LOGERR;
401: return (void*) -1;
402: }
403:
404: return NULL;
405: }
406:
407: /*
408: * sched_hook_proc() - Default PROC hook
409: *
410: * @task = current task
411: * @arg = unused
412: * return: <0 errors and 0 ok
413: */
414: void *
415: sched_hook_proc(void *task, void *arg __unused)
416: {
417: sched_task_t *t = task;
418: struct kevent chg[1];
419: struct timespec timeout = { 0, 0 };
420:
421: if (!t || !TASK_ROOT(t))
422: return (void*) -1;
423:
424: #ifdef __NetBSD__
425: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
426: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (intptr_t) TASK_VAL(t));
427: #else
428: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
429: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (void*) TASK_VAL(t));
430: #endif
431: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
432: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
433: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
434: else
435: LOGERR;
436: return (void*) -1;
437: }
438:
439: return NULL;
440: }
441:
442: /*
443: * sched_hook_signal() - Default SIGNAL hook
444: *
445: * @task = current task
446: * @arg = unused
447: * return: <0 errors and 0 ok
448: */
449: void *
450: sched_hook_signal(void *task, void *arg __unused)
451: {
452: sched_task_t *t = task;
453: struct kevent chg[1];
454: struct timespec timeout = { 0, 0 };
455:
456: if (!t || !TASK_ROOT(t))
457: return (void*) -1;
458:
459: /* ignore signal */
460: signal(TASK_VAL(t), SIG_IGN);
461:
462: #ifdef __NetBSD__
463: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_VAL(t));
464: #else
465: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_VAL(t));
466: #endif
467: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
468: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
469: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
470: else
471: LOGERR;
472: return (void*) -1;
473: }
474:
475: return NULL;
476: }
477:
478: /*
479: * sched_hook_user() - Default USER hook
480: *
481: * @task = current task
482: * @arg = unused
483: * return: <0 errors and 0 ok
484: */
485: #ifdef EVFILT_USER
486: void *
487: sched_hook_user(void *task, void *arg __unused)
488: {
489: sched_task_t *t = task;
490: struct kevent chg[1];
491: struct timespec timeout = { 0, 0 };
492:
493: if (!t || !TASK_ROOT(t))
494: return (void*) -1;
495:
496: #ifdef __NetBSD__
497: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
498: 0, (intptr_t) TASK_VAL(t));
499: #else
500: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
501: 0, (void*) TASK_VAL(t));
502: #endif
503: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
504: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
505: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
506: else
507: LOGERR;
508: return (void*) -1;
509: }
510:
511: return NULL;
512: }
513: #endif
514:
515: /*
516: * sched_hook_fetch() - Default FETCH hook
517: *
518: * @root = root task
519: * @arg = unused
520: * return: NULL error or !=NULL fetched task
521: */
522: void *
523: sched_hook_fetch(void *root, void *arg __unused)
524: {
525: sched_root_task_t *r = root;
526: sched_task_t *task, *tmp;
527: struct timespec now, m, mtmp;
528: struct timespec *timeout;
529: struct kevent evt[1], res[KQ_EVENTS];
530: register int i, flg;
531: int en;
532: #ifdef AIO_SUPPORT
533: int len, fd;
534: struct aiocb *acb;
535: #ifdef EVFILT_LIO
536: int l;
537: register int j;
538: off_t off;
539: struct aiocb **acbs;
540: struct iovec *iv;
541: #endif /* EVFILT_LIO */
542: #endif /* AIO_SUPPORT */
543:
544: if (!r)
545: return NULL;
546:
547: /* get new task by queue priority */
548: while ((task = TAILQ_FIRST(&r->root_event))) {
549: #ifdef HAVE_LIBPTHREAD
550: pthread_mutex_lock(&r->root_mtx[taskEVENT]);
551: #endif
552: TAILQ_REMOVE(&r->root_event, task, task_node);
553: #ifdef HAVE_LIBPTHREAD
554: pthread_mutex_unlock(&r->root_mtx[taskEVENT]);
555: #endif
556: task->task_type = taskUNUSE;
557: #ifdef HAVE_LIBPTHREAD
558: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
559: #endif
560: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
561: #ifdef HAVE_LIBPTHREAD
562: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
563: #endif
564: return task;
565: }
566: while ((task = TAILQ_FIRST(&r->root_ready))) {
567: #ifdef HAVE_LIBPTHREAD
568: pthread_mutex_lock(&r->root_mtx[taskREADY]);
569: #endif
570: TAILQ_REMOVE(&r->root_ready, task, task_node);
571: #ifdef HAVE_LIBPTHREAD
572: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
573: #endif
574: task->task_type = taskUNUSE;
575: #ifdef HAVE_LIBPTHREAD
576: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
577: #endif
578: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
579: #ifdef HAVE_LIBPTHREAD
580: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
581: #endif
582: return task;
583: }
584:
585: #ifdef TIMER_WITHOUT_SORT
586: clock_gettime(CLOCK_MONOTONIC, &now);
587:
588: sched_timespecclear(&r->root_wait);
589: TAILQ_FOREACH(task, &r->root_timer, task_node) {
590: if (!sched_timespecisset(&r->root_wait))
591: r->root_wait = TASK_TS(task);
592: else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
593: r->root_wait = TASK_TS(task);
594: }
595:
596: if (TAILQ_FIRST(&r->root_timer)) {
597: m = r->root_wait;
598: sched_timespecsub(&m, &now, &mtmp);
599: r->root_wait = mtmp;
600: } else {
601: /* set wait INFTIM */
602: sched_timespecinf(&r->root_wait);
603: }
604: #else
605: if (!TAILQ_FIRST(&r->root_task) && (task = TAILQ_FIRST(&r->root_timer))) {
606: clock_gettime(CLOCK_MONOTONIC, &now);
607:
608: m = TASK_TS(task);
609: sched_timespecsub(&m, &now, &mtmp);
610: r->root_wait = mtmp;
611: } else {
612: /* set wait INFTIM */
613: sched_timespecinf(&r->root_wait);
614: }
615: #endif
616: /* if present member of task, set NOWAIT */
617: if (TAILQ_FIRST(&r->root_task))
618: sched_timespecclear(&r->root_wait);
619:
620: if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1)
621: timeout = &r->root_wait;
622: else if (sched_timespecisinf(&r->root_poll))
623: timeout = NULL;
624: else
625: timeout = &r->root_poll;
626: if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
627: if (r->root_hooks.hook_exec.exception) {
628: if (r->root_hooks.hook_exec.exception(r, NULL))
629: return NULL;
630: } else if (errno != EINTR)
631: LOGERR;
632: goto skip_event;
633: }
634:
635: /* kevent dispatcher */
636: now.tv_sec = now.tv_nsec = 0;
637: /* Go and catch the cat into pipes ... */
638: for (i = 0; i < en; i++) {
639: memcpy(evt, &res[i], sizeof evt);
640: evt->flags = EV_DELETE;
641: /* Put read/write task to ready queue */
642: switch (res[i].filter) {
643: case EVFILT_READ:
644: flg = 0;
645: TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) {
646: if (TASK_FD(task) != ((intptr_t) res[i].udata))
647: continue;
648: else {
649: flg++;
650: TASK_RET(task) = res[i].data;
651: TASK_FLAG(task) = (u_long) res[i].fflags;
652: }
653: /* remove read handle */
654: #ifdef HAVE_LIBPTHREAD
655: pthread_mutex_lock(&r->root_mtx[taskREAD]);
656: #endif
657: TAILQ_REMOVE(&r->root_read, task, task_node);
658: #ifdef HAVE_LIBPTHREAD
659: pthread_mutex_unlock(&r->root_mtx[taskREAD]);
660: #endif
661: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
662: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
663: task->task_type = taskUNUSE;
664: #ifdef HAVE_LIBPTHREAD
665: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
666: #endif
667: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
668: #ifdef HAVE_LIBPTHREAD
669: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
670: #endif
671: } else {
672: task->task_type = taskREADY;
673: #ifdef HAVE_LIBPTHREAD
674: pthread_mutex_lock(&r->root_mtx[taskREADY]);
675: #endif
676: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
677: #ifdef HAVE_LIBPTHREAD
678: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
679: #endif
680: }
681: } else {
682: task->task_type = taskREADY;
683: #ifdef HAVE_LIBPTHREAD
684: pthread_mutex_lock(&r->root_mtx[taskREADY]);
685: #endif
686: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
687: #ifdef HAVE_LIBPTHREAD
688: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
689: #endif
690: }
691: }
692: /* if match at least 2, don't remove resouce of event */
693: if (flg > 1)
694: evt->flags ^= evt->flags;
695: break;
696: case EVFILT_WRITE:
697: flg = 0;
698: TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) {
699: if (TASK_FD(task) != ((intptr_t) res[i].udata))
700: continue;
701: else {
702: flg++;
703: TASK_RET(task) = res[i].data;
704: TASK_FLAG(task) = (u_long) res[i].fflags;
705: }
706: /* remove write handle */
707: #ifdef HAVE_LIBPTHREAD
708: pthread_mutex_lock(&r->root_mtx[taskWRITE]);
709: #endif
710: TAILQ_REMOVE(&r->root_write, task, task_node);
711: #ifdef HAVE_LIBPTHREAD
712: pthread_mutex_unlock(&r->root_mtx[taskWRITE]);
713: #endif
714: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
715: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
716: task->task_type = taskUNUSE;
717: #ifdef HAVE_LIBPTHREAD
718: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
719: #endif
720: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
721: #ifdef HAVE_LIBPTHREAD
722: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
723: #endif
724: } else {
725: task->task_type = taskREADY;
726: #ifdef HAVE_LIBPTHREAD
727: pthread_mutex_lock(&r->root_mtx[taskREADY]);
728: #endif
729: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
730: #ifdef HAVE_LIBPTHREAD
731: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
732: #endif
733: }
734: } else {
735: task->task_type = taskREADY;
736: #ifdef HAVE_LIBPTHREAD
737: pthread_mutex_lock(&r->root_mtx[taskREADY]);
738: #endif
739: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
740: #ifdef HAVE_LIBPTHREAD
741: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
742: #endif
743: }
744: }
745: /* if match at least 2, don't remove resouce of event */
746: if (flg > 1)
747: evt->flags ^= evt->flags;
748: break;
749: case EVFILT_TIMER:
750: flg = 0;
751: TAILQ_FOREACH_SAFE(task, &r->root_alarm, task_node, tmp) {
752: if ((uintptr_t) TASK_DATA(task) != ((uintptr_t) res[i].udata))
753: continue;
754: else {
755: flg++;
756: TASK_RET(task) = res[i].data;
757: TASK_FLAG(task) = (u_long) res[i].fflags;
758: }
759: /* remove alarm handle */
760: #ifdef HAVE_LIBPTHREAD
761: pthread_mutex_lock(&r->root_mtx[taskALARM]);
762: #endif
763: TAILQ_REMOVE(&r->root_alarm, task, task_node);
764: #ifdef HAVE_LIBPTHREAD
765: pthread_mutex_unlock(&r->root_mtx[taskALARM]);
766: #endif
767: task->task_type = taskREADY;
768: #ifdef HAVE_LIBPTHREAD
769: pthread_mutex_lock(&r->root_mtx[taskREADY]);
770: #endif
771: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
772: #ifdef HAVE_LIBPTHREAD
773: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
774: #endif
775: }
776: /* if match at least 2, don't remove resouce of event */
777: if (flg > 1)
778: evt->flags ^= evt->flags;
779: break;
780: case EVFILT_VNODE:
781: flg = 0;
782: TAILQ_FOREACH_SAFE(task, &r->root_node, task_node, tmp) {
783: if (TASK_FD(task) != ((intptr_t) res[i].udata))
784: continue;
785: else {
786: flg++;
787: TASK_RET(task) = res[i].data;
788: TASK_FLAG(task) = (u_long) res[i].fflags;
789: }
790: /* remove node handle */
791: #ifdef HAVE_LIBPTHREAD
792: pthread_mutex_lock(&r->root_mtx[taskNODE]);
793: #endif
794: TAILQ_REMOVE(&r->root_node, task, task_node);
795: #ifdef HAVE_LIBPTHREAD
796: pthread_mutex_unlock(&r->root_mtx[taskNODE]);
797: #endif
798: task->task_type = taskREADY;
799: #ifdef HAVE_LIBPTHREAD
800: pthread_mutex_lock(&r->root_mtx[taskREADY]);
801: #endif
802: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
803: #ifdef HAVE_LIBPTHREAD
804: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
805: #endif
806: }
807: /* if match at least 2, don't remove resouce of event */
808: if (flg > 1)
809: evt->flags ^= evt->flags;
810: break;
811: case EVFILT_PROC:
812: flg = 0;
813: TAILQ_FOREACH_SAFE(task, &r->root_proc, task_node, tmp) {
814: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
815: continue;
816: else {
817: flg++;
818: TASK_RET(task) = res[i].data;
819: TASK_FLAG(task) = (u_long) res[i].fflags;
820: }
821: /* remove proc handle */
822: #ifdef HAVE_LIBPTHREAD
823: pthread_mutex_lock(&r->root_mtx[taskPROC]);
824: #endif
825: TAILQ_REMOVE(&r->root_proc, task, task_node);
826: #ifdef HAVE_LIBPTHREAD
827: pthread_mutex_unlock(&r->root_mtx[taskPROC]);
828: #endif
829: task->task_type = taskREADY;
830: #ifdef HAVE_LIBPTHREAD
831: pthread_mutex_lock(&r->root_mtx[taskREADY]);
832: #endif
833: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
834: #ifdef HAVE_LIBPTHREAD
835: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
836: #endif
837: }
838: /* if match at least 2, don't remove resouce of event */
839: if (flg > 1)
840: evt->flags ^= evt->flags;
841: break;
842: case EVFILT_SIGNAL:
843: flg = 0;
844: TAILQ_FOREACH_SAFE(task, &r->root_signal, task_node, tmp) {
845: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
846: continue;
847: else {
848: flg++;
849: TASK_RET(task) = res[i].data;
850: TASK_FLAG(task) = (u_long) res[i].fflags;
851: }
852: /* remove signal handle */
853: #ifdef HAVE_LIBPTHREAD
854: pthread_mutex_lock(&r->root_mtx[taskSIGNAL]);
855: #endif
856: TAILQ_REMOVE(&r->root_signal, task, task_node);
857: #ifdef HAVE_LIBPTHREAD
858: pthread_mutex_unlock(&r->root_mtx[taskSIGNAL]);
859: #endif
860: task->task_type = taskREADY;
861: #ifdef HAVE_LIBPTHREAD
862: pthread_mutex_lock(&r->root_mtx[taskREADY]);
863: #endif
864: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
865: #ifdef HAVE_LIBPTHREAD
866: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
867: #endif
868: }
869: /* if match at least 2, don't remove resouce of event */
870: if (flg > 1)
871: evt->flags ^= evt->flags;
872: break;
873: #ifdef AIO_SUPPORT
874: case EVFILT_AIO:
875: flg = 0;
876: TAILQ_FOREACH_SAFE(task, &r->root_aio, task_node, tmp) {
877: acb = (struct aiocb*) TASK_VAL(task);
878: if (acb != ((struct aiocb*) res[i].udata))
879: continue;
880: else {
881: flg++;
882: TASK_RET(task) = res[i].data;
883: TASK_FLAG(task) = (u_long) res[i].fflags;
884: }
885: /* remove user handle */
886: #ifdef HAVE_LIBPTHREAD
887: pthread_mutex_lock(&r->root_mtx[taskAIO]);
888: #endif
889: TAILQ_REMOVE(&r->root_aio, task, task_node);
890: #ifdef HAVE_LIBPTHREAD
891: pthread_mutex_unlock(&r->root_mtx[taskAIO]);
892: #endif
893: task->task_type = taskREADY;
894: #ifdef HAVE_LIBPTHREAD
895: pthread_mutex_lock(&r->root_mtx[taskREADY]);
896: #endif
897: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
898: #ifdef HAVE_LIBPTHREAD
899: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
900: #endif
901: fd = acb->aio_fildes;
902: if ((len = aio_return(acb)) != -1) {
903: if (lseek(fd, acb->aio_offset + len, SEEK_CUR) == -1)
904: LOGERR;
905: } else
906: LOGERR;
907: free(acb);
908: TASK_DATLEN(task) = (u_long) len;
909: TASK_FD(task) = fd;
910: }
911: /* if match at least 2, don't remove resouce of event */
912: if (flg > 1)
913: evt->flags ^= evt->flags;
914: break;
915: #ifdef EVFILT_LIO
916: case EVFILT_LIO:
917: flg = 0;
918: TAILQ_FOREACH_SAFE(task, &r->root_lio, task_node, tmp) {
919: acbs = (struct aiocb**) TASK_VAL(task);
920: if (acbs != ((struct aiocb**) res[i].udata))
921: continue;
922: else {
923: flg++;
924: TASK_RET(task) = res[i].data;
925: TASK_FLAG(task) = (u_long) res[i].fflags;
926: }
927: /* remove user handle */
928: #ifdef HAVE_LIBPTHREAD
929: pthread_mutex_lock(&r->root_mtx[taskLIO]);
930: #endif
931: TAILQ_REMOVE(&r->root_lio, task, task_node);
932: #ifdef HAVE_LIBPTHREAD
933: pthread_mutex_unlock(&r->root_mtx[taskLIO]);
934: #endif
935: task->task_type = taskREADY;
936: #ifdef HAVE_LIBPTHREAD
937: pthread_mutex_lock(&r->root_mtx[taskREADY]);
938: #endif
939: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
940: #ifdef HAVE_LIBPTHREAD
941: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
942: #endif
943: iv = (struct iovec*) TASK_DATA(task);
944: fd = acbs[0]->aio_fildes;
945: off = acbs[0]->aio_offset;
946: for (j = len = 0; i < TASK_DATLEN(task); len += l, i++) {
947: if ((iv[i].iov_len = aio_return(acbs[i])) == -1)
948: l = 0;
949: else
950: l = iv[i].iov_len;
951: free(acbs[i]);
952: }
953: free(acbs);
954: TASK_DATLEN(task) = (u_long) len;
955: TASK_FD(task) = fd;
956:
957: if (lseek(fd, off + len, SEEK_CUR) == -1)
958: LOGERR;
959: }
960: /* if match at least 2, don't remove resouce of event */
961: if (flg > 1)
962: evt->flags ^= evt->flags;
963: break;
964: #endif /* EVFILT_LIO */
965: #endif /* AIO_SUPPORT */
966: #ifdef EVFILT_USER
967: case EVFILT_USER:
968: flg = 0;
969: TAILQ_FOREACH_SAFE(task, &r->root_user, task_node, tmp) {
970: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
971: continue;
972: else {
973: flg++;
974: TASK_RET(task) = res[i].data;
975: TASK_FLAG(task) = (u_long) res[i].fflags;
976: }
977: /* remove user handle */
978: #ifdef HAVE_LIBPTHREAD
979: pthread_mutex_lock(&r->root_mtx[taskUSER]);
980: #endif
981: TAILQ_REMOVE(&r->root_user, task, task_node);
982: #ifdef HAVE_LIBPTHREAD
983: pthread_mutex_unlock(&r->root_mtx[taskUSER]);
984: #endif
985: task->task_type = taskREADY;
986: #ifdef HAVE_LIBPTHREAD
987: pthread_mutex_lock(&r->root_mtx[taskREADY]);
988: #endif
989: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
990: #ifdef HAVE_LIBPTHREAD
991: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
992: #endif
993: }
994: /* if match at least 2, don't remove resouce of event */
995: if (flg > 1)
996: evt->flags ^= evt->flags;
997: break;
998: #endif /* EVFILT_USER */
999: }
1000: if (kevent(r->root_kq, evt, 1, NULL, 0, &now) == -1) {
1001: if (r->root_hooks.hook_exec.exception) {
1002: if (r->root_hooks.hook_exec.exception(r, NULL))
1003: return NULL;
1004: } else
1005: LOGERR;
1006: }
1007: } /* end of kevent dispatcher */
1008:
1009: skip_event:
1010: /* timer update & put in ready queue */
1011: clock_gettime(CLOCK_MONOTONIC, &now);
1012:
1013: TAILQ_FOREACH_SAFE(task, &r->root_timer, task_node, tmp)
1014: if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0) {
1015: #ifdef HAVE_LIBPTHREAD
1016: pthread_mutex_lock(&r->root_mtx[taskTIMER]);
1017: #endif
1018: TAILQ_REMOVE(&r->root_timer, task, task_node);
1019: #ifdef HAVE_LIBPTHREAD
1020: pthread_mutex_unlock(&r->root_mtx[taskTIMER]);
1021: #endif
1022: task->task_type = taskREADY;
1023: #ifdef HAVE_LIBPTHREAD
1024: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1025: #endif
1026: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1027: #ifdef HAVE_LIBPTHREAD
1028: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1029: #endif
1030: }
1031:
1032: /* put regular task priority task to ready queue,
1033: if there is no ready task or reach max missing hit for regular task */
1034: if ((task = TAILQ_FIRST(&r->root_task))) {
1035: if (!TAILQ_FIRST(&r->root_ready) || r->root_miss >= TASK_VAL(task)) {
1036: r->root_miss ^= r->root_miss;
1037:
1038: #ifdef HAVE_LIBPTHREAD
1039: pthread_mutex_lock(&r->root_mtx[taskTASK]);
1040: #endif
1041: TAILQ_REMOVE(&r->root_task, task, task_node);
1042: #ifdef HAVE_LIBPTHREAD
1043: pthread_mutex_unlock(&r->root_mtx[taskTASK]);
1044: #endif
1045: task->task_type = taskREADY;
1046: #ifdef HAVE_LIBPTHREAD
1047: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1048: #endif
1049: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1050: #ifdef HAVE_LIBPTHREAD
1051: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1052: #endif
1053: } else
1054: r->root_miss++;
1055: } else
1056: r->root_miss ^= r->root_miss;
1057:
1058: /* OK, lets get ready task !!! */
1059: task = TAILQ_FIRST(&r->root_ready);
1060: if (!(task))
1061: return NULL;
1062:
1063: #ifdef HAVE_LIBPTHREAD
1064: pthread_mutex_lock(&r->root_mtx[taskREADY]);
1065: #endif
1066: TAILQ_REMOVE(&r->root_ready, task, task_node);
1067: #ifdef HAVE_LIBPTHREAD
1068: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
1069: #endif
1070: task->task_type = taskUNUSE;
1071: #ifdef HAVE_LIBPTHREAD
1072: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
1073: #endif
1074: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1075: #ifdef HAVE_LIBPTHREAD
1076: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
1077: #endif
1078: return task;
1079: }
1080:
1081: /*
1082: * sched_hook_exception() - Default EXCEPTION hook
1083: *
1084: * @root = root task
1085: * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
1086: * return: <0 errors and 0 ok
1087: */
1088: void *
1089: sched_hook_exception(void *root, void *arg)
1090: {
1091: sched_root_task_t *r = root;
1092:
1093: if (!r)
1094: return NULL;
1095:
1096: /* custom exception handling ... */
1097: if (arg) {
1098: if (arg == (void*) EV_EOF)
1099: return NULL;
1100: return (void*) -1; /* raise scheduler error!!! */
1101: }
1102:
1103: /* if error hook exists */
1104: if (r->root_hooks.hook_root.error)
1105: return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
1106:
1107: /* default case! */
1108: LOGERR;
1109: return NULL;
1110: }
1111:
1112: /*
1113: * sched_hook_condition() - Default CONDITION hook
1114: *
1115: * @root = root task
1116: * @arg = killState from schedRun()
1117: * return: NULL kill scheduler loop or !=NULL ok
1118: */
1119: void *
1120: sched_hook_condition(void *root, void *arg)
1121: {
1122: sched_root_task_t *r = root;
1123:
1124: if (!r)
1125: return NULL;
1126:
1127: return (void*) (r->root_cond - *(intptr_t*) arg);
1128: }
1129:
1130: /*
1131: * sched_hook_rtc() - Default RTC hook
1132: *
1133: * @task = current task
1134: * @arg = unused
1135: * return: <0 errors and 0 ok
1136: */
1137: #if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
1138: void *
1139: sched_hook_rtc(void *task, void *arg __unused)
1140: {
1141: sched_task_t *sigt = NULL, *t = task;
1142: struct itimerspec its;
1143: struct sigevent evt;
1144: timer_t tmr;
1145:
1146: if (!t || !TASK_ROOT(t))
1147: return (void*) -1;
1148:
1149: memset(&evt, 0, sizeof evt);
1150: evt.sigev_notify = SIGEV_SIGNAL;
1151: evt.sigev_signo = (intptr_t) TASK_DATA(t) + SIGRTMIN;
1152: evt.sigev_value.sival_ptr = TASK_DATA(t);
1153:
1154: if (timer_create(CLOCK_MONOTONIC, &evt, &tmr) == -1) {
1155: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1156: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1157: else
1158: LOGERR;
1159: return (void*) -1;
1160: } else
1161: TASK_FLAG(t) = (u_long) tmr;
1162:
1163: if (!(sigt = schedSignal(TASK_ROOT(t), _sched_rtcWrapper, TASK_ARG(t), evt.sigev_signo,
1164: t, (size_t) tmr))) {
1165: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1166: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1167: else
1168: LOGERR;
1169: timer_delete(tmr);
1170: return (void*) -1;
1171: } else
1172: TASK_RET(t) = (uintptr_t) sigt;
1173:
1174: memset(&its, 0, sizeof its);
1175: its.it_value.tv_sec = t->task_val.ts.tv_sec;
1176: its.it_value.tv_nsec = t->task_val.ts.tv_nsec;
1177:
1178: if (timer_settime(tmr, TIMER_RELTIME, &its, NULL) == -1) {
1179: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
1180: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1181: else
1182: LOGERR;
1183: schedCancel(sigt);
1184: timer_delete(tmr);
1185: return (void*) -1;
1186: }
1187:
1188: return NULL;
1189: }
1190: #endif /* HAVE_TIMER_CREATE */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>