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