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