--- libaitsched/src/hooks.c 2013/08/26 08:20:55 1.21 +++ libaitsched/src/hooks.c 2014/01/28 13:17:33 1.25 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: hooks.c,v 1.21 2013/08/26 08:20:55 misho Exp $ +* $Id: hooks.c,v 1.25 2014/01/28 13:17:33 misho Exp $ * ************************************************************************** The ELWIX and AITNET software is distributed under the following @@ -12,7 +12,7 @@ terms: All of the documentation and software included in the ELWIX and AITNET Releases is copyrighted by ELWIX - Sofia/Bulgaria -Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +Copyright 2004 - 2014 by Michael Pounov . All rights reserved. Redistribution and use in source and binary forms, with or without @@ -62,11 +62,17 @@ sched_hook_init(void *root, void *arg __unused) if (!r) return (void*) -1; +#ifndef KQ_DISABLE r->root_kq = kqueue(); if (r->root_kq == -1) { LOGERR; return (void*) -1; } +#else + r->root_kq ^= r->root_kq; + FD_ZERO(&r->root_fds[0]); + FD_ZERO(&r->root_fds[1]); +#endif return NULL; } @@ -86,10 +92,16 @@ sched_hook_fini(void *root, void *arg __unused) if (!r) return (void*) -1; +#ifndef KQ_DISABLE if (r->root_kq > 2) { close(r->root_kq); r->root_kq = 0; } +#else + FD_ZERO(&r->root_fds[1]); + FD_ZERO(&r->root_fds[0]); + r->root_kq ^= r->root_kq; +#endif return NULL; } @@ -105,8 +117,13 @@ void * sched_hook_cancel(void *task, void *arg __unused) { sched_task_t *t = task; +#ifndef KQ_DISABLE struct kevent chg[1]; struct timespec timeout = { 0, 0 }; +#else + sched_root_task_t *r = NULL; + register int i; +#endif #ifdef AIO_SUPPORT struct aiocb *acb; #ifdef EVFILT_LIO @@ -117,23 +134,49 @@ sched_hook_cancel(void *task, void *arg __unused) if (!t || !TASK_ROOT(t)) return (void*) -1; +#ifdef KQ_DISABLE + r = TASK_ROOT(t); +#endif switch (TASK_TYPE(t)) { case taskREAD: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t)); #else EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (void*) TASK_FD(t)); #endif +#else + FD_CLR(TASK_FD(t), &r->root_fds[0]); + + /* optimize select */ + for (i = r->root_kq - 1; i > 2; i--) + if (FD_ISSET(i, &r->root_fds[0]) || FD_ISSET(i, &r->root_fds[1])) + break; + if (i > 2) + r->root_kq = i + 1; +#endif break; case taskWRITE: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t)); #else EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (void*) TASK_FD(t)); #endif +#else + FD_CLR(TASK_FD(t), &r->root_fds[1]); + + /* optimize select */ + for (i = r->root_kq - 1; i > 2; i--) + if (FD_ISSET(i, &r->root_fds[0]) || FD_ISSET(i, &r->root_fds[1])) + break; + if (i > 2) + r->root_kq = i + 1; +#endif break; case taskALARM: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE, 0, 0, (intptr_t) TASK_DATA(t)); @@ -141,22 +184,28 @@ sched_hook_cancel(void *task, void *arg __unused) EV_SET(&chg[0], (uintptr_t) TASK_DATA(t), EVFILT_TIMER, EV_DELETE, 0, 0, (void*) TASK_DATA(t)); #endif +#endif break; case taskNODE: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t)); #else EV_SET(&chg[0], TASK_FD(t), EVFILT_VNODE, EV_DELETE, 0, 0, (void*) TASK_FD(t)); #endif +#endif break; case taskPROC: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t)); #else EV_SET(&chg[0], TASK_VAL(t), EVFILT_PROC, EV_DELETE, 0, 0, (void*) TASK_VAL(t)); #endif +#endif break; case taskSIGNAL: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_VAL(t), EVFILT_SIGNAL, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t)); #else @@ -164,9 +213,11 @@ sched_hook_cancel(void *task, void *arg __unused) #endif /* restore signal */ signal(TASK_VAL(t), SIG_DFL); +#endif break; #ifdef AIO_SUPPORT case taskAIO: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_VAL(t), EVFILT_AIO, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t)); #else @@ -179,9 +230,11 @@ sched_hook_cancel(void *task, void *arg __unused) free(acb); TASK_VAL(t) = 0; } +#endif break; #ifdef EVFILT_LIO case taskLIO: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_VAL(t), EVFILT_LIO, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t)); #else @@ -197,16 +250,19 @@ sched_hook_cancel(void *task, void *arg __unused) free(acbs); TASK_VAL(t) = 0; } +#endif break; #endif /* EVFILT_LIO */ #endif /* AIO_SUPPORT */ #ifdef EVFILT_USER case taskUSER: +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (intptr_t) TASK_VAL(t)); #else EV_SET(&chg[0], TASK_VAL(t), EVFILT_USER, EV_DELETE, 0, 0, (void*) TASK_VAL(t)); #endif +#endif break; #endif /* EVFILT_USER */ case taskTHREAD: @@ -224,7 +280,9 @@ sched_hook_cancel(void *task, void *arg __unused) return NULL; } +#ifndef KQ_DISABLE kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout); +#endif return NULL; } @@ -275,12 +333,20 @@ void * sched_hook_read(void *task, void *arg __unused) { sched_task_t *t = task; +#ifndef KQ_DISABLE struct kevent chg[1]; struct timespec timeout = { 0, 0 }; +#else + sched_root_task_t *r = NULL; +#endif if (!t || !TASK_ROOT(t)) return (void*) -1; +#ifdef KQ_DISABLE + r = TASK_ROOT(t); +#endif +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t)); #else @@ -293,6 +359,11 @@ sched_hook_read(void *task, void *arg __unused) LOGERR; return (void*) -1; } +#else + FD_SET(TASK_FD(t), &r->root_fds[0]); + if (TASK_FD(t) >= r->root_kq) + r->root_kq = TASK_FD(t) + 1; +#endif return NULL; } @@ -308,12 +379,20 @@ void * sched_hook_write(void *task, void *arg __unused) { sched_task_t *t = task; +#ifndef KQ_DISABLE struct kevent chg[1]; struct timespec timeout = { 0, 0 }; +#else + sched_root_task_t *r = NULL; +#endif if (!t || !TASK_ROOT(t)) return (void*) -1; +#ifdef KQ_DISABLE + r = TASK_ROOT(t); +#endif +#ifndef KQ_DISABLE #ifdef __NetBSD__ EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, (intptr_t) TASK_FD(t)); #else @@ -326,6 +405,11 @@ sched_hook_write(void *task, void *arg __unused) LOGERR; return (void*) -1; } +#else + FD_SET(TASK_FD(t), &r->root_fds[1]); + if (TASK_FD(t) >= r->root_kq) + r->root_kq = TASK_FD(t) + 1; +#endif return NULL; } @@ -340,6 +424,7 @@ sched_hook_write(void *task, void *arg __unused) void * sched_hook_alarm(void *task, void *arg __unused) { +#ifndef KQ_DISABLE sched_task_t *t = task; struct kevent chg[1]; struct timespec timeout = { 0, 0 }; @@ -364,6 +449,7 @@ sched_hook_alarm(void *task, void *arg __unused) return (void*) -1; } +#endif return NULL; } @@ -377,6 +463,7 @@ sched_hook_alarm(void *task, void *arg __unused) void * sched_hook_node(void *task, void *arg __unused) { +#ifndef KQ_DISABLE sched_task_t *t = task; struct kevent chg[1]; struct timespec timeout = { 0, 0 }; @@ -401,6 +488,7 @@ sched_hook_node(void *task, void *arg __unused) return (void*) -1; } +#endif return NULL; } @@ -414,6 +502,7 @@ sched_hook_node(void *task, void *arg __unused) void * sched_hook_proc(void *task, void *arg __unused) { +#ifndef KQ_DISABLE sched_task_t *t = task; struct kevent chg[1]; struct timespec timeout = { 0, 0 }; @@ -436,6 +525,7 @@ sched_hook_proc(void *task, void *arg __unused) return (void*) -1; } +#endif return NULL; } @@ -449,6 +539,7 @@ sched_hook_proc(void *task, void *arg __unused) void * sched_hook_signal(void *task, void *arg __unused) { +#ifndef KQ_DISABLE sched_task_t *t = task; struct kevent chg[1]; struct timespec timeout = { 0, 0 }; @@ -471,7 +562,25 @@ sched_hook_signal(void *task, void *arg __unused) LOGERR; return (void*) -1; } +#else +#if 0 + sched_task_t *t = task; + struct sigaction sa; + memset(&sa, 0, sizeof sa); + sigemptyset(&sa.sa_mask); + sa.sa_handler = _sched_sigHandler; + sa.sa_flags = SA_RESETHAND | SA_RESTART; + + if (sigaction(TASK_VAL(t), &sa, NULL) == -1) { + if (TASK_ROOT(t)->root_hooks.hook_exec.exception) + TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL); + else + LOGERR; + return (void*) -1; + } +#endif /* 0 */ +#endif return NULL; } @@ -486,6 +595,7 @@ sched_hook_signal(void *task, void *arg __unused) void * sched_hook_user(void *task, void *arg __unused) { +#ifndef KQ_DISABLE sched_task_t *t = task; struct kevent chg[1]; struct timespec timeout = { 0, 0 }; @@ -508,6 +618,7 @@ sched_hook_user(void *task, void *arg __unused) return (void*) -1; } +#endif return NULL; } #endif @@ -525,8 +636,13 @@ sched_hook_fetch(void *root, void *arg __unused) sched_root_task_t *r = root; sched_task_t *task, *tmp; struct timespec now, m, mtmp; - struct timespec *timeout; +#ifndef KQ_DISABLE struct kevent evt[1], res[KQ_EVENTS]; + struct timespec *timeout; +#else + struct timeval *timeout, tv; + fd_set rfd, wfd, xfd; +#endif register int i, flg; int en; #ifdef AIO_SUPPORT @@ -601,7 +717,7 @@ sched_hook_fetch(void *root, void *arg __unused) /* set wait INFTIM */ sched_timespecinf(&r->root_wait); } -#else +#else /* ! TIMER_WITHOUT_SORT */ if (!TAILQ_FIRST(&r->root_task) && (task = TAILQ_FIRST(&r->root_timer))) { clock_gettime(CLOCK_MONOTONIC, &now); @@ -612,28 +728,48 @@ sched_hook_fetch(void *root, void *arg __unused) /* set wait INFTIM */ sched_timespecinf(&r->root_wait); } -#endif +#endif /* TIMER_WITHOUT_SORT */ /* if present member of task, set NOWAIT */ if (TAILQ_FIRST(&r->root_task)) sched_timespecclear(&r->root_wait); - if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1) + if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1) { +#ifndef KQ_DISABLE timeout = &r->root_wait; - else if (sched_timespecisinf(&r->root_poll)) +#else + sched_timespec2val(&r->root_wait, &tv); + timeout = &tv; +#endif /* KQ_DISABLE */ + } else if (sched_timespecisinf(&r->root_poll)) timeout = NULL; - else + else { +#ifndef KQ_DISABLE timeout = &r->root_poll; +#else + sched_timespec2val(&r->root_poll, &tv); + timeout = &tv; +#endif /* KQ_DISABLE */ + } + +#ifndef KQ_DISABLE if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) { +#else + rfd = xfd = r->root_fds[0]; + wfd = r->root_fds[1]; + if ((en = select(r->root_kq, &rfd, &wfd, &xfd, timeout)) == -1) { +#endif /* KQ_DISABLE */ if (r->root_hooks.hook_exec.exception) { if (r->root_hooks.hook_exec.exception(r, NULL)) return NULL; } else if (errno != EINTR) LOGERR; - return NULL; + goto skip_event; } + /* kevent dispatcher */ now.tv_sec = now.tv_nsec = 0; /* Go and catch the cat into pipes ... */ +#ifndef KQ_DISABLE for (i = 0; i < en; i++) { memcpy(evt, &res[i], sizeof evt); evt->flags = EV_DELETE; @@ -1004,7 +1140,126 @@ sched_hook_fetch(void *root, void *arg __unused) LOGERR; } } +#else /* end of kevent dispatcher */ + for (i = 0; i < r->root_kq; i++) { + if (FD_ISSET(i, &rfd) || FD_ISSET(i, &xfd)) { + flg = 0; + TAILQ_FOREACH_SAFE(task, &r->root_read, task_node, tmp) { + if (TASK_FD(task) != i) + continue; + else { + flg++; + TASK_RET(task) ^= TASK_RET(task); + TASK_FLAG(task) ^= TASK_FLAG(task); + } + /* remove read handle */ +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&r->root_mtx[taskREAD]); +#endif + TAILQ_REMOVE(&r->root_read, task, task_node); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&r->root_mtx[taskREAD]); +#endif + if (r->root_hooks.hook_exec.exception) { + if (r->root_hooks.hook_exec.exception(r, NULL)) { + task->task_type = taskUNUSE; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&r->root_mtx[taskUNUSE]); +#endif + TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&r->root_mtx[taskUNUSE]); +#endif + } else { + task->task_type = taskREADY; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&r->root_mtx[taskREADY]); +#endif + TAILQ_INSERT_TAIL(&r->root_ready, task, task_node); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&r->root_mtx[taskREADY]); +#endif + } + } else { + task->task_type = taskREADY; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&r->root_mtx[taskREADY]); +#endif + TAILQ_INSERT_TAIL(&r->root_ready, task, task_node); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&r->root_mtx[taskREADY]); +#endif + } + } + /* if match equal to 1, remove resouce */ + if (flg == 1) + FD_CLR(i, &r->root_fds[0]); + } + if (FD_ISSET(i, &wfd)) { + flg = 0; + TAILQ_FOREACH_SAFE(task, &r->root_write, task_node, tmp) { + if (TASK_FD(task) != i) + continue; + else { + flg++; + TASK_RET(task) ^= TASK_RET(task); + TASK_FLAG(task) ^= TASK_FLAG(task); + } + /* remove write handle */ +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&r->root_mtx[taskWRITE]); +#endif + TAILQ_REMOVE(&r->root_write, task, task_node); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&r->root_mtx[taskWRITE]); +#endif + if (r->root_hooks.hook_exec.exception) { + if (r->root_hooks.hook_exec.exception(r, NULL)) { + task->task_type = taskUNUSE; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&r->root_mtx[taskUNUSE]); +#endif + TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&r->root_mtx[taskUNUSE]); +#endif + } else { + task->task_type = taskREADY; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&r->root_mtx[taskREADY]); +#endif + TAILQ_INSERT_TAIL(&r->root_ready, task, task_node); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&r->root_mtx[taskREADY]); +#endif + } + } else { + task->task_type = taskREADY; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&r->root_mtx[taskREADY]); +#endif + TAILQ_INSERT_TAIL(&r->root_ready, task, task_node); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&r->root_mtx[taskREADY]); +#endif + } + } + /* if match equal to 1, remove resouce */ + if (flg == 1) + FD_CLR(i, &r->root_fds[1]); + } + } + + /* optimize select */ + for (i = r->root_kq - 1; i > 2; i--) + if (FD_ISSET(i, &r->root_fds[0]) || FD_ISSET(i, &r->root_fds[1])) + break; + if (i > 2) + r->root_kq = i + 1; +#endif /* KQ_DISABLE */ + +skip_event: /* timer update & put in ready queue */ clock_gettime(CLOCK_MONOTONIC, &now);