From 99df837ee712005c3c2dbc019ec40ec2947dc19f Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 27 Jun 2003 03:30:43 +0000 Subject: [PATCH] Cleanup lwkt threads a bit, change the exit/reap interlock. --- sys/i386/i386/genassym.c | 5 +- sys/i386/i386/machdep.c | 7 +- sys/i386/i386/pmap.c | 25 +--- sys/i386/i386/swtch.s | 16 +-- sys/i386/i386/vm_machdep.c | 44 ++++--- sys/kern/kern_exit.c | 28 ++-- sys/kern/kern_kthread.c | 49 +------ sys/kern/lwkt_thread.c | 188 ++++++++++++++++++++++----- sys/platform/pc32/i386/genassym.c | 5 +- sys/platform/pc32/i386/machdep.c | 7 +- sys/platform/pc32/i386/pmap.c | 25 +--- sys/platform/pc32/i386/swtch.s | 16 +-- sys/platform/pc32/i386/vm_machdep.c | 44 ++++--- sys/platform/vkernel/i386/genassym.c | 5 +- sys/sys/kthread.h | 9 +- sys/sys/proc.h | 9 +- sys/sys/thread.h | 26 ++-- sys/vm/pmap.h | 3 +- sys/vm/vm_glue.c | 4 +- 19 files changed, 288 insertions(+), 227 deletions(-) diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c index f522c2e29b..63e11f530e 100644 --- a/sys/i386/i386/genassym.c +++ b/sys/i386/i386/genassym.c @@ -35,7 +35,7 @@ * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $ - * $DragonFly: src/sys/i386/i386/Attic/genassym.c,v 1.13 2003/06/27 01:53:24 dillon Exp $ + * $DragonFly: src/sys/i386/i386/Attic/genassym.c,v 1.14 2003/06/27 03:30:37 dillon Exp $ */ #include "opt_user_ldt.h" @@ -85,8 +85,9 @@ ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); ASSYM(TD_SP, offsetof(struct thread, td_sp)); ASSYM(TD_PRI, offsetof(struct thread, td_pri)); ASSYM(TD_MACH, offsetof(struct thread, td_mach)); -ASSYM(TD_RWLOCK, offsetof(struct thread, td_rwlock)); ASSYM(TD_WCHAN, offsetof(struct thread, td_wchan)); +ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); +ASSYM(TDF_EXITED, TDF_EXITED); ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner)); diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index c96a53667d..c1f5833b3f 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -36,7 +36,7 @@ * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $ - * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.12 2003/06/25 03:55:53 dillon Exp $ + * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.13 2003/06/27 03:30:37 dillon Exp $ */ #include "apm.h" @@ -1866,14 +1866,13 @@ init386(first) */ gd = &CPU_prvspace[0].globaldata; - lwkt_init_thread(&thread0, proc0paddr); + lwkt_init_thread(&thread0, proc0paddr, 0); gd->gd_curthread = &thread0; safepri = thread0.td_cpl = SWI_MASK | HWI_MASK; thread0.td_switch = cpu_heavy_switch; /* YYY eventually LWKT */ proc0.p_addr = (void *)thread0.td_kstack; proc0.p_thread = &thread0; thread0.td_proc = &proc0; - thread0.td_flags = TDF_RUNNING; atdevbase = ISA_HOLE_START + KERNBASE; @@ -2088,7 +2087,7 @@ cpu_gdinit(struct globaldata *gd, int cpu) if (cpu) gd->gd_curthread = &gd->gd_idlethread; sp = gd->gd_prvspace->idlestack; - lwkt_init_thread(&gd->gd_idlethread, sp); + lwkt_init_thread(&gd->gd_idlethread, sp, 0); gd->gd_idlethread.td_switch = cpu_lwkt_switch; gd->gd_idlethread.td_sp -= sizeof(void *); *(void **)gd->gd_idlethread.td_sp = cpu_idle_restore; diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index dbb4099097..4548c717f4 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -40,7 +40,7 @@ * * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/i386/pmap.c,v 1.250.2.18 2002/03/06 22:48:53 silby Exp $ - * $DragonFly: src/sys/i386/i386/Attic/pmap.c,v 1.10 2003/06/22 04:30:39 dillon Exp $ + * $DragonFly: src/sys/i386/i386/Attic/pmap.c,v 1.11 2003/06/27 03:30:37 dillon Exp $ */ /* @@ -850,29 +850,6 @@ pmap_init_thread(thread_t td) td->td_sp = (char *)td->td_pcb - 16; } -/* - * Dispose of a thread, unlink it from its related proc (if any). Keep - * CACHE_NTHREAD threads around for fast-startup. - */ -void -pmap_dispose_thread(struct thread *td) -{ - /* HIPRI YYY */ - KASSERT((td->td_flags & (TDF_RUNQ|TDF_RUNNING)) == 0, - ("pmap_dispose_thread: still on queue: %08x", td->td_flags)); - if (mycpu->gd_tdfreecount < CACHE_NTHREADS) { - ++mycpu->gd_tdfreecount; - TAILQ_INSERT_HEAD(&mycpu->gd_tdfreeq, td, td_threadq); - } else { - if (td->td_kstack) { - kmem_free(kernel_map, - (vm_offset_t)td->td_kstack, UPAGES * PAGE_SIZE); - td->td_kstack = NULL; - } - zfree(thread_zone, td); - } -} - /* * Create the UPAGES for a new process. * This routine directly affects the fork perf for a process. diff --git a/sys/i386/i386/swtch.s b/sys/i386/i386/swtch.s index f9c790865e..09261b02fc 100644 --- a/sys/i386/i386/swtch.s +++ b/sys/i386/i386/swtch.s @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $ - * $DragonFly: src/sys/i386/i386/Attic/swtch.s,v 1.13 2003/06/27 01:53:24 dillon Exp $ + * $DragonFly: src/sys/i386/i386/Attic/swtch.s,v 1.14 2003/06/27 03:30:37 dillon Exp $ */ #include "npx.h" @@ -214,17 +214,15 @@ ENTRY(cpu_exit_switch) movl TD_SP(%eax),%esp /* - * We are now effectively the next thread, transfer ownership to - * this thread and release the original thread's RW lock, which - * will allow it to be reaped. Messy but rock solid. + * We are now the next thread, set the exited flag and wakeup + * any waiters. */ - addl $TD_RWLOCK,%ecx - movl %eax,RW_OWNER(%ecx) + orl $TDF_EXITED,TD_FLAGS(%ecx) pushl %eax - pushl %ecx - call lwkt_exunlock + pushl %ecx /* wakeup(oldthread) */ + call wakeup addl $4,%esp - popl %eax + popl %eax /* note: next thread expects curthread in %eax */ /* * Restore the next thread's state and resume it. Note: the diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c index 845ce55390..a2ee279600 100644 --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -39,7 +39,7 @@ * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ * $FreeBSD: src/sys/i386/i386/vm_machdep.c,v 1.132.2.9 2003/01/25 19:02:23 dillon Exp $ - * $DragonFly: src/sys/i386/i386/Attic/vm_machdep.c,v 1.11 2003/06/27 01:53:24 dillon Exp $ + * $DragonFly: src/sys/i386/i386/Attic/vm_machdep.c,v 1.12 2003/06/27 03:30:37 dillon Exp $ */ #include "npx.h" @@ -257,19 +257,21 @@ cpu_set_thread_handler(thread_t td, void (*rfunc)(void), void *func, void *arg) } void -cpu_exit(p) - register struct proc *p; +cpu_proc_exit(void) { + struct thread *td = curthread; struct pcb *pcb; + #if NNPX > 0 - npxexit(p); + KKASSERT(td->td_proc); + npxexit(td->td_proc); #endif /* NNPX */ /* * Cleanup the PCB */ - pcb = curthread->td_pcb; + pcb = td->td_pcb; if (pcb->pcb_ext != 0) { /* * XXX do we need to move the TSS off the allocated pages @@ -291,29 +293,41 @@ cpu_exit(p) } cnt.v_swtch++; - /* - * Set a special switch function which will release td_rwlock after - * the thread has been derferenced. - */ crit_enter(); - KASSERT(curthread->td_switch == cpu_heavy_switch, - ("cpu_exit: unexpected switchout")); - curthread->td_switch = cpu_exit_switch; lwkt_deschedule_self(); + cpu_thread_exit(); +} + +/* + * Terminate the current thread. The caller must have already acquired + * the thread's rwlock and placed it on a reap list or otherwise notified + * a reaper of its existance. We set a special assembly switch function which + * releases td_rwlock after it has cleaned up the MMU state and switched + * out the stack. + * + * Must be caller from a critical section and with the thread descheduled. + */ +void +cpu_thread_exit(void) +{ + curthread->td_switch = cpu_exit_switch; lwkt_switch(); panic("cpu_exit"); } +/* + * Process Reaper. Called after the caller has acquired the thread's + * rwlock and removed it from the reap list. + */ void -cpu_wait(p) - struct proc *p; +cpu_proc_wait(struct proc *p) { struct thread *td; /* drop per-process resources */ td = pmap_dispose_proc(p); if (td) - pmap_dispose_thread(td); + lwkt_free_thread(td); } /* diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index c8b16d723f..825e8fa587 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -37,7 +37,7 @@ * * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94 * $FreeBSD: src/sys/kern/kern_exit.c,v 1.92.2.11 2003/01/13 22:51:16 dillon Exp $ - * $DragonFly: src/sys/kern/kern_exit.c,v 1.10 2003/06/25 03:55:57 dillon Exp $ + * $DragonFly: src/sys/kern/kern_exit.c,v 1.11 2003/06/27 03:30:42 dillon Exp $ */ #include "opt_compat.h" @@ -277,12 +277,10 @@ exit1(int rv) } /* - * Once we set SZOMB the process can get reaped. To prevent this - * from occuring we obtain an exclusive access lock on the underlying - * thread which will not be released until the thread has been - * completed switched out. + * Once we set SZOMB the process can get reaped. The wait1 code + * will also wait for TDF_EXITED to be set in the thread's flags, + * indicating that it has been completely switched out. */ - lwkt_exlock(&curthread->td_rwlock, "exit"); /* * Remove proc from allproc queue and pidhash chain. @@ -375,7 +373,7 @@ exit1(int rv) * finish. cpu_exit will end with a call to cpu_switch(), finishing * our execution (pun intended). */ - cpu_exit(p); + cpu_proc_exit(); } #ifdef COMPAT_43 @@ -439,17 +437,13 @@ loop: nfound++; if (p->p_stat == SZOMB) { /* - * This is a tad nasty because lwkt_*() functions can - * block, causing our information to become out of - * date. - * - * YYY there may be some inefficiency here. + * The process's thread may still be in the middle + * of switching away, we can't rip its stack out from + * under it until TDF_EXITED is set. */ - if ((p->p_flag & P_EXITINTERLOCK) == 0) { - lwkt_exlock(&p->p_thread->td_rwlock, "reap"); - p->p_flag |= P_EXITINTERLOCK; - lwkt_exunlock(&p->p_thread->td_rwlock); - goto loop; + if ((p->p_thread->td_flags & TDF_EXITED) == 0) { + tsleep(p->p_thread, PWAIT, "reap", 0); + goto loop; } KASSERT(p->p_lock == 0, ("p_lock not 0! %p", p)); diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c index 18ee90a3c2..e118977e00 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_kthread.c,v 1.5.2.3 2001/12/25 01:51:14 dillon Exp $ - * $DragonFly: src/sys/kern/kern_kthread.c,v 1.6 2003/06/27 01:53:25 dillon Exp $ + * $DragonFly: src/sys/kern/kern_kthread.c,v 1.7 2003/06/27 03:30:42 dillon Exp $ */ #include @@ -59,51 +59,6 @@ kproc_start(udata) panic("kproc_start: %s: error %d", kp->arg0, error); } -/* - * Create a kernel process/thread/whatever. It shares it's address space - * with proc0 - ie: kernel only. - */ -int -kthread_create(void (*func)(void *), void *arg, - struct thread **tdp, const char *fmt, ...) -{ - struct thread *td; - va_list ap; - - td = *tdp = lwkt_alloc_thread(); - cpu_set_thread_handler(td, kthread_exit, func, arg); - - /* - * Set up arg0 for 'ps' etc - */ - va_start(ap, fmt); - vsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap); - va_end(ap); - - /* - * Schedule the thread to run - */ - lwkt_schedule(td); - return 0; -} - -/* - * YYY kthread_exit() should get rid of the kthread. We have to put it on - * some sort of wait list and set our switcher to interlock against - * the reaper. - */ -void -kthread_exit(void) -{ - thread_t td = curthread; - - printf("kthread %p %s has exited\n", td, td->td_comm); /* YYY */ - for (;;) { - td->td_flags |= TDF_STOPREQ; - kproc_suspend_loop(); - } -} - /* * Advise a kernel process to suspend (or resume) in its main loop. * Participation is voluntary. @@ -112,7 +67,7 @@ int suspend_kproc(struct thread *td, int timo) { if (td->td_proc == NULL) { - td->td_flags |= TDF_STOPREQ; /* request thread exit */ + td->td_flags |= TDF_STOPREQ; /* request thread pause */ wakeup(td); while (td->td_flags & TDF_STOPREQ) { int error = tsleep(td, PPAUSE, "suspkp", timo); diff --git a/sys/kern/lwkt_thread.c b/sys/kern/lwkt_thread.c index d94bed3dc6..5067c818f4 100644 --- a/sys/kern/lwkt_thread.c +++ b/sys/kern/lwkt_thread.c @@ -27,7 +27,7 @@ * thread scheduler, which means that generally speaking we only need * to use a critical section to prevent hicups. * - * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.5 2003/06/27 01:53:25 dillon Exp $ + * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.6 2003/06/27 03:30:42 dillon Exp $ */ #include @@ -37,9 +37,10 @@ #include #include #include -#include #include +#include #include +#include #include #include @@ -51,6 +52,8 @@ #include #include +#include + static int untimely_switch = 0; SYSCTL_INT(_debug, OID_AUTO, untimely_switch, CTLFLAG_RW, &untimely_switch, 0, ""); @@ -107,24 +110,25 @@ lwkt_init_wait(lwkt_wait_t w) thread_t lwkt_alloc_thread(void) { - struct thread *td; - void *stack; + struct thread *td; + void *stack; - crit_enter(); - if (mycpu->gd_tdfreecount > 0) { - --mycpu->gd_tdfreecount; - td = TAILQ_FIRST(&mycpu->gd_tdfreeq); - KASSERT(td != NULL, ("unexpected null cache td")); - TAILQ_REMOVE(&mycpu->gd_tdfreeq, td, td_threadq); - crit_exit(); - stack = td->td_kstack; - } else { - crit_exit(); - td = zalloc(thread_zone); - stack = (void *)kmem_alloc(kernel_map, UPAGES * PAGE_SIZE); - } - lwkt_init_thread(td, stack); - return(td); + crit_enter(); + if (mycpu->gd_tdfreecount > 0) { + --mycpu->gd_tdfreecount; + td = TAILQ_FIRST(&mycpu->gd_tdfreeq); + KASSERT(td != NULL && (td->td_flags & TDF_EXITED), + ("lwkt_alloc_thread: unexpected NULL or corrupted td")); + TAILQ_REMOVE(&mycpu->gd_tdfreeq, td, td_threadq); + crit_exit(); + stack = td->td_kstack; + } else { + crit_exit(); + td = zalloc(thread_zone); + stack = (void *)kmem_alloc(kernel_map, UPAGES * PAGE_SIZE); + } + lwkt_init_thread(td, stack, TDF_ALLOCATED_STACK|TDF_ALLOCATED_THREAD); + return(td); } /* @@ -134,14 +138,40 @@ lwkt_alloc_thread(void) * NOTE! called from low level boot code, we cannot do anything fancy! */ void -lwkt_init_thread(thread_t td, void *stack) +lwkt_init_thread(thread_t td, void *stack, int flags) { - bzero(td, sizeof(struct thread)); - lwkt_rwlock_init(&td->td_rwlock); - td->td_kstack = stack; - pmap_init_thread(td); + bzero(td, sizeof(struct thread)); + td->td_kstack = stack; + td->td_flags |= flags; + pmap_init_thread(td); } +void +lwkt_free_thread(struct thread *td) +{ + KASSERT(td->td_flags & TDF_EXITED, + ("lwkt_free_thread: did not exit! %p", td)); + + crit_enter(); + if (mycpu->gd_tdfreecount < CACHE_NTHREADS && + (td->td_flags & TDF_ALLOCATED_THREAD) + ) { + ++mycpu->gd_tdfreecount; + TAILQ_INSERT_HEAD(&mycpu->gd_tdfreeq, td, td_threadq); + crit_exit(); + } else { + crit_exit(); + if (td->td_kstack && (td->td_flags & TDF_ALLOCATED_STACK)) { + kmem_free(kernel_map, + (vm_offset_t)td->td_kstack, UPAGES * PAGE_SIZE); + td->td_kstack = NULL; + } + if (td->td_flags & TDF_ALLOCATED_THREAD) + zfree(thread_zone, td); + } +} + + /* * Switch to the next runnable lwkt. If no LWKTs are runnable then * switch to the idlethread. Switching must occur within a critical @@ -169,17 +199,21 @@ lwkt_switch(void) thread_t ntd; crit_enter(); - if ((ntd = TAILQ_FIRST(&mycpu->gd_tdrunq)) != NULL) { + if ((ntd = td->td_preempted) != NULL) { + /* + * We had preempted another thread on this cpu, resume the preempted + * thread. + */ + td->td_preempted = NULL; + ntd->td_flags &= ~TDF_PREEMPTED; + } else if ((ntd = TAILQ_FIRST(&mycpu->gd_tdrunq)) != NULL) { TAILQ_REMOVE(&mycpu->gd_tdrunq, ntd, td_threadq); TAILQ_INSERT_TAIL(&mycpu->gd_tdrunq, ntd, td_threadq); } else { ntd = &mycpu->gd_idlethread; } - if (td != ntd) { - td->td_flags &= ~TDF_RUNNING; - ntd->td_flags |= TDF_RUNNING; + if (td != ntd) td->td_switch(ntd); - } crit_exit(); } @@ -257,7 +291,6 @@ lwkt_schedule_self(void) crit_enter(); KASSERT(td->td_wait == NULL, ("lwkt_schedule_self(): td_wait not NULL!")); - KASSERT(td->td_flags & TDF_RUNNING, ("lwkt_schedule_self(): TDF_RUNNING not set!")); _lwkt_enqueue(td); crit_exit(); } @@ -351,7 +384,6 @@ lwkt_deschedule_self(void) crit_enter(); KASSERT(td->td_wait == NULL, ("lwkt_schedule_self(): td_wait not NULL!")); - KASSERT(td->td_flags & TDF_RUNNING, ("lwkt_schedule_self(): TDF_RUNNING not set!")); _lwkt_dequeue(td); crit_exit(); } @@ -528,3 +560,97 @@ lwkt_regettoken(lwkt_token_t tok) return(0); } +/* + * Create a kernel process/thread/whatever. It shares it's address space + * with proc0 - ie: kernel only. + * + * XXX should be renamed to lwkt_create() + */ +int +lwkt_create(void (*func)(void *), void *arg, + struct thread **tdp, const char *fmt, ...) +{ + struct thread *td; + va_list ap; + + td = *tdp = lwkt_alloc_thread(); + cpu_set_thread_handler(td, kthread_exit, func, arg); + td->td_flags |= TDF_VERBOSE; + + /* + * Set up arg0 for 'ps' etc + */ + va_start(ap, fmt); + vsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap); + va_end(ap); + + /* + * Schedule the thread to run + */ + lwkt_schedule(td); + return 0; +} + +/* + * Destroy an LWKT thread. Warning! This function is not called when + * a process exits, cpu_proc_exit() directly calls cpu_thread_exit() and + * uses a different reaping mechanism. + */ +void +lwkt_exit(void) +{ + thread_t td = curthread; + + if (td->td_flags & TDF_VERBOSE) + printf("kthread %p %s has exited\n", td, td->td_comm); + crit_enter(); + lwkt_deschedule_self(); + ++mycpu->gd_tdfreecount; + TAILQ_INSERT_TAIL(&mycpu->gd_tdfreeq, td, td_threadq); + cpu_thread_exit(); +} + +/* + * Create a kernel process/thread/whatever. It shares it's address space + * with proc0 - ie: kernel only. + * + * XXX exact duplicate of lwkt_create(). + */ +int +kthread_create(void (*func)(void *), void *arg, + struct thread **tdp, const char *fmt, ...) +{ + struct thread *td; + va_list ap; + + td = *tdp = lwkt_alloc_thread(); + cpu_set_thread_handler(td, kthread_exit, func, arg); + td->td_flags |= TDF_VERBOSE; + + /* + * Set up arg0 for 'ps' etc + */ + va_start(ap, fmt); + vsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap); + va_end(ap); + + /* + * Schedule the thread to run + */ + lwkt_schedule(td); + return 0; +} + +/* + * Destroy an LWKT thread. Warning! This function is not called when + * a process exits, cpu_proc_exit() directly calls cpu_thread_exit() and + * uses a different reaping mechanism. + * + * XXX duplicates lwkt_exit() + */ +void +kthread_exit(void) +{ + lwkt_exit(); +} + diff --git a/sys/platform/pc32/i386/genassym.c b/sys/platform/pc32/i386/genassym.c index 87ef05611e..006b6cf0cc 100644 --- a/sys/platform/pc32/i386/genassym.c +++ b/sys/platform/pc32/i386/genassym.c @@ -35,7 +35,7 @@ * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $ - * $DragonFly: src/sys/platform/pc32/i386/genassym.c,v 1.13 2003/06/27 01:53:24 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/genassym.c,v 1.14 2003/06/27 03:30:37 dillon Exp $ */ #include "opt_user_ldt.h" @@ -85,8 +85,9 @@ ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); ASSYM(TD_SP, offsetof(struct thread, td_sp)); ASSYM(TD_PRI, offsetof(struct thread, td_pri)); ASSYM(TD_MACH, offsetof(struct thread, td_mach)); -ASSYM(TD_RWLOCK, offsetof(struct thread, td_rwlock)); ASSYM(TD_WCHAN, offsetof(struct thread, td_wchan)); +ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); +ASSYM(TDF_EXITED, TDF_EXITED); ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner)); diff --git a/sys/platform/pc32/i386/machdep.c b/sys/platform/pc32/i386/machdep.c index b69c5d6984..89b6bcb0ee 100644 --- a/sys/platform/pc32/i386/machdep.c +++ b/sys/platform/pc32/i386/machdep.c @@ -36,7 +36,7 @@ * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $ - * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.12 2003/06/25 03:55:53 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.13 2003/06/27 03:30:37 dillon Exp $ */ #include "apm.h" @@ -1866,14 +1866,13 @@ init386(first) */ gd = &CPU_prvspace[0].globaldata; - lwkt_init_thread(&thread0, proc0paddr); + lwkt_init_thread(&thread0, proc0paddr, 0); gd->gd_curthread = &thread0; safepri = thread0.td_cpl = SWI_MASK | HWI_MASK; thread0.td_switch = cpu_heavy_switch; /* YYY eventually LWKT */ proc0.p_addr = (void *)thread0.td_kstack; proc0.p_thread = &thread0; thread0.td_proc = &proc0; - thread0.td_flags = TDF_RUNNING; atdevbase = ISA_HOLE_START + KERNBASE; @@ -2088,7 +2087,7 @@ cpu_gdinit(struct globaldata *gd, int cpu) if (cpu) gd->gd_curthread = &gd->gd_idlethread; sp = gd->gd_prvspace->idlestack; - lwkt_init_thread(&gd->gd_idlethread, sp); + lwkt_init_thread(&gd->gd_idlethread, sp, 0); gd->gd_idlethread.td_switch = cpu_lwkt_switch; gd->gd_idlethread.td_sp -= sizeof(void *); *(void **)gd->gd_idlethread.td_sp = cpu_idle_restore; diff --git a/sys/platform/pc32/i386/pmap.c b/sys/platform/pc32/i386/pmap.c index 79f378159b..6bdabe61aa 100644 --- a/sys/platform/pc32/i386/pmap.c +++ b/sys/platform/pc32/i386/pmap.c @@ -40,7 +40,7 @@ * * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/i386/pmap.c,v 1.250.2.18 2002/03/06 22:48:53 silby Exp $ - * $DragonFly: src/sys/platform/pc32/i386/pmap.c,v 1.10 2003/06/22 04:30:39 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/pmap.c,v 1.11 2003/06/27 03:30:37 dillon Exp $ */ /* @@ -850,29 +850,6 @@ pmap_init_thread(thread_t td) td->td_sp = (char *)td->td_pcb - 16; } -/* - * Dispose of a thread, unlink it from its related proc (if any). Keep - * CACHE_NTHREAD threads around for fast-startup. - */ -void -pmap_dispose_thread(struct thread *td) -{ - /* HIPRI YYY */ - KASSERT((td->td_flags & (TDF_RUNQ|TDF_RUNNING)) == 0, - ("pmap_dispose_thread: still on queue: %08x", td->td_flags)); - if (mycpu->gd_tdfreecount < CACHE_NTHREADS) { - ++mycpu->gd_tdfreecount; - TAILQ_INSERT_HEAD(&mycpu->gd_tdfreeq, td, td_threadq); - } else { - if (td->td_kstack) { - kmem_free(kernel_map, - (vm_offset_t)td->td_kstack, UPAGES * PAGE_SIZE); - td->td_kstack = NULL; - } - zfree(thread_zone, td); - } -} - /* * Create the UPAGES for a new process. * This routine directly affects the fork perf for a process. diff --git a/sys/platform/pc32/i386/swtch.s b/sys/platform/pc32/i386/swtch.s index 65376ef229..90e8319501 100644 --- a/sys/platform/pc32/i386/swtch.s +++ b/sys/platform/pc32/i386/swtch.s @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $ - * $DragonFly: src/sys/platform/pc32/i386/swtch.s,v 1.13 2003/06/27 01:53:24 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/swtch.s,v 1.14 2003/06/27 03:30:37 dillon Exp $ */ #include "npx.h" @@ -214,17 +214,15 @@ ENTRY(cpu_exit_switch) movl TD_SP(%eax),%esp /* - * We are now effectively the next thread, transfer ownership to - * this thread and release the original thread's RW lock, which - * will allow it to be reaped. Messy but rock solid. + * We are now the next thread, set the exited flag and wakeup + * any waiters. */ - addl $TD_RWLOCK,%ecx - movl %eax,RW_OWNER(%ecx) + orl $TDF_EXITED,TD_FLAGS(%ecx) pushl %eax - pushl %ecx - call lwkt_exunlock + pushl %ecx /* wakeup(oldthread) */ + call wakeup addl $4,%esp - popl %eax + popl %eax /* note: next thread expects curthread in %eax */ /* * Restore the next thread's state and resume it. Note: the diff --git a/sys/platform/pc32/i386/vm_machdep.c b/sys/platform/pc32/i386/vm_machdep.c index b33d9fc16a..685545073c 100644 --- a/sys/platform/pc32/i386/vm_machdep.c +++ b/sys/platform/pc32/i386/vm_machdep.c @@ -39,7 +39,7 @@ * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ * $FreeBSD: src/sys/i386/i386/vm_machdep.c,v 1.132.2.9 2003/01/25 19:02:23 dillon Exp $ - * $DragonFly: src/sys/platform/pc32/i386/vm_machdep.c,v 1.11 2003/06/27 01:53:24 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/vm_machdep.c,v 1.12 2003/06/27 03:30:37 dillon Exp $ */ #include "npx.h" @@ -257,19 +257,21 @@ cpu_set_thread_handler(thread_t td, void (*rfunc)(void), void *func, void *arg) } void -cpu_exit(p) - register struct proc *p; +cpu_proc_exit(void) { + struct thread *td = curthread; struct pcb *pcb; + #if NNPX > 0 - npxexit(p); + KKASSERT(td->td_proc); + npxexit(td->td_proc); #endif /* NNPX */ /* * Cleanup the PCB */ - pcb = curthread->td_pcb; + pcb = td->td_pcb; if (pcb->pcb_ext != 0) { /* * XXX do we need to move the TSS off the allocated pages @@ -291,29 +293,41 @@ cpu_exit(p) } cnt.v_swtch++; - /* - * Set a special switch function which will release td_rwlock after - * the thread has been derferenced. - */ crit_enter(); - KASSERT(curthread->td_switch == cpu_heavy_switch, - ("cpu_exit: unexpected switchout")); - curthread->td_switch = cpu_exit_switch; lwkt_deschedule_self(); + cpu_thread_exit(); +} + +/* + * Terminate the current thread. The caller must have already acquired + * the thread's rwlock and placed it on a reap list or otherwise notified + * a reaper of its existance. We set a special assembly switch function which + * releases td_rwlock after it has cleaned up the MMU state and switched + * out the stack. + * + * Must be caller from a critical section and with the thread descheduled. + */ +void +cpu_thread_exit(void) +{ + curthread->td_switch = cpu_exit_switch; lwkt_switch(); panic("cpu_exit"); } +/* + * Process Reaper. Called after the caller has acquired the thread's + * rwlock and removed it from the reap list. + */ void -cpu_wait(p) - struct proc *p; +cpu_proc_wait(struct proc *p) { struct thread *td; /* drop per-process resources */ td = pmap_dispose_proc(p); if (td) - pmap_dispose_thread(td); + lwkt_free_thread(td); } /* diff --git a/sys/platform/vkernel/i386/genassym.c b/sys/platform/vkernel/i386/genassym.c index 3eb6aab5d9..6a90bea76a 100644 --- a/sys/platform/vkernel/i386/genassym.c +++ b/sys/platform/vkernel/i386/genassym.c @@ -35,7 +35,7 @@ * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $ - * $DragonFly: src/sys/platform/vkernel/i386/genassym.c,v 1.13 2003/06/27 01:53:24 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/i386/genassym.c,v 1.14 2003/06/27 03:30:37 dillon Exp $ */ #include "opt_user_ldt.h" @@ -85,8 +85,9 @@ ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); ASSYM(TD_SP, offsetof(struct thread, td_sp)); ASSYM(TD_PRI, offsetof(struct thread, td_pri)); ASSYM(TD_MACH, offsetof(struct thread, td_mach)); -ASSYM(TD_RWLOCK, offsetof(struct thread, td_rwlock)); ASSYM(TD_WCHAN, offsetof(struct thread, td_wchan)); +ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); +ASSYM(TDF_EXITED, TDF_EXITED); ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner)); diff --git a/sys/sys/kthread.h b/sys/sys/kthread.h index 83cfe69d4c..1d43761b11 100644 --- a/sys/sys/kthread.h +++ b/sys/sys/kthread.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/sys/kthread.h,v 1.2 2000/01/07 08:36:44 luoqi Exp $ - * $DragonFly: src/sys/sys/kthread.h,v 1.4 2003/06/27 01:53:26 dillon Exp $ + * $DragonFly: src/sys/sys/kthread.h,v 1.5 2003/06/27 03:30:43 dillon Exp $ */ #ifndef _SYS_KTHREAD_H_ @@ -45,13 +45,14 @@ struct kproc_desc { }; void kproc_start __P((const void *)); -int kthread_create __P((void (*)(void *), void *, struct thread **, - const char *, ...)) __printflike(4, 5); -void kthread_exit __P((void)) __dead2; int suspend_kproc __P((struct thread *, int)); int resume_kproc __P((struct thread *)); void kproc_suspend_loop __P((void)); void shutdown_kproc __P((void *, int)); +int kthread_create __P((void (*)(void *), void *, struct thread **, + const char *, ...)); +void kthread_exit __P((void)) __dead2; + #endif diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 683d1a39ce..f4eaefc5f0 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -37,7 +37,7 @@ * * @(#)proc.h 8.15 (Berkeley) 5/19/95 * $FreeBSD: src/sys/sys/proc.h,v 1.99.2.9 2003/06/06 20:21:32 tegge Exp $ - * $DragonFly: src/sys/sys/proc.h,v 1.16 2003/06/27 01:53:26 dillon Exp $ + * $DragonFly: src/sys/sys/proc.h,v 1.17 2003/06/27 03:30:43 dillon Exp $ */ #ifndef _SYS_PROC_H_ @@ -281,7 +281,6 @@ struct proc { #define P_OLDMASK 0x2000000 /* need to restore mask before pause */ #define P_ALTSTACK 0x4000000 /* have alternate signal stack */ #define P_INEXEC 0x8000000 /* Process is in execve(). */ -#define P_EXITINTERLOCK 0x10000000 /* Reaping process exit interlock */ #ifdef _KERNEL @@ -414,7 +413,8 @@ void cpu_heavy_switch __P((struct thread *)); void cpu_lwkt_switch __P((struct thread *)); void unsleep __P((struct thread *)); -void cpu_exit __P((struct proc *)) __dead2; +void cpu_proc_exit __P((void)) __dead2; +void cpu_thread_exit __P((void)) __dead2; void exit1 __P((int)) __dead2; void cpu_fork __P((struct proc *, struct proc *, int)); void cpu_set_fork_handler __P((struct proc *, void (*)(void *), void *)); @@ -422,7 +422,8 @@ void cpu_set_thread_handler(struct thread *td, void (*retfunc)(void), void *func int fork1 __P((struct proc *, int, struct proc **)); void start_forked_proc __P((struct proc *, struct proc *)); int trace_req __P((struct proc *)); -void cpu_wait __P((struct proc *)); +void cpu_proc_wait __P((struct proc *)); +void cpu_thread_wait __P((struct thread *)); int cpu_coredump __P((struct thread *, struct vnode *, struct ucred *)); void setsugid __P((void)); void faultin __P((struct proc *p)); diff --git a/sys/sys/thread.h b/sys/sys/thread.h index 60d5f2f075..748b608268 100644 --- a/sys/sys/thread.h +++ b/sys/sys/thread.h @@ -4,7 +4,7 @@ * Implements the architecture independant portion of the LWKT * subsystem. * - * $DragonFly: src/sys/sys/thread.h,v 1.10 2003/06/27 01:53:26 dillon Exp $ + * $DragonFly: src/sys/sys/thread.h,v 1.11 2003/06/27 03:30:43 dillon Exp $ */ #ifndef _SYS_THREAD_H_ @@ -132,25 +132,26 @@ struct thread { char *td_sp; /* kernel stack pointer for LWKT restore */ void (*td_switch)(struct thread *ntd); lwkt_wait_t td_wait; /* thread sitting on wait structure */ - lwkt_rwlock td_rwlock; /* thread arbitration */ u_int64_t td_uticks; /* Statclock hits in user mode (uS) */ u_int64_t td_sticks; /* Statclock hits in system mode (uS) */ u_int64_t td_iticks; /* Statclock hits processing intr (uS) */ int td_locks; /* lockmgr lock debugging YYY */ char td_comm[MAXCOMLEN+1]; /* typ 16+1 bytes */ + struct thread *td_preempted; /* we preempted this thread */ struct mi_thread td_mach; }; -#define td_token td_rwlock.rw_token - /* - * Thread flags. Note that the RUNNING state is independant from the - * RUNQ/WAITQ state. That is, a thread's queueing state can be manipulated - * while it is running. If a thread is preempted it will always be moved - * back to the RUNQ if it isn't on it. + * Thread flags. Note that TDF_EXITED is set by the appropriate switchout + * code when a thread exits, after it has switched to another stack and + * cleaned up the MMU state. */ -#define TDF_RUNNING 0x0001 /* currently running */ +#define TDF_EXITED 0x0001 /* thread finished exiting */ #define TDF_RUNQ 0x0002 /* on run queue */ +#define TDF_PREEMPTED 0x0004 /* thread is currently preempted */ +#define TDF_ALLOCATED_THREAD 0x0200 /* zalloc allocated thread */ +#define TDF_ALLOCATED_STACK 0x0400 /* zalloc allocated stack */ +#define TDF_VERBOSE 0x0800 /* verbose on exit */ #define TDF_DEADLKTREAT 0x1000 /* special lockmgr deadlock treatment */ #define TDF_STOPREQ 0x2000 /* suspend_kproc */ #define TDF_WAKEREQ 0x4000 /* resume_kproc */ @@ -190,7 +191,8 @@ struct thread { extern struct vm_zone *thread_zone; extern struct thread *lwkt_alloc_thread(void); -extern void lwkt_init_thread(struct thread *td, void *stack); +extern void lwkt_init_thread(struct thread *td, void *stack, int flags); +extern void lwkt_free_thread(struct thread *td); extern void lwkt_init_wait(struct lwkt_wait *w); extern void lwkt_gdinit(struct globaldata *gd); extern void lwkt_switch(void); @@ -213,6 +215,10 @@ extern void lwkt_shlock(lwkt_rwlock_t lock, const char *wmesg); extern void lwkt_exunlock(lwkt_rwlock_t lock); extern void lwkt_shunlock(lwkt_rwlock_t lock); +extern int lwkt_create (void (*func)(void *), void *arg, struct thread **ptd, + const char *ctl, ...); +extern void lwkt_exit __P((void)) __dead2; + #endif #endif diff --git a/sys/vm/pmap.h b/sys/vm/pmap.h index 789ce967cd..fab9153097 100644 --- a/sys/vm/pmap.h +++ b/sys/vm/pmap.h @@ -62,7 +62,7 @@ * rights to redistribute these changes. * * $FreeBSD: src/sys/vm/pmap.h,v 1.33.2.4 2002/03/06 22:44:24 silby Exp $ - * $DragonFly: src/sys/vm/pmap.h,v 1.5 2003/06/22 04:30:43 dillon Exp $ + * $DragonFly: src/sys/vm/pmap.h,v 1.6 2003/06/27 03:30:43 dillon Exp $ */ /* @@ -138,7 +138,6 @@ void pmap_prefault __P((pmap_t, vm_offset_t, vm_map_entry_t)); int pmap_mincore __P((pmap_t pmap, vm_offset_t addr)); void pmap_init_proc __P((struct proc *p, struct thread *td)); void pmap_init_thread __P((struct thread *td)); -void pmap_dispose_thread __P((struct thread *td)); struct thread *pmap_dispose_proc __P((struct proc *p)); void pmap_swapout_proc __P((struct proc *p)); void pmap_swapin_proc __P((struct proc *p)); diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index 1c5b597748..9589958665 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -60,7 +60,7 @@ * rights to redistribute these changes. * * $FreeBSD: src/sys/vm/vm_glue.c,v 1.94.2.4 2003/01/13 22:51:17 dillon Exp $ - * $DragonFly: src/sys/vm/vm_glue.c,v 1.6 2003/06/25 03:56:12 dillon Exp $ + * $DragonFly: src/sys/vm/vm_glue.c,v 1.7 2003/06/27 03:30:43 dillon Exp $ */ #include "opt_vm.h" @@ -283,7 +283,7 @@ vm_fork(p1, p2, flags) void vm_waitproc(struct proc *p) { - cpu_wait(p); + cpu_proc_wait(p); vmspace_exitfree(p); /* and clean-out the vmspace */ } -- 2.41.0