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.7.2.2 2012/05/31 14:45:10 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
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:
111: if (!t || !TASK_ROOT(t))
112: return (void*) -1;
113:
114: switch (TASK_TYPE(t)) {
115: case taskREAD:
116: #ifdef __NetBSD__
117: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
118: #else
119: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (void*) TASK_FD(t));
120: #endif
121: break;
122: case taskWRITE:
123: #ifdef __NetBSD__
124: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
125: #else
126: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
127: #endif
128: break;
129: case taskALARM:
130: #ifdef __NetBSD__
131: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE,
132: 0, 0, (intptr_t) TASK_DATA(t));
133: #else
134: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE,
135: 0, 0, (void*) TASK_DATA(t));
136: #endif
137: break;
138: case taskNODE:
139: #ifdef __NetBSD__
140: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
141: #else
142: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
143: #endif
144: break;
145: case taskPROC:
146: #ifdef __NetBSD__
147: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
148: #else
149: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
150: #endif
151: break;
152: case taskSIGNAL:
153: #ifdef __NetBSD__
154: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
155: #else
156: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
157: #endif
158: break;
159: case taskUSER:
160: #ifdef __NetBSD__
161: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t));
162: #else
163: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (void*) TASK_VAL(t));
164: #endif
165: break;
166: default:
167: return (void*) -1;
168: }
169:
170: kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout);
171: return NULL;
172: }
173:
174: /*
175: * sched_hook_read() - Default READ hook
176: *
177: * @task = current task
178: * @arg = unused
179: * return: <0 errors and 0 ok
180: */
181: void *
182: sched_hook_read(void *task, void *arg __unused)
183: {
184: sched_task_t *t = task;
185: struct kevent chg[1];
186: struct timespec timeout = { 0, 0 };
187:
188: if (!t || !TASK_ROOT(t))
189: return (void*) -1;
190:
191: #ifdef __NetBSD__
192: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
193: #else
194: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
195: #endif
196: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
197: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
198: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
199: else
200: LOGERR;
201: return (void*) -1;
202: }
203:
204: return NULL;
205: }
206:
207: /*
208: * sched_hook_write() - Default WRITE hook
209: *
210: * @task = current task
211: * @arg = unused
212: * return: <0 errors and 0 ok
213: */
214: void *
215: sched_hook_write(void *task, void *arg __unused)
216: {
217: sched_task_t *t = task;
218: struct kevent chg[1];
219: struct timespec timeout = { 0, 0 };
220:
221: if (!t || !TASK_ROOT(t))
222: return (void*) -1;
223:
224: #ifdef __NetBSD__
225: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t));
226: #else
227: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (void*) TASK_FD(t));
228: #endif
229: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
230: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
231: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
232: else
233: LOGERR;
234: return (void*) -1;
235: }
236:
237: return NULL;
238: }
239:
240: /*
241: * sched_hook_alarm() - Default ALARM hook
242: *
243: * @task = current task
244: * @arg = unused
245: * return: <0 errors and 0 ok
246: */
247: void *
248: sched_hook_alarm(void *task, void *arg __unused)
249: {
250: sched_task_t *t = task;
251: struct kevent chg[1];
252: struct timespec timeout = { 0, 0 };
253:
254: if (!t || !TASK_ROOT(t))
255: return (void*) -1;
256:
257: #ifdef __NetBSD__
258: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0,
259: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
260: (intptr_t) TASK_DATA(t));
261: #else
262: EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0,
263: t->task_val.ts.tv_sec * 1000 + t->task_val.ts.tv_nsec / 1000000,
264: (void*) TASK_DATA(t));
265: #endif
266: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
267: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
268: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
269: else
270: LOGERR;
271: return (void*) -1;
272: }
273:
274: return NULL;
275: }
276:
277: /*
278: * sched_hook_node() - Default NODE hook
279: *
280: * @task = current task
281: * @arg = unused
282: * return: <0 errors and 0 ok
283: */
284: void *
285: sched_hook_node(void *task, void *arg __unused)
286: {
287: sched_task_t *t = task;
288: struct kevent chg[1];
289: struct timespec timeout = { 0, 0 };
290:
291: if (!t || !TASK_ROOT(t))
292: return (void*) -1;
293:
294: #ifdef __NetBSD__
295: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
296: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
297: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (intptr_t) TASK_FD(t));
298: #else
299: EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_ADD | EV_CLEAR,
300: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
301: NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, (void*) TASK_FD(t));
302: #endif
303: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
304: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
305: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
306: else
307: LOGERR;
308: return (void*) -1;
309: }
310:
311: return NULL;
312: }
313:
314: /*
315: * sched_hook_proc() - Default PROC hook
316: *
317: * @task = current task
318: * @arg = unused
319: * return: <0 errors and 0 ok
320: */
321: void *
322: sched_hook_proc(void *task, void *arg __unused)
323: {
324: sched_task_t *t = task;
325: struct kevent chg[1];
326: struct timespec timeout = { 0, 0 };
327:
328: if (!t || !TASK_ROOT(t))
329: return (void*) -1;
330:
331: #ifdef __NetBSD__
332: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
333: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (intptr_t) TASK_VAL(t));
334: #else
335: EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_ADD | EV_CLEAR,
336: NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK, 0, (void*) TASK_VAL(t));
337: #endif
338: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
339: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
340: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
341: else
342: LOGERR;
343: return (void*) -1;
344: }
345:
346: return NULL;
347: }
348:
349: /*
350: * sched_hook_signal() - Default SIGNAL hook
351: *
352: * @task = current task
353: * @arg = unused
354: * return: <0 errors and 0 ok
355: */
356: void *
357: sched_hook_signal(void *task, void *arg __unused)
358: {
359: sched_task_t *t = task;
360: struct kevent chg[1];
361: struct timespec timeout = { 0, 0 };
362:
363: if (!t || !TASK_ROOT(t))
364: return (void*) -1;
365:
366: #ifdef __NetBSD__
367: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD, 0, 0, (intptr_t) TASK_VAL(t));
368: #else
369: EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_ADD, 0, 0, (void*) TASK_VAL(t));
370: #endif
371: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
372: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
373: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
374: else
375: LOGERR;
376: return (void*) -1;
377: }
378:
379: return NULL;
380: }
381:
382: /*
383: * sched_hook_user() - Default USER hook
384: *
385: * @task = current task
386: * @arg = unused
387: * return: <0 errors and 0 ok
388: */
389: void *
390: sched_hook_user(void *task, void *arg __unused)
391: {
392: sched_task_t *t = task;
393: struct kevent chg[1];
394: struct timespec timeout = { 0, 0 };
395:
396: if (!t || !TASK_ROOT(t))
397: return (void*) -1;
398:
399: #ifdef __NetBSD__
400: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
401: 0, (intptr_t) TASK_VAL(t));
402: #else
403: EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_ADD | EV_CLEAR, TASK_DATLEN(t),
404: 0, (void*) TASK_VAL(t));
405: #endif
406: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
407: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
408: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
409: else
410: LOGERR;
411: return (void*) -1;
412: }
413:
414: return NULL;
415: }
416:
417: /*
418: * sched_hook_fetch() - Default FETCH hook
419: *
420: * @root = root task
421: * @arg = unused
422: * return: NULL error or !=NULL fetched task
423: */
424: void *
425: sched_hook_fetch(void *root, void *arg __unused)
426: {
427: sched_root_task_t *r = root;
428: sched_task_t *task, *tmp;
429: struct timespec now, m, mtmp;
430: struct timespec *timeout;
431: struct kevent evt[1], res[KQ_EVENTS];
432: register int i;
433: int en;
434:
435: if (!r)
436: return NULL;
437:
438: /* get new task by queue priority */
439: while ((task = TAILQ_FIRST(&r->root_event))) {
440: #ifdef HAVE_LIBPTHREAD
441: pthread_mutex_lock(&r->root_mtx[taskEVENT]);
442: #endif
443: TAILQ_REMOVE(&r->root_event, task, task_node);
444: #ifdef HAVE_LIBPTHREAD
445: pthread_mutex_unlock(&r->root_mtx[taskEVENT]);
446: #endif
447: task->task_type = taskUNUSE;
448: #ifdef HAVE_LIBPTHREAD
449: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
450: #endif
451: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
452: #ifdef HAVE_LIBPTHREAD
453: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
454: #endif
455: return task;
456: }
457: while ((task = TAILQ_FIRST(&r->root_ready))) {
458: #ifdef HAVE_LIBPTHREAD
459: pthread_mutex_lock(&r->root_mtx[taskREADY]);
460: #endif
461: TAILQ_REMOVE(&r->root_ready, task, task_node);
462: #ifdef HAVE_LIBPTHREAD
463: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
464: #endif
465: task->task_type = taskUNUSE;
466: #ifdef HAVE_LIBPTHREAD
467: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
468: #endif
469: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
470: #ifdef HAVE_LIBPTHREAD
471: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
472: #endif
473: return task;
474: }
475:
476: #ifdef TIMER_WITHOUT_SORT
477: clock_gettime(CLOCK_MONOTONIC, &now);
478:
479: sched_timespecclear(&r->root_wait);
480: TAILQ_FOREACH(task, &r->root_timer, task_node) {
481: if (!sched_timespecisset(&r->root_wait))
482: r->root_wait = TASK_TS(task);
483: else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
484: r->root_wait = TASK_TS(task);
485: }
486:
487: if (TAILQ_FIRST(&r->root_timer)) {
488: m = r->root_wait;
489: sched_timespecsub(&m, &now, &mtmp);
490: r->root_wait = mtmp;
491: } else {
492: /* set wait INFTIM */
493: sched_timespecinf(&r->root_wait);
494: }
495: #else
496: if (!TAILQ_FIRST(&r->root_eventlo) && (task = TAILQ_FIRST(&r->root_timer))) {
497: clock_gettime(CLOCK_MONOTONIC, &now);
498:
499: m = TASK_TS(task);
500: sched_timespecsub(&m, &now, &mtmp);
501: r->root_wait = mtmp;
502: } else {
503: /* set wait INFTIM */
504: sched_timespecinf(&r->root_wait);
505: }
506: #endif
507: /* if present member of eventLo, set NOWAIT */
508: if (TAILQ_FIRST(&r->root_eventlo))
509: sched_timespecclear(&r->root_wait);
510:
511: if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1)
512: timeout = &r->root_wait;
513: else if (sched_timespecisinf(&r->root_poll))
514: timeout = NULL;
515: else
516: timeout = &r->root_poll;
517: if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
518: if (r->root_hooks.hook_exec.exception) {
519: if (r->root_hooks.hook_exec.exception(r, NULL))
520: return NULL;
521: } else if (errno != EINTR)
522: LOGERR;
523: return NULL;
524: }
525:
526: now.tv_sec = now.tv_nsec = 0;
527: /* Go and catch the cat into pipes ... */
528: for (i = 0; i < en; i++) {
529: memcpy(evt, &res[i], sizeof evt);
530: evt->flags = EV_DELETE;
531: /* Put read/write task to ready queue */
532: switch (res[i].filter) {
533: case EVFILT_READ:
534: TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) {
535: if (TASK_FD(task) != ((intptr_t) res[i].udata))
536: continue;
537: /* remove read handle */
538: #ifdef HAVE_LIBPTHREAD
539: pthread_mutex_lock(&r->root_mtx[taskREAD]);
540: #endif
541: TAILQ_REMOVE(&r->root_read, task, task_node);
542: #ifdef HAVE_LIBPTHREAD
543: pthread_mutex_unlock(&r->root_mtx[taskREAD]);
544: #endif
545: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
546: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
547: task->task_type = taskUNUSE;
548: #ifdef HAVE_LIBPTHREAD
549: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
550: #endif
551: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
552: #ifdef HAVE_LIBPTHREAD
553: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
554: #endif
555: } else {
556: task->task_type = taskREADY;
557: #ifdef HAVE_LIBPTHREAD
558: pthread_mutex_lock(&r->root_mtx[taskREADY]);
559: #endif
560: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
561: #ifdef HAVE_LIBPTHREAD
562: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
563: #endif
564: }
565: } else {
566: task->task_type = taskREADY;
567: #ifdef HAVE_LIBPTHREAD
568: pthread_mutex_lock(&r->root_mtx[taskREADY]);
569: #endif
570: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
571: #ifdef HAVE_LIBPTHREAD
572: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
573: #endif
574: }
575: break;
576: }
577: break;
578: case EVFILT_WRITE:
579: TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) {
580: if (TASK_FD(task) != ((intptr_t) res[i].udata))
581: continue;
582: /* remove write handle */
583: #ifdef HAVE_LIBPTHREAD
584: pthread_mutex_lock(&r->root_mtx[taskWRITE]);
585: #endif
586: TAILQ_REMOVE(&r->root_write, task, task_node);
587: #ifdef HAVE_LIBPTHREAD
588: pthread_mutex_unlock(&r->root_mtx[taskWRITE]);
589: #endif
590: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
591: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
592: task->task_type = taskUNUSE;
593: #ifdef HAVE_LIBPTHREAD
594: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
595: #endif
596: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
597: #ifdef HAVE_LIBPTHREAD
598: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
599: #endif
600: } else {
601: task->task_type = taskREADY;
602: #ifdef HAVE_LIBPTHREAD
603: pthread_mutex_lock(&r->root_mtx[taskREADY]);
604: #endif
605: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
606: #ifdef HAVE_LIBPTHREAD
607: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
608: #endif
609: }
610: } else {
611: task->task_type = taskREADY;
612: #ifdef HAVE_LIBPTHREAD
613: pthread_mutex_lock(&r->root_mtx[taskREADY]);
614: #endif
615: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
616: #ifdef HAVE_LIBPTHREAD
617: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
618: #endif
619: }
620: break;
621: }
622: break;
623: case EVFILT_TIMER:
624: TAILQ_FOREACH_SAFE(task, &r->root_alarm, task_node, tmp) {
625: if ((uintptr_t) TASK_DATA(task) != ((uintptr_t) res[i].udata))
626: continue;
627: /* remove alarm handle */
628: #ifdef HAVE_LIBPTHREAD
629: pthread_mutex_lock(&r->root_mtx[taskALARM]);
630: #endif
631: TAILQ_REMOVE(&r->root_alarm, task, task_node);
632: #ifdef HAVE_LIBPTHREAD
633: pthread_mutex_unlock(&r->root_mtx[taskALARM]);
634: #endif
635: task->task_type = taskREADY;
636: #ifdef HAVE_LIBPTHREAD
637: pthread_mutex_lock(&r->root_mtx[taskREADY]);
638: #endif
639: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
640: #ifdef HAVE_LIBPTHREAD
641: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
642: #endif
643: break;
644: }
645: break;
646: case EVFILT_VNODE:
647: TAILQ_FOREACH_SAFE(task, &r->root_node, task_node, tmp) {
648: if (TASK_FD(task) != ((intptr_t) res[i].udata))
649: continue;
650: else {
651: TASK_DATA(task) = (void*) res[i].data;
652: TASK_DATLEN(task) = res[i].fflags;
653: }
654: /* remove node handle */
655: #ifdef HAVE_LIBPTHREAD
656: pthread_mutex_lock(&r->root_mtx[taskNODE]);
657: #endif
658: TAILQ_REMOVE(&r->root_node, task, task_node);
659: #ifdef HAVE_LIBPTHREAD
660: pthread_mutex_unlock(&r->root_mtx[taskNODE]);
661: #endif
662: task->task_type = taskREADY;
663: #ifdef HAVE_LIBPTHREAD
664: pthread_mutex_lock(&r->root_mtx[taskREADY]);
665: #endif
666: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
667: #ifdef HAVE_LIBPTHREAD
668: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
669: #endif
670: break;
671: }
672: break;
673: case EVFILT_PROC:
674: TAILQ_FOREACH_SAFE(task, &r->root_proc, task_node, tmp) {
675: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
676: continue;
677: else {
678: TASK_DATA(task) = (void*) res[i].data;
679: TASK_DATLEN(task) = res[i].fflags;
680: }
681: /* remove proc handle */
682: #ifdef HAVE_LIBPTHREAD
683: pthread_mutex_lock(&r->root_mtx[taskPROC]);
684: #endif
685: TAILQ_REMOVE(&r->root_proc, task, task_node);
686: #ifdef HAVE_LIBPTHREAD
687: pthread_mutex_unlock(&r->root_mtx[taskPROC]);
688: #endif
689: task->task_type = taskREADY;
690: #ifdef HAVE_LIBPTHREAD
691: pthread_mutex_lock(&r->root_mtx[taskREADY]);
692: #endif
693: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
694: #ifdef HAVE_LIBPTHREAD
695: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
696: #endif
697: break;
698: }
699: break;
700: case EVFILT_SIGNAL:
701: TAILQ_FOREACH_SAFE(task, &r->root_signal, task_node, tmp) {
702: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
703: continue;
704: /* remove signal handle */
705: #ifdef HAVE_LIBPTHREAD
706: pthread_mutex_lock(&r->root_mtx[taskSIGNAL]);
707: #endif
708: TAILQ_REMOVE(&r->root_signal, task, task_node);
709: #ifdef HAVE_LIBPTHREAD
710: pthread_mutex_unlock(&r->root_mtx[taskSIGNAL]);
711: #endif
712: task->task_type = taskREADY;
713: #ifdef HAVE_LIBPTHREAD
714: pthread_mutex_lock(&r->root_mtx[taskREADY]);
715: #endif
716: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
717: #ifdef HAVE_LIBPTHREAD
718: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
719: #endif
720: break;
721: }
722: break;
723: case EVFILT_USER:
724: TAILQ_FOREACH_SAFE(task, &r->root_user, task_node, tmp) {
725: if (TASK_VAL(task) != ((uintptr_t) res[i].udata))
726: continue;
727: else {
728: TASK_DATA(task) = (void*) res[i].data;
729: TASK_DATLEN(task) = res[i].fflags;
730: }
731: /* remove user handle */
732: #ifdef HAVE_LIBPTHREAD
733: pthread_mutex_lock(&r->root_mtx[taskUSER]);
734: #endif
735: TAILQ_REMOVE(&r->root_user, task, task_node);
736: #ifdef HAVE_LIBPTHREAD
737: pthread_mutex_unlock(&r->root_mtx[taskUSER]);
738: #endif
739: task->task_type = taskREADY;
740: #ifdef HAVE_LIBPTHREAD
741: pthread_mutex_lock(&r->root_mtx[taskREADY]);
742: #endif
743: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
744: #ifdef HAVE_LIBPTHREAD
745: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
746: #endif
747: break;
748: }
749: break;
750: }
751: if (kevent(r->root_kq, evt, 1, NULL, 0, &now) == -1) {
752: if (r->root_hooks.hook_exec.exception) {
753: if (r->root_hooks.hook_exec.exception(r, NULL))
754: return NULL;
755: } else
756: LOGERR;
757: }
758: }
759:
760: /* timer update & put in ready queue */
761: clock_gettime(CLOCK_MONOTONIC, &now);
762:
763: TAILQ_FOREACH_SAFE(task, &r->root_timer, task_node, tmp)
764: if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0) {
765: #ifdef HAVE_LIBPTHREAD
766: pthread_mutex_lock(&r->root_mtx[taskTIMER]);
767: #endif
768: TAILQ_REMOVE(&r->root_timer, task, task_node);
769: #ifdef HAVE_LIBPTHREAD
770: pthread_mutex_unlock(&r->root_mtx[taskTIMER]);
771: #endif
772: task->task_type = taskREADY;
773: #ifdef HAVE_LIBPTHREAD
774: pthread_mutex_lock(&r->root_mtx[taskREADY]);
775: #endif
776: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
777: #ifdef HAVE_LIBPTHREAD
778: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
779: #endif
780: }
781:
782: /* put eventlo priority task to ready queue, if there is no ready task or
783: reach max missed fetch-rotate */
784: if ((task = TAILQ_FIRST(&r->root_eventlo))) {
785: if (!TAILQ_FIRST(&r->root_ready) || r->root_eventlo_miss > MAX_EVENTLO_MISS) {
786: r->root_eventlo_miss = 0;
787:
788: #ifdef HAVE_LIBPTHREAD
789: pthread_mutex_lock(&r->root_mtx[taskEVENTLO]);
790: #endif
791: TAILQ_REMOVE(&r->root_eventlo, task, task_node);
792: #ifdef HAVE_LIBPTHREAD
793: pthread_mutex_unlock(&r->root_mtx[taskEVENTLO]);
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: } else
804: r->root_eventlo_miss++;
805: } else
806: r->root_eventlo_miss = 0;
807:
808: /* OK, lets get ready task !!! */
809: task = TAILQ_FIRST(&r->root_ready);
810: if (!(task))
811: return NULL;
812:
813: #ifdef HAVE_LIBPTHREAD
814: pthread_mutex_lock(&r->root_mtx[taskREADY]);
815: #endif
816: TAILQ_REMOVE(&r->root_ready, task, task_node);
817: #ifdef HAVE_LIBPTHREAD
818: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
819: #endif
820: task->task_type = taskUNUSE;
821: #ifdef HAVE_LIBPTHREAD
822: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
823: #endif
824: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
825: #ifdef HAVE_LIBPTHREAD
826: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
827: #endif
828: return task;
829: }
830:
831: /*
832: * sched_hook_exception() - Default EXCEPTION hook
833: *
834: * @root = root task
835: * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
836: * return: <0 errors and 0 ok
837: */
838: void *
839: sched_hook_exception(void *root, void *arg)
840: {
841: sched_root_task_t *r = root;
842:
843: if (!r)
844: return NULL;
845:
846: /* custom exception handling ... */
847: if (arg) {
848: if (arg == (void*) EV_EOF)
849: return NULL;
850: return (void*) -1; /* raise scheduler error!!! */
851: }
852:
853: /* if error hook exists */
854: if (r->root_hooks.hook_root.error)
855: return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
856:
857: /* default case! */
858: LOGERR;
859: return NULL;
860: }
861:
862: /*
863: * sched_hook_condition() - Default CONDITION hook
864: *
865: * @root = root task
866: * @arg = killState from schedRun()
867: * return: NULL kill scheduler loop or !=NULL ok
868: */
869: void *
870: sched_hook_condition(void *root, void *arg)
871: {
872: sched_root_task_t *r = root;
873:
874: if (!r)
875: return NULL;
876:
877: return (void*) (r->root_cond - *(intptr_t*) arg);
878: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>