From owner-p4-projects@FreeBSD.ORG Sun May 9 19:13:30 2004 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id A220716A4D0; Sun, 9 May 2004 19:13:29 -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 67A6616A4CE for ; Sun, 9 May 2004 19:13:29 -0700 (PDT) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 18FAA43D53 for ; Sun, 9 May 2004 19:13:28 -0700 (PDT) (envelope-from julian@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.12.10/8.12.10) with ESMTP id i4A2DSGe022545 for ; Sun, 9 May 2004 19:13:28 -0700 (PDT) (envelope-from julian@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.12.10/8.12.10/Submit) id i4A2DRRx022542 for perforce@freebsd.org; Sun, 9 May 2004 19:13:27 -0700 (PDT) (envelope-from julian@freebsd.org) Date: Sun, 9 May 2004 19:13:27 -0700 (PDT) Message-Id: <200405100213.i4A2DRRx022542@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to julian@freebsd.org using -f From: Julian Elischer To: Perforce Change Reviews Subject: PERFORCE change 52575 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 10 May 2004 02:13:30 -0000 http://perforce.freebsd.org/chv.cgi?CH=52575 Change 52575 by julian@julian_ref on 2004/05/09 19:12:45 checkin for safety Affected files ... .. //depot/projects/nsched/sys/i386/i386/machdep.c#5 edit .. //depot/projects/nsched/sys/kern/kern_exit.c#4 edit .. //depot/projects/nsched/sys/kern/kern_kse.c#4 edit .. //depot/projects/nsched/sys/kern/kern_synch.c#3 edit .. //depot/projects/nsched/sys/kern/kern_thr.c#4 edit .. //depot/projects/nsched/sys/kern/kern_thread.c#11 edit .. //depot/projects/nsched/sys/kern/sched_4bsd.c#6 edit .. //depot/projects/nsched/sys/sys/proc.h#6 edit .. //depot/projects/nsched/sys/sys/sched.h#4 edit Differences ... ==== //depot/projects/nsched/sys/i386/i386/machdep.c#5 (text+ko) ==== @@ -1950,15 +1950,18 @@ int gsel_tss, metadata_missing, off, x; struct pcpu *pc; + /* + * Set up things that proc0 would have associated with it already + * if it were taken from the process allocation cache. + * This includes a ksegrp, a thread, and a stack and uarea to go + * with the thread. The pcb is deliniated ready for use. + * Note that the stack for proc0 has no guard page. + */ proc0.p_uarea = proc0uarea; thread0.td_kstack = proc0kstack; thread0.td_pcb = (struct pcb *) (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; atdevbase = ISA_HOLE_START + KERNBASE; - - /* - * Link a few more bits of the proc0 together. - */ proc_linkup(&proc0, &ksegrp0, &thread0); metadata_missing = 0; ==== //depot/projects/nsched/sys/kern/kern_exit.c#4 (text+ko) ==== @@ -155,6 +155,12 @@ */ if (thread_single(SINGLE_EXIT)) panic ("Exit: Single threading fouled up"); + /* + * For this to happen, the thread_suspend_check(0) + * above must have failed to kill a sibling + * even though we should have gone single-file + * because of the PROC lock. + */ /* * All other activity in this process is now stopped. * Remove excess KSEs and KSEGRPS. XXXKSE (when we have them) @@ -162,18 +168,8 @@ * Turn off threading support. */ p->p_flag &= ~P_SA; - thread_single_end(); /* Don't need this any more. */ + thread_single_end(); /* end single-threading mode */ } - /* - * With this state set: - * Any thread entering the kernel from userspace will thread_exit() - * in trap(). Any thread attempting to sleep will return immediatly - * with EINTR or EWOULDBLOCK, which will hopefully force them - * to back out to userland, freeing resources as they go, and - * anything attempting to return to userland will thread_exit() - * from userret(). thread_exit() will do a wakeup on p->p_numthreads - * if it transitions to 1. - */ p->p_flag |= P_WEXIT; PROC_UNLOCK(p); @@ -391,16 +387,6 @@ lim_free(plim); /* - * Release this thread's reference to the ucred. The actual proc - * reference will stay around until the proc is harvested by - * wait(). At this point the ucred is immutable (no other threads - * from this proc are around that can change it) so we leave the - * per-thread ucred pointer intact in case it is needed although - * in theory nothing should be using it at this point. - */ - crfree(td->td_ucred); - - /* * Remove proc from allproc queue and pidhash chain. * Place onto zombproc. Unlink from parent's child list. */ @@ -503,6 +489,15 @@ */ cpu_exit(td); + /* + * Release this thread's reference to the ucred. The actual proc + * reference will stay around until the proc is harvested by + * wait(). XXX maybe this should be done there too. + */ + crfree(td->td_ucred); + td->td_ucred = NULL; + + PROC_LOCK(p); PROC_LOCK(p->p_pptr); sx_xunlock(&proctree_lock); @@ -533,7 +528,7 @@ cpu_sched_exit(td); /* XXXKSE check if this should be in thread_exit */ /* * Allow the scheduler to adjust the priority of the - * parent when a kseg is exiting. + * parent when a process is exiting. */ if (p->p_pid != 1) sched_exit(p->p_pptr, td); ==== //depot/projects/nsched/sys/kern/kern_kse.c#4 (text+ko) ==== @@ -444,7 +444,7 @@ PROC_LOCK(p); if (!(p->p_flag & P_SA)) { first = 1; - p->p_flag |= P_SA; + p->p_flag |= P_SA|P_HADTHREADS; } PROC_UNLOCK(p); if (!sa && !uap->newgroup && !first) ==== //depot/projects/nsched/sys/kern/kern_synch.c#3 (text+ko) ==== @@ -361,7 +361,7 @@ p->p_comm); if (td->td_proc->p_flag & P_SA) thread_switchout(td); - sched_switch(td); + sched_switch(td, flags); CTR3(KTR_PROC, "mi_switch: new thread %p (pid %d, %s)", td, p->p_pid, p->p_comm); ==== //depot/projects/nsched/sys/kern/kern_thr.c#4 (text+ko) ==== @@ -101,7 +101,7 @@ sched_exit_thread(p->p_pptr, td); thread_stash(td); - cpu_throw(td, choosethread()); + cpu_throw(td, choosethread(SW_VOL)); } #define RANGEOF(type, start, end) (offsetof(type, end) - offsetof(type, start)) @@ -141,6 +141,7 @@ td0->td_proc = td->td_proc; PROC_LOCK(td->td_proc); td0->td_sigmask = td->td_sigmask; + td->td_proc->p_flag |= P_HADTHREADS; PROC_UNLOCK(td->td_proc); td0->td_ucred = crhold(td->td_ucred); ==== //depot/projects/nsched/sys/kern/kern_thread.c#11 (text+ko) ==== @@ -395,7 +395,11 @@ } /* - * Reap zombie kse resource. + * Reap zombie thread resources. + * These include threads & ksegrps that were still live and in use + * at they were exiting, and possibly other structures associated + * with them by the threading and scheduling modules that could not + * be freed until the running thread had completly stopped running. */ void thread_reap(void) @@ -406,6 +410,8 @@ /* * Don't even bother to lock if none at this instant, * we really don't care about the next instant.. + * Note, never call the other GC routines unless we have a + * thread or ksegrp to clean up as well. */ if ((!TAILQ_EMPTY(&zombie_threads)) || (!TAILQ_EMPTY(&zombie_ksegrps))) { @@ -522,11 +528,24 @@ /* * Discard the current thread and exit from its context. + * Always called with scheduler locked. * * Because we can't free a thread while we're operating under its context, * push the current thread into our CPU's deadthread holder. This means * we needn't worry about someone else grabbing our context before we - * do a cpu_throw(). + * do a cpu_throw(). This may not be needed now as we are under schedlock. + * Maybe we can just do a thread_stash() as thr_exit1 does. + */ +/* XXX + * libthr expects its thread exit to return for the last + * thread, meaning that the program is back to non-threaded + * mode I guess. Because we do this (cpu_throw) unconditionally + * here, they have their own version of it. (thr_exit1()) + * that doesn't do it all if this was the last thread. + * It is also called from thread_suspend_check(). + * Of course in the end, they end up coming here through exit1 + * anyhow.. After fixing 'thr' to play by the rules we should be able + * to merge these two functions together. */ void thread_exit(void) @@ -556,48 +575,59 @@ /* * The last thread is left attached to the process * So that the whole bundle gets recycled. Skip - * all this stuff. + * all this stuff if we never had threads. */ - if (p->p_numthreads > 1) { - thread_unlink(td); - if (p->p_maxthrwaits) - wakeup(&p->p_numthreads); - /* - * The test below is NOT true if we are the - * sole exiting thread. P_STOPPED_SINGLE is unset - * in exit1() after it is the only survivor. - */ - if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { - if (p->p_numthreads == p->p_suspcount) { - thread_unsuspend_one(p->p_singlethread); + if (p->p_flag & P_HADTHREADS) { + if (p->p_numthreads > 1) { + thread_unlink(td); + if (p->p_maxthrwaits) + wakeup(&p->p_numthreads); + /* + * The test below is NOT true if we are the + * sole exiting thread. P_STOPPED_SINGLE is unset + * in exit1() after it is the only survivor. + */ + if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { + if (p->p_numthreads == p->p_suspcount) { + thread_unsuspend_one(p->p_singlethread); + } } - } - /* - * Because each upcall structure has an owner thread, - * owner thread exits only when process is in exiting - * state, so upcall to userland is no longer needed, - * deleting upcall structure is safe here. - * So when all threads in a group is exited, all upcalls - * in the group should be automatically freed. - */ - if (td->td_upcall) - upcall_remove(td); + /* + * Because each upcall structure has an owner thread, + * owner thread exits only when process is in exiting + * state, so upcall to userland is no longer needed, + * deleting upcall structure is safe here. + * So when all threads in a group is exited, all upcalls + * in the group should be automatically freed. + * XXXKSE This is a KSE thing and should be exported + * there somehow. + */ + if (td->td_upcall) + upcall_remove(td); - sched_exit_thread(td->td_proc->p_pptr, td); - PROC_UNLOCK(p); - td->td_state = TDS_INACTIVE; -#if 0 - td->td_proc = NULL; -#endif - td->td_ksegrp = NULL; - PCPU_SET(deadthread, td); - } else { - PROC_UNLOCK(p); + if (kg->kg_numthreads == 0) { + /* This kseg is kaput */ + sched_set_concurrancy(kg, 0); + ksegrp_unlink(kg); + } + + sched_exit_thread(td->td_proc->p_pptr, td); + td->td_state = TDS_INACTIVE; + #if 0 + td->td_proc = NULL; + #endif + td->td_ksegrp = NULL; + PCPU_SET(deadthread, td); + } else { + if (p->p_numthreads == 1 ) { + sched_set_concurrancy(kg, 1); + } + } } - /* XXX Shouldn't cpu_throw() here. */ + PROC_UNLOCK(p); mtx_assert(&sched_lock, MA_OWNED); - cpu_throw(td, choosethread()); + cpu_throw(td, choosethread(SW_VOL)); panic("I'm a teapot!"); /* NOTREACHED */ } ==== //depot/projects/nsched/sys/kern/sched_4bsd.c#6 (text+ko) ==== @@ -148,6 +148,7 @@ int skg_runq_kses; /* (j) Num KSEs on runq. */ int skg_idle_kses; /* (j) Num KSEs on iq. */ int skg_kses; /* (j) Num KSEs in group. */ + int skg_concurrancy; /* (j) desired concurrancy */ }; #define kg_kseq kg_sched->skg_kseq #define kg_iq kg_sched->skg_iq @@ -751,7 +752,7 @@ } void -sched_switch(struct thread *td) +sched_switch(struct thread *td, int flags) { struct thread *newtd; struct kse *ke; @@ -785,7 +786,7 @@ */ kse_reassign(ke); } - newtd = choosethread(); + newtd = choosethread(flags); if (td != newtd) cpu_switch(td, newtd); sched_lock.mtx_lock = (uintptr_t)td; @@ -1297,12 +1298,28 @@ childtd->td_last_kse = NULL; } +/* + * Whenever we have idle KSEs and there are too many for the concurrancy, + * then free as many as we can. + */ +#define REDUCE_KSES(skg) \ +do { \ + while ((skg->skg_concurrancy < skg->skg_kses) && \ + (skg->skg_idle_kses > 0)) { \ + kse_unlink(TAILQ_FIRST(&skg->skg_iq)); \ + } \ +} while (0) + void sched_set_concurrancy(struct ksegrp *kg, int concurrancy) { struct kse *newke; + struct kg_sched *skg; - while (kg->kg_kses < concurrancy) { + skg = kg->kg_sched; + skg->skg_concurrancy = concurrancy; + REDUCE_KSES(skg); + while (skg->skg_kses < skg->skg_concurrancy) { newke = kse_alloc(); bzero(&newke->ke_startzero, RANGEOF(struct kse, ke_startzero, ke_endzero)); @@ -1426,7 +1443,7 @@ * if the switch is voluntary or involuntary. */ struct thread * -choosethread(void) +choosethread(int flags) { struct kse *ke; struct thread *td; @@ -1445,7 +1462,16 @@ #endif retry: - ke = sched_choose(); + kg = curthread->td_ksegrp; +#if 0 + if (flags & SW_VOL) { + if (kg->kg_runnable) { + td = TAILQ_FIRST(&kg->kg_runq); + } + } + if (ke == NULL) +#endif + ke = sched_choose(); if (ke) { td = ke->ke_thread; KASSERT((td->td_kse == ke), ("kse/thread mismatch")); @@ -1528,6 +1554,7 @@ TAILQ_INSERT_TAIL(&kg->kg_iq, ke, ke_kgrlist); kg->kg_idle_kses++; CTR1(KTR_RUNQ, "kse_reassign: ke%p on idle queue", ke); + REDUCE_KSES(kg->kg_sched); /* if we are closing down discard it */ return; } ==== //depot/projects/nsched/sys/sys/proc.h#6 (text+ko) ==== @@ -532,9 +532,7 @@ #define NOCPU 0xff /* For when we aren't on a CPU. (SMP) */ -/* Status values (p_stat). */ - -/* These flags are kept in p_flag. */ +/* These flags are kept in p_flag. Only change under PROC LOCK */ #define P_ADVLOCK 0x00001 /* Process may hold a POSIX advisory lock. */ #define P_CONTROLT 0x00002 /* Has a controlling terminal. */ #define P_KTHREAD 0x00004 /* Kernel thread. (*)*/ @@ -542,6 +540,7 @@ #define P_PPWAIT 0x00010 /* Parent is waiting for child to exec/exit. */ #define P_PROFIL 0x00020 /* Has started profiling. */ #define P_STOPPROF 0x00040 /* Has thread in requesting to stop prof */ +#define P_HADTHREADS 0x00080 /* Has had threads (no cleanup shortcuts) */ #define P_SUGID 0x00100 /* Had set id privileges since last exec. */ #define P_SYSTEM 0x00200 /* System proc: no sigs, stats or swapping. */ #define P_SINGLE_EXIT 0x00400 /* Threads suspending should exit, not wait. */ @@ -739,7 +738,7 @@ void adjustrunqueue(struct thread *, int newpri); void ast(struct trapframe *framep); -struct thread *choosethread(void); +struct thread *choosethread(int flags); int cr_cansignal(struct ucred *cred, struct proc *proc, int signum); int enterpgrp(struct proc *p, pid_t pgid, struct pgrp *pgrp, struct session *sess); int enterthispgrp(struct proc *p, struct pgrp *pgrp); ==== //depot/projects/nsched/sys/sys/sched.h#4 (text+ko) ==== @@ -67,7 +67,7 @@ fixpt_t sched_pctcpu(struct thread *td); void sched_prio(struct thread *td, u_char prio); void sched_sleep(struct thread *td); -void sched_switch(struct thread *td); +void sched_switch(struct thread *td, int flags); void sched_userret(struct thread *td); void sched_wakeup(struct thread *td);