File:  [ELWIX - Embedded LightWeight unIX -] / libaitsched / src / hooks.c
Revision 1.7.2.3: download - view: text, annotated - select for diffs - revision graph
Thu May 31 21:36:40 2012 UTC (12 years, 1 month ago) by misho
Branches: sched2_2
Diff to: branchpoint 1.7: preferred, unified
PATCH & FIX libaitsched !!!!
very ugly and tricky BUG in cancel hook. It caused unfree task if they not related with kevent
properly free schedCancel when it did copied from another task

    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.3 2012/05/31 21:36:40 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 NULL;
  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>