From owner-p4-projects Wed Aug 28 17: 1: 5 2002 Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 8596837B413; Wed, 28 Aug 2002 17:00:16 -0700 (PDT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id F127237B405 for ; Wed, 28 Aug 2002 17:00:14 -0700 (PDT) Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 24BB143E8A for ; Wed, 28 Aug 2002 16:59:15 -0700 (PDT) (envelope-from mini@freebsd.org) Received: from freefall.freebsd.org (perforce@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.4/8.12.4) with ESMTP id g7SNx4JU022843 for ; Wed, 28 Aug 2002 16:59:04 -0700 (PDT) (envelope-from mini@freebsd.org) Received: (from perforce@localhost) by freefall.freebsd.org (8.12.4/8.12.4/Submit) id g7SNx4Qa022840 for perforce@freebsd.org; Wed, 28 Aug 2002 16:59:04 -0700 (PDT) Date: Wed, 28 Aug 2002 16:59:04 -0700 (PDT) Message-Id: <200208282359.g7SNx4Qa022840@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: perforce set sender to mini@freebsd.org using -f From: Jonathan Mini Subject: PERFORCE change 16716 for review To: Perforce Change Reviews Sender: owner-p4-projects@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG http://people.freebsd.org/~peter/p4db/chv.cgi?CH=16716 Change 16716 by mini@mini_stylus on 2002/08/28 16:58:11 - Invert the logic in thread_userret(), so that we don't have so many nested blocks. - Split out the logic to determine whether we upcall on the current thread or just discard it into thread_consider_upcalling(). - Don't upcall on a thread when its UTS is busy. Affected files ... .. //depot/projects/kse/sys/kern/kern_thread.c#92 edit Differences ... ==== //depot/projects/kse/sys/kern/kern_thread.c#92 (text+ko) ==== @@ -483,145 +483,194 @@ } /* - * The extra work we go through if we are a threaded process when we - * return to userland + * Consider whether or not an upcall should be made, and update the + * TDF_UPCALLING flag appropriately. + * + * This function is called when the current thread had been bound to a user + * thread that performed a syscall that blocked, and is now returning. + * Got that? syscall -> msleep -> wakeup -> syscall_return -> us. + * + * This thread will be returned to the UTS in its mailbox as a completed + * thread. We need to decide whether or not to perform an upcall now, + * or simply queue the thread for later. + * + * XXXKSE Future enhancement: We could also return back to + * the thread if we haven't had to do an upcall since then. + * If the KSE's copy is == the thread's copy, and there are + * no other completed threads. + */ +static int +thread_consider_upcalling(struct proc *p, struct ksegrp *kg, struct kse *ke, + struct thread *td, struct trapframe *frame) +{ + int discard, error; + + /* + * Save the thread's context, and link it + * into the KSE's list of completed threads. + */ + error = thread_export_context(td); + td->td_mailbox = NULL; + if (error) + /* + * Failing to do the KSE operation just defaults + * back to synchonous operation, so just return from + * the syscall. + */ + return (error); + + /* + * Second, decide whether to perfom an upcall now. + */ + discard = 0; + + /* Make sure there are no other threads waiting to run. */ + if (TAILQ_FIRST(&kg->kg_runq)) + /* + * Another thread in this KSEG needs to run. + * Switch to it instead of performing an upcall, + * abondoning this thread. + * + * XXXKSE - As for the other threads to run; + * we COULD rush through all the threads + * in this KSEG at this priority, or we + * could throw the ball back into the court + * and just run the highest prio kse available. + * What is OUR priority? The priority of the highest + * sycall waiting to be returned? + * For now, just let another KSE run (easiest). + */ + discard = 1; + + /* Make sure the KSE's UTS context is free for use. */ + if (fuword((caddr_t)ke->ke_mailbox + + offsetof(struct kse_mailbox, km_context) + + offsetof(ucontext_t, uc_busy)) != 0) + /* + * The KSE's UTS context is currently marked busy. This + * means the UTS is currently running, so switch to it + * instead of performing another upcall (abandon this + * thread). + */ + discard = 1; + + /* Discard thread or mark for upcall. */ + if (discard) { + /* + * Perform the upcall later; discard this thread for + * now. + * + * XXXKSE Future enhancement: Shove threads in this + * state onto a list of completed threads hanging + * off the KSEG. Then, collect them before performing + * an upcall. This way, we don't commit to an upcall + * on a particular KSE, but report completed threads on + * the next upcall to any KSE in this KSEG. + * + */ + PROC_LOCK(p); + mtx_lock_spin(&sched_lock); + thread_exit(); /* Abandon current thread. */ + /* NOTREACHED */ + } else + /* + * Perform an upcall now. + * + * XXXKSE - Assumes we are going to userland, and not + * nested in the kernel. + */ + td->td_flags |= TDF_UPCALLING; + return (0); +} + +/* + * The extra work we go through if we are a threaded process when we + * return to userland. * * If we are a KSE process and returning to user mode, check for * extra work to do before we return (e.g. for more syscalls * to complete first). If we were in a critical section, we should * just return to let it finish. Same if we were in the UTS (in - * which case we will have no thread mailbox registered). The only - * traps we suport will have set the mailbox. We will clear it here. + * which case the mailbox's context's busy indicator will equal the + * struct thread address). The only traps we suport will have set the + * mailbox. We will clear it here. */ int thread_userret(struct proc *p, struct ksegrp *kg, struct kse *ke, struct thread *td, struct trapframe *frame) { - int error = 0; + int error; caddr_t ucp; ucontext_t uc; + /* + * Ensure that we have a spare thread available. + */ if (ke->ke_tdspare == NULL) { ke->ke_tdspare = thread_alloc(); } - if (td->td_flags & TDF_UNBOUND) { + + /* + * Bound threads need no additional work. + */ + if ((td->td_flags & TDF_UNBOUND) == 0) { + return (0); + } + error = 0; + + /* + * Decide whether or not we should perform an upcall now. + */ + if (((td->td_flags & TDF_UPCALLING) == 0) && td->td_mailbox) { + error = thread_consider_upcalling(p, kg, ke, td, frame); + if (error != 0) + goto cont; + } + if (td->td_flags & TDF_UPCALLING) { /* - * Are we returning from a thread that had a mailbox? - * - * XXX Maybe this should be in a separate function. + * There is no more work to do and we are going to ride + * this thead/KSE up to userland. */ - if (((td->td_flags & TDF_UPCALLING) == 0) && td->td_mailbox) { - /* - * [XXXKSE Future enhancement] - * We could also go straight back to the syscall - * if we never had to do an upcall since then. - * If the KSE's copy is == the thread's copy.. - * AND there are no other completed threads. - */ - /* - * We will go back as an upcall or go do another thread. - * Either way we need to save the context back to - * the user thread mailbox. - * So the UTS can restart it later. - */ - error = thread_export_context(td); - td->td_mailbox = NULL; - if (error) { - /* - * Failing to do the KSE - * operation just defaults operation - * back to synchonous operation. - */ - goto cont; - } + CTR3(KTR_PROC, "userret: upcall thread %p (pid %d, %s)", + td, p->p_pid, p->p_comm); - if (TAILQ_FIRST(&kg->kg_runq)) { - /* - * Uh-oh.. don't return to the user. - * Instead, switch to the thread that - * needs to run. The question is: - * What do we do with the thread we have now? - * We have put the completion block - * on the kse mailbox. If we had more energy, - * we could lazily do so, assuming someone - * else might get to userland earlier - * and deliver it earlier than we could. - * To do that we could save it off the KSEG. - * An upcalling KSE would 'reap' all completed - * threads. - * Being in a hurry, we'll do nothing and - * leave it on the current KSE for now. - * - * As for the other threads to run; - * we COULD rush through all the threads - * in this KSEG at this priority, or we - * could throw the ball back into the court - * and just run the highest prio kse available. - * What is OUR priority? - * the priority of the highest sycall waiting - * to be returned? - * For now, just let another KSE run (easiest). - */ - PROC_LOCK(p); - mtx_lock_spin(&sched_lock); - thread_exit(); /* Abandon current thread. */ - /* NOTREACHED */ - } else { /* if (number of returning syscalls = 1) */ - /* - * Swap our frame for the upcall frame. - * - * XXXKSE Assumes we are going to user land - * and not nested in the kernel - */ - td->td_flags |= TDF_UPCALLING; - } - } /* - * This is NOT just an 'else' clause for the above test... + * Fetch the current UTS context from userland. */ - if (td->td_flags & TDF_UPCALLING) { - CTR3(KTR_PROC, "userret: upcall thread %p (pid %d, %s)", - td, p->p_pid, p->p_comm); + ucp = (caddr_t)ke->ke_mailbox + + offsetof(struct kse_mailbox, km_context); + error = copyin(ucp, &uc, sizeof(ucontext_t)); + if (error) /* - * There is no more work to do and we are going to ride - * this thead/KSE up to userland. + * Failing to do the KSE operation just defaults + * back to synchonous operation, so just return from + * the syscall. */ + goto cont; - /* - * Set user/machine context to the UTS. - */ - ucp = (caddr_t)ke->ke_mailbox + - offsetof(struct kse_mailbox, km_context); - if (copyin(ucp, &uc, sizeof(ucontext_t)) != 0) - /* - * If copyin() fails here, act as if it had - * read nothing but nulls. This will cause - * the process to crash from the bogus state - * information. - */ - bzero(&uc, sizeof(ucontext_t)); - thread_setcontext(td, &uc); - /* Mark the context busy (XXXSMP: must be atomic). */ - suword(ucp + offsetof(ucontext_t, uc_busy), 1); + /* + * Set user context to the UTS's. + * + * XXX - Add the busy marker to thread_setcontext(). + */ + thread_setcontext(td, &uc); + suword(ucp + offsetof(ucontext_t, uc_busy), (intptr_t)td); - /* - * Make sure the user's pointer to the thread - * mailbox is cleared before we re-enter the kernel - * next time for any reason.. - */ - td->td_flags &= ~TDF_UPCALLING; /* Hmmmm. */ - error = suword((caddr_t)td->td_kse->ke_mailbox + - offsetof(struct kse_mailbox, km_curthread), - 0); - } /* - * Stop any chance that we may be separated from - * the KSE we are currently on. This is "biting the bullet", - * we are committing to go to user space as as THIS KSE here. + * Set state and mailbox. */ + td->td_flags &= ~TDF_UPCALLING; + error = suword((caddr_t)td->td_kse->ke_mailbox + + offsetof(struct kse_mailbox, km_curthread), + 0); + } cont: - td->td_flags &= ~TDF_UNBOUND; - } + /* + * Stop any chance that we may be separated from + * the KSE we are currently on. This is "biting the bullet", + * we are committing to go to user space as as this KSE here. + */ + td->td_flags &= ~TDF_UNBOUND; /* Bind to this user thread. */ return (error); } To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe p4-projects" in the body of the message