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