From owner-p4-projects@FreeBSD.ORG Sat Dec 9 17:26:03 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 607C116A4CA; Sat, 9 Dec 2006 17:26:03 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 22E5B16A47E for ; Sat, 9 Dec 2006 17:26:03 +0000 (UTC) (envelope-from piso@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.FreeBSD.org (Postfix) with ESMTP id 78A3543C9D for ; Sat, 9 Dec 2006 17:24:57 +0000 (GMT) (envelope-from piso@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id kB9HQ2Oh029478 for ; Sat, 9 Dec 2006 17:26:02 GMT (envelope-from piso@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id kB9HQ2tW029475 for perforce@freebsd.org; Sat, 9 Dec 2006 17:26:02 GMT (envelope-from piso@freebsd.org) Date: Sat, 9 Dec 2006 17:26:02 GMT Message-Id: <200612091726.kB9HQ2tW029475@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to piso@freebsd.org using -f From: Paolo Pisati To: Perforce Change Reviews Cc: Subject: PERFORCE change 111336 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 09 Dec 2006 17:26:03 -0000 http://perforce.freebsd.org/chv.cgi?CH=111336 Change 111336 by piso@piso_newluxor on 2006/12/09 17:25:17 Add a private per handler ithread for every filtered driver. Affected files ... .. //depot/projects/soc2006/intr_filter/i386/i386/intr_machdep.c#16 edit .. //depot/projects/soc2006/intr_filter/kern/kern_intr.c#18 edit .. //depot/projects/soc2006/intr_filter/sys/interrupt.h#7 edit Differences ... ==== //depot/projects/soc2006/intr_filter/i386/i386/intr_machdep.c#16 (text+ko) ==== @@ -235,6 +235,7 @@ { struct thread *td; struct intr_event *ie; + struct intr_thread *ithd = NULL; int error, vector, thread; td = curthread; @@ -275,9 +276,9 @@ } td->td_intr_nesting_level++; - thread = 0; + thread = 0; critical_enter(); - thread = intr_filter_loop(ie, frame); + thread = intr_filter_loop(ie, frame, &ithd); /* * If the interrupt was fully served, send it an EOI but leave it @@ -299,9 +300,9 @@ mtx_unlock_spin(&intr_table_lock); } - /* Schedule the ithread if needed. */ + /* Schedule an ithread if needed. */ if (thread & FILTER_SCHEDULE_THREAD) { - error = intr_event_schedule_thread(ie); + error = intr_event_schedule_thread(ie, ithd); KASSERT(error == 0, ("bad stray interrupt")); } td->td_intr_nesting_level--; ==== //depot/projects/soc2006/intr_filter/kern/kern_intr.c#18 (text+ko) ==== @@ -96,9 +96,12 @@ TAILQ_HEAD_INITIALIZER(event_list); static void intr_event_update(struct intr_event *ie); -static struct intr_thread *ithread_create(const char *name); +static struct intr_thread *ithread_create(const char *name, + struct intr_handler *ih); static void ithread_destroy(struct intr_thread *ithread); static void ithread_execute_handlers(struct proc *p, struct intr_event *ie); +static void priv_ithread_execute_handler(struct proc *p, + struct intr_handler *ih); static void ithread_loop(void *); static void ithread_update(struct intr_thread *ithd); static void start_softintr(void *); @@ -286,7 +289,7 @@ } static struct intr_thread * -ithread_create(const char *name) +ithread_create(const char *name, struct intr_handler *ih) { struct intr_thread *ithd; struct thread *td; @@ -295,7 +298,7 @@ ithd = malloc(sizeof(struct intr_thread), M_ITHREAD, M_WAITOK | M_ZERO); - error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, + error = kthread_create(ithread_loop, ih, &p, RFSTOPPED | RFHIGHPID, 0, "%s", name); if (error) panic("kthread_create() failed with %d", error); @@ -378,20 +381,29 @@ TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); intr_event_update(ie); - /* Create a thread if we need one. */ - while (ie->ie_thread == NULL && handler != NULL) { - if (ie->ie_flags & IE_ADDING_THREAD) - msleep(ie, &ie->ie_lock, 0, "ithread", 0); - else { - ie->ie_flags |= IE_ADDING_THREAD; - mtx_unlock(&ie->ie_lock); - it = ithread_create("intr: newborn"); - mtx_lock(&ie->ie_lock); - ie->ie_flags &= ~IE_ADDING_THREAD; - ie->ie_thread = it; - it->it_event = ie; - ithread_update(it); - wakeup(ie); + /* For filtered handlers, create a private ithread to run on. */ + if (filter != NULL && handler != NULL) { + mtx_unlock(&ie->ie_lock); + it = ithread_create("intr: newborn", ih); + mtx_lock(&ie->ie_lock); + it->it_event = ie; + ih->ih_thread = it; + ithread_update(it); // XXX - do we really need this?!?!? + } else { /* Create the global per-event thread if we need one. */ + while (ie->ie_thread == NULL && handler != NULL) { + if (ie->ie_flags & IE_ADDING_THREAD) + msleep(ie, &ie->ie_lock, 0, "ithread", 0); + else { + ie->ie_flags |= IE_ADDING_THREAD; + mtx_unlock(&ie->ie_lock); + it = ithread_create("intr: newborn", ih); + mtx_lock(&ie->ie_lock); + ie->ie_flags &= ~IE_ADDING_THREAD; + ie->ie_thread = it; + it->it_event = ie; + ithread_update(it); + wakeup(ie); + } } } CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name, @@ -408,6 +420,7 @@ { struct intr_handler *handler = (struct intr_handler *)cookie; struct intr_event *ie; + struct intr_thread *it; #ifdef INVARIANTS struct intr_handler *ih; #endif @@ -434,17 +447,19 @@ ok: #endif /* - * If there is no ithread, then just remove the handler and return. - * XXX: Note that an INTR_FAST handler might be running on another - * CPU! + * If there are no ithreads (per event and per handler), then + * just remove the handler and return. + * XXX: Note that an INTR_FAST handler might be running on another CPU! */ - if (ie->ie_thread == NULL) { + if (ie->ie_thread == NULL && handler->ih_thread == NULL) { TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next); mtx_unlock(&ie->ie_lock); free(handler, M_ITHREAD); return (0); } + /* Private or global ithread? */ + it = (handler->ih_thread) ? handler->ih_thread : ie->ie_thread; /* * If the interrupt thread is already running, then just mark this * handler as being dead and let the ithread do the actual removal. @@ -454,7 +469,7 @@ * thread do it. */ mtx_lock_spin(&sched_lock); - if (!TD_AWAITING_INTR(ie->ie_thread->it_thread) && !cold) { + if (!TD_AWAITING_INTR(it->it_thread) && !cold) { handler->ih_flags |= IH_DEAD; /* @@ -462,12 +477,20 @@ * again and remove this handler if it has already passed * it on the list. */ - ie->ie_thread->it_need = 1; + it->it_need = 1; } else TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next); mtx_unlock_spin(&sched_lock); while (handler->ih_flags & IH_DEAD) msleep(handler, &ie->ie_lock, 0, "iev_rmh", 0); + /* + * At this point, the handler has been disconnected from the event, + * so we can kill the private ithread if any. + */ + if (handler->ih_thread) { + ithread_destroy(handler->ih_thread); + handler->ih_thread = NULL; + } intr_event_update(ie); #ifdef notyet /* @@ -493,10 +516,9 @@ } int -intr_event_schedule_thread(struct intr_event *ie) +intr_event_schedule_thread(struct intr_event *ie, struct intr_thread *it) { struct intr_entropy entropy; - struct intr_thread *it; struct thread *td; struct thread *ctd; struct proc *p; @@ -504,12 +526,10 @@ /* * If no ithread or no handlers, then we have a stray interrupt. */ - if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers) || - ie->ie_thread == NULL) + if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers) || it == NULL) return (EINVAL); ctd = curthread; - it = ie->ie_thread; td = it->it_thread; p = td->td_proc; @@ -603,7 +623,7 @@ if (!(flags & SWI_DELAY)) { PCPU_LAZY_INC(cnt.v_soft); - error = intr_event_schedule_thread(ie); + error = intr_event_schedule_thread(ie, ie->ie_thread); KASSERT(error == 0, ("stray software interrupt")); } } @@ -622,6 +642,37 @@ } static void +priv_ithread_execute_handler(struct proc *p, struct intr_handler *ih) +{ + struct intr_event *ie; + + ie = ih->ih_event; + /* + * If this handler is marked for death, remove it from + * the list of handlers and wake up the sleeper. + */ + if (ih->ih_flags & IH_DEAD) { + mtx_lock(&ie->ie_lock); + TAILQ_REMOVE(&ie->ie_handlers, ih, ih_next); + ih->ih_flags &= ~IH_DEAD; + wakeup(ih); + mtx_unlock(&ie->ie_lock); + return; + } + + /* Execute this handler. */ + CTR6(KTR_INTR, "%s: pid %d exec %p(%p) for %s flg=%x", + __func__, p->p_pid, (void *)ih->ih_handler, ih->ih_argument, + ih->ih_name, ih->ih_flags); + + if (!(ih->ih_flags & IH_MPSAFE)) + mtx_lock(&Giant); + ih->ih_handler(ih->ih_argument); + if (!(ih->ih_flags & IH_MPSAFE)) + mtx_unlock(&Giant); +} + +static void ithread_execute_handlers(struct proc *p, struct intr_event *ie) { struct intr_handler *ih, *ihn; @@ -645,12 +696,16 @@ } /* - * Execute handlers that have their need flag set. - */ - if (!ih->ih_need) - continue; - else - atomic_store_rel_int(&ih->ih_need, 0); + * For software interrupt threads, we only execute + * handlers that have their need flag set. Hardware + * interrupt threads always invoke all of their handlers. + */ + if (ie->ie_flags & IE_SOFT) { + if (!ih->ih_need) + continue; + else + atomic_store_rel_int(&ih->ih_need, 0); + } /* Execute this handler. */ CTR6(KTR_INTR, "%s: pid %d exec %p(%p) for %s flg=%x", @@ -702,13 +757,17 @@ ithread_loop(void *arg) { struct intr_thread *ithd; + struct intr_handler *ih; struct intr_event *ie; struct thread *td; struct proc *p; + int priv; td = curthread; p = td->td_proc; - ithd = (struct intr_thread *)arg; + ih = (struct intr_handler *)arg; + priv = (ih->ih_thread != NULL) ? 1 : 0; + ithd = (priv) ? ih->ih_thread : ih->ih_event->ie_thread; KASSERT(ithd->it_thread == td, ("%s: ithread and proc linkage out of sync", __func__)); ie = ithd->it_event; @@ -742,7 +801,10 @@ * handlers. */ atomic_store_rel_int(&ithd->it_need, 0); - ithread_execute_handlers(p, ie); + if (priv) + priv_ithread_execute_handler(p, ih); + else + ithread_execute_handlers(p, ie); } WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread"); mtx_assert(&Giant, MA_NOTOWNED); @@ -768,13 +830,30 @@ * Some architectures (i386, amd64 and arm) require the optional frame * parameter, and use it as the main argument for fast handler execution * when ih_argument == NULL. + * + * Return value: + * o FILTER_STRAY: No filter recognized the event, and no + * filter-less handler is registered on this + * line. + * o FILTER_HANDLED: A filter claimed the event and served it. + * o FILTER_SCHEDULE_THREAD: No filter claimed the event, but there's at + * least one filter-less handler on this line. + * o FILTER_HANDLED | + * FILTER_SCHEDULE_THREAD: A filter claimed the event, and asked for + * scheduling the per-handler ithread. + * + * In case an ithread has to be scheduled, in *ithd there will be a + * pointer to a struct intr_thread containing the thread to be + * scheduled. */ int -intr_filter_loop(struct intr_event *ie, struct trapframe *frame) { +intr_filter_loop(struct intr_event *ie, struct trapframe *frame, + struct intr_thread **ithd) +{ struct intr_handler *ih; void *arg; - int ret, ret2, thread_only; + int ret, thread_only; ret = 0; thread_only = 0; @@ -791,45 +870,30 @@ ih->ih_filter, ih->ih_handler, arg, ih->ih_name); if (ih->ih_filter != NULL) - ret2 = ih->ih_filter(arg); - else { - /* Legacy ithread only handler. */ + ret = ih->ih_filter(arg); + else { thread_only = 1; continue; } - /* Mark handler for later execution in ithread. */ - if (ret2 & FILTER_SCHEDULE_THREAD) { - ih->ih_need = 1; - ret |= FILTER_SCHEDULE_THREAD; + KASSERT(ret != FILTER_SCHEDULE_THREAD, + "intr_filter_loop: FILTER_SCHEDULE_THREAD from filter"); + + if (ret & FILTER_STRAY) continue; - } - - /* Interrupt served in filter. */ - if (ret2 & FILTER_HANDLED) { - ret |= FILTER_HANDLED; + else { + *ithd = ih->ih_thread; return (ret); } } /* - * A filter did claim the interrupt but didn't shut it up - * fully, so schedule the ithread. - */ - if (ret != 0) - return (ret); - - /* * No filters handled the interrupt and we have at least * one handler without a filter. In this case, we schedule * all of the filter-less handlers to run in the ithread. */ if (thread_only) { - TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) { - if (ih->ih_filter != NULL) - continue; - ih->ih_need = 1; - } + *ithd = ie->ie_thread; return (FILTER_SCHEDULE_THREAD); } return (FILTER_STRAY); @@ -839,6 +903,7 @@ void stray_detection(void *_arg) { + struct intr_thread *ithd = NULL; struct intr_event *ie; void *(*walk_src)(void) = _arg; int thread; @@ -852,7 +917,7 @@ /* * yes, it's still pending: call filters... */ - thread = intr_filter_loop(ie, NULL /* XXX frame */ ); + thread = intr_filter_loop(ie, NULL /* XXX frame */, &ithd); if (thread & FILTER_STRAY) { /* * no filter claimed the intr, ==== //depot/projects/soc2006/intr_filter/sys/interrupt.h#7 (text+ko) ==== @@ -52,6 +52,7 @@ int ih_need; /* Needs service. */ TAILQ_ENTRY(intr_handler) ih_next; /* Next handler for this event. */ u_char ih_pri; /* Priority of this handler. */ + struct intr_thread *ih_thread; /* Ithread for filtered handler. */ }; #define IS_FAST(filter, handler) (filter != NULL && handler == NULL) @@ -115,7 +116,8 @@ #ifdef DDB void db_dump_intr_event(struct intr_event *ie, int handlers); #endif -int intr_filter_loop(struct intr_event *ie, struct trapframe *frame); +int intr_filter_loop(struct intr_event *ie, struct trapframe *frame, + struct intr_thread **ithd); void stray_detection(void *_arg); u_char intr_priority(enum intr_type flags); int intr_event_add_handler(struct intr_event *ie, const char *name, @@ -127,7 +129,7 @@ __printflike(6, 7); int intr_event_destroy(struct intr_event *ie); int intr_event_remove_handler(void *cookie); -int intr_event_schedule_thread(struct intr_event *ie); +int intr_event_schedule_thread(struct intr_event *ie, struct intr_thread *ithd); int swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler, void *arg, int pri, enum intr_type flags, void **cookiep);