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