diff options
| author | ad <ad@NetBSD.org> | 2007-03-02 18:53:51 +0000 |
|---|---|---|
| committer | ad <ad@NetBSD.org> | 2007-03-02 18:53:51 +0000 |
| commit | de2138164cd16145ee5fd4d0aef1e8f952c1a9fb (patch) | |
| tree | 62f3356c867aad6687c1930c0d2b01494a60a30b /lib/libpthread | |
| parent | dba14ef0a08bc45d3d11517130f37fff26a4ba4c (diff) | |
Remove the PTHREAD_SA option. If M:N threads is reimplemented it's
better off done with a seperate library.
Diffstat (limited to 'lib/libpthread')
48 files changed, 184 insertions, 8527 deletions
diff --git a/lib/libpthread/Makefile b/lib/libpthread/Makefile index 8c7642187d0..b6becb174fc 100644 --- a/lib/libpthread/Makefile +++ b/lib/libpthread/Makefile @@ -1,7 +1,6 @@ -# $NetBSD: Makefile,v 1.39 2007/02/09 22:08:48 ad Exp $ +# $NetBSD: Makefile,v 1.40 2007/03/02 18:53:51 ad Exp $ # -#PTHREAD_SA=1 WARNS= 4 # Define PT_FIXEDSTACKSIZE_LG to set a fixed stacksize @@ -29,10 +28,6 @@ ARCHDIR= ${.CURDIR}/arch/${ARCHSUBDIR} CPPFLAGS+= -I${ARCHDIR} -I${.CURDIR} -I${.OBJDIR} -D_LIBC CPPFLAGS+= -D__LIBPTHREAD_SOURCE__ -.if defined(PTHREAD_SA) -CPPFLAGS+= -DPTHREAD_SA -DPTHREAD_MLOCK_KLUDGE -.endif - # XXX: This crappy poke at libc's internals needs to be fixed. # We need to put this *after our own includes, so that our "assym.h" # gets picked, instead of the libc one @@ -55,18 +50,14 @@ LIB= pthread # library semantics will end up discarding potentially important objects. # SRCS= pthread.c -SRCS+= pthread_alarms.c SRCS+= pthread_attr.c SRCS+= pthread_barrier.c SRCS+= pthread_cancelstub.c SRCS+= pthread_cond.c SRCS+= pthread_lock.c +SRCS+= pthread_misc.c SRCS+= pthread_mutex.c -SRCS+= pthread_run.c SRCS+= pthread_rwlock.c -SRCS+= pthread_sa.c -SRCS+= pthread_sig.c -SRCS+= pthread_sleep.c SRCS+= pthread_specific.c SRCS+= pthread_stack.c SRCS+= pthread_tsd.c @@ -75,9 +66,6 @@ SRCS+= res_state.c SRCS+= sched.c SRCS+= sem.c # Architecture-dependent files -.if defined(PTHREAD_SA) -SRCS+= pthread_switch.S -.endif SRCS+= _context_u.S .if exists(${ARCHDIR}/pthread_md.c) SRCS+= pthread_md.c diff --git a/lib/libpthread/TODO b/lib/libpthread/TODO index ac9f2cdb129..2d71aae7aec 100644 --- a/lib/libpthread/TODO +++ b/lib/libpthread/TODO @@ -1,69 +1,50 @@ -$NetBSD: TODO,v 1.7 2007/03/02 17:47:40 ad Exp $ - -Bugs to fix, mostly with SA: - -- some blocking routines (like sem_wait()) don't work if SA's aren't - running yet, because the alarm system isn't up and running or there is no - thread context to switch to. It would be weird to use them that - way, but it's perfectly legal. -- There is a race between pthread_cancel() and - pthread_cond_broadcast() or pthread_exit() about removing an item - from the sleep queue. The locking protocols there need a little - adjustment. -- pthread_sig.c: pthread__kill_self() passes a bogus ucontext to the handler. - This is probably not very important. -- pthread_sig.c: Come up with a signal trampoline naming convention like - libc's, so that GDB will have an easier time with things. -- Consider moving pthread__signal_tramp() to its own file, and building - it with -fasync-unwind-tables, so that DWARF2 EH unwinding works through - it. (This is required for e.g. GCC's libjava.) +$NetBSD: TODO,v 1.8 2007/03/02 18:53:51 ad Exp $ + +Bugs to fix: + - Add locking to ld.elf_so so that multiple threads doing lazy binding - doesn't trash things. + doesn't trash things. XXX Still the case? - Verify the cancel stub symbol trickery. - Interfaces/features to implement: -- pthread_atfork() + - priority scheduling - libc integration: - foo_r interfaces - system integration - some macros and prototypes belong in headers other than pthread.h - Features that need more/better regression tests: + - pthread_cond_broadcast() - pthread_once() - pthread_get/setspecific() - signals - -Things that need fixing: -- Recycle dead threads for new threads. - Ideas to play with: + - Explore the trapcontext vs. usercontext distinction in ucontext_t. + - Get rid of thread structures when too many accumulate (is this actually a good idea?) -- Adaptive spin/sleep locks for mutexes. + - Currently, each thread uses two real pages of memory: one at the top of the stack for actual stack data, and one at the bottom for the pthread_st. If we can get suitable space above the initial stack for main(), we can cut this to one page per thread. Perhaps crt0 should do something different (give us more space) if libpthread is linked in? + - Figure out whether/how to expose the inline version of pthread_self(). + - Along the same lines, figure out whether/how to use registers reserved in the ABI for thread-specific-data to implement pthread_self(). -- Figure out what to do with changing stack sizes. -Future work for 1:1 threads: +- Figure out what to do with changing stack sizes. - Stress testing, particularly with multiple CPUs. -- Verify that gdb still works well (basic functionality seems to be OK). - - A race between pthread_exit() and pthread_create() for detached LWPs, where the stack (and pthread structure) could be reclaimed before the thread has a chance to call _lwp_exit(), is currently prevented by @@ -110,8 +91,7 @@ Future work for 1:1 threads: - Need to give consideration to the order in which threads enter and exit synchronisation objects, both in the pthread library and in the kernel. - Commonly locks are acquired/released in order (a, b, c -> c, b, a). The - pthread spec probably has something to say about this. + Commonly locks are acquired/released in order (a, b, c -> c, b, a). - The kernel scheduler needs improving to handle LWPs and processor affinity better, and user space tools like top(1) and ps(1) need to be changed to diff --git a/lib/libpthread/arch/alpha/genassym.cf b/lib/libpthread/arch/alpha/genassym.cf index 92c469d4c60..fd1989ac225 100644 --- a/lib/libpthread/arch/alpha/genassym.cf +++ b/lib/libpthread/arch/alpha/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.5 2003/09/07 14:47:46 cl Exp $ +# $NetBSD: genassym.cf,v 1.6 2007/03/02 18:53:54 ad Exp $ # # Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -44,13 +44,7 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define CONTEXTSIZE sizeof(ucontext_t) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_GREGS offsetof(ucontext_t, uc_mcontext.__gregs) diff --git a/lib/libpthread/arch/alpha/pthread_switch.S b/lib/libpthread/arch/alpha/pthread_switch.S deleted file mode 100644 index aabae829350..00000000000 --- a/lib/libpthread/arch/alpha/pthread_switch.S +++ /dev/null @@ -1,288 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.5 2003/09/07 14:47:47 cl Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -#include <machine/asm.h> -#include "assym.h" - -/* Force an error when "notreached" code is reached. */ -#define NOTREACHED \ - call_pal PAL_bugchk ; \ - /* NOTREACHED */ - -/* *** WARNING *** - * STACK_SWITCH is more subtle than it looks. Please go read the extended - * comment in the i386 pthread_switch.S file. - */ - -#define STACK_SWITCH(pt,tmp) \ - ldq tmp, PT_TRAPUC(pt) ; \ - bne tmp, 1f ; \ - ldq tmp, PT_UC(pt) ; \ -1: lda sp, -STACKSPACE(tmp) ; \ - stq zero, PT_TRAPUC(pt) - -NESTED(pthread__switch, 2, CONTEXTSIZE + 24, ra, 0, 0) - LDGP(pv) - lda sp, -(CONTEXTSIZE + 24)(sp) - stq ra, 0(sp) - stq a0, 8(sp) - stq a1, 16(sp) - - /* Get the current context */ - lda a0, 24(sp) - CALL(_getcontext_u) - ldq a0, 8(sp) - ldq a1, 16(sp) - - /* Edit the context to make it continue below, rather than here */ - lda t3, 24(sp) - lda t1, pthread__switch_return_point - stq t1, (UC_GREGS + _REG_PC * 8)(t3) - - lda t0, 24(sp) - stq t0, PT_UC(a0) - - STACK_SWITCH(a1, t2) - - mov t2, a0 - CALL(_setcontext_u) -XNESTED(pthread__switch_return_point, 2) - ldq ra, 0(sp) - lda sp, (CONTEXTSIZE + 24)(sp) - RET - END(pthread__switch) - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - */ - -NESTED(pthread__switch_away, 3, 0, ra, 0, 0) - STACK_SWITCH(a1, s2) - - /* If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there may - * be a fake spinlock-count set. If so, they will set a2 to - * let us know, and we decrement it now that we're no longer - * using the old stack. - */ - beq a2, 1f - ldl t0, PT_SPINLOCKS(a0) - subl t0, 1, t0 - stl t0, PT_SPINLOCKS(a0) - -1: mov s2, a0 - CALL(_setcontext_u) - NOTREACHED - END(pthread__switch_away) - -NESTED(pthread__locked_switch, 3, CONTEXTSIZE + 32, ra, 0x00030000, 0) - LDGP(pv) - lda sp, -(CONTEXTSIZE + 32)(sp) - stq ra, 0(sp) - stq a0, 8(sp) - stq a1, 16(sp) - stq a2, 24(sp) - - /* Make sure we get continuted */ - ldl t0, PT_SPINLOCKS(a1) - addl t0, 1, t0 - stl t0, PT_SPINLOCKS(a1) - - /* Get the current context */ - lda a0, 32(sp) - CALL(_getcontext_u) - ldq a0, 8(sp) - ldq a1, 16(sp) - ldq a2, 24(sp) - - /* Edit the context to make it continue below, rather than here */ - lda t3, 32(sp) - lda t1, locked_return_point - stq t1, (UC_GREGS + _REG_PC * 8)(t3) - - lda t0, 32(sp) - stq t0, PT_UC(a0) - - STACK_SWITCH(a1, t2) - - /* Check if the switcher was preempted and continued to here. */ - ldq t0, PT_NEXT(a0) - beq t0, 1f - - /* Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, - * and switch to the next thread in the continuation chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - stq a2, PT_HELDLOCK(a0) - stq t2, PT_SWITCHTOUC(a0) - stq a1, PT_SWITCHTO(a0) - ldl t4, PT_SPINLOCKS(a0) - subl t4, 1, t4 - stl t4, PT_SPINLOCKS(a0) - - mov a1, a0 - mov t0, a1 - mov 1, a2 - jmp zero, pthread__switch_away - NOTREACHED - - /* No locked old-preemption */ -1: /* We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - /* Reduce the lock count... */ - ldl t0, PT_SPINLOCKS(a0) - subl t0, 1, t0 - stl t0, PT_SPINLOCKS(a0) - /* ... actually release the lock.. */ - mb - stl zero, 0(a2) - /* .. and remove the fake lock */ - ldl t0, PT_SPINLOCKS(a1) - subl t0, 1, t0 - stl t0, PT_SPINLOCKS(a1) - - /* Check if we were preempted while holding the fake lock. */ - ldq t0, PT_NEXT(a1) - beq t0, 2f - - /* Yes, we were. Go to the next element in the chain. */ - stq t2, PT_SWITCHTOUC(a1) - stq a1, PT_SWITCHTO(a1) - mov a1, a0 - mov t0, a1 - mov zero, a2 - jmp zero, pthread__switch_away - NOTREACHED - -2: mov t2, a0 - CALL(_setcontext_u) -locked_return_point: - ldq ra, 0(sp) - lda sp, (CONTEXTSIZE + 32)(sp) - RET - END(pthread__locked_switch) - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - */ - -NESTED(pthread__upcall_switch,2,0,ra,0,0) - LDGP(pv) - /* Loading the global pointer is unnecessary; this routine - * is only ever called from the pthreads module, and the C - * code will have gp set up. - * - * Also, this code never returns, so we can treat s0-s6 as - * convenient registers that will be saved for us by callees, - * but that we do not have to save. - */ - - /* Create a "fake" lock count so that this code will be continued */ - ldl t0, PT_SPINLOCKS(a1) - addl t0, 1, t0 - stl t0, PT_SPINLOCKS(a1) - - STACK_SWITCH(a1,s2) - - /* Check if the upcall code was preempted and continued to here. */ - ldq t0, PT_NEXT(a0) - beq t0, 1f - - /* Yes, it was. Stash the thread we were going to switch to, - * and switch to the next thread in the continuation chain. - */ - stq s2, PT_SWITCHTOUC(a0) - stq a1, PT_SWITCHTO(a0) - mov a1, a0 - mov t0, a1 - mov 1, a2 - jmp zero, pthread__switch_away - NOTREACHED - - /* No old-upcall-preemption */ -1: mov a0, s0 - mov a1, s1 - CALL(pthread__sa_recycle) - mov s0, a0 - mov s1, a1 - - /* We can now release the fake lock. */ - ldl t0, PT_SPINLOCKS(a1) - subl t0, 1, t0 - stl t0, PT_SPINLOCKS(a1) - - /* Check if we were preempted and continued while faking the lock */ - ldq t0, PT_NEXT(a1) - beq t0, 2f - - /* Yes, we were. Stash the to-be-switched-to context in our thread - * structure and go to the next link in the chain. - */ - stq s2, PT_SWITCHTOUC(a1) - stq a1, PT_SWITCHTO(a1) - mov a1, a0 - mov t0, a1 - mov 0, a2 - jmp zero, pthread__switch_away - - /* No new-upcall-preemption */ -2: mov s2, a0 - CALL(_setcontext_u) - NOTREACHED - END(pthread__upcall_switch) diff --git a/lib/libpthread/arch/arm/genassym.cf b/lib/libpthread/arch/arm/genassym.cf index 49b8b9cf341..da86a861ed8 100644 --- a/lib/libpthread/arch/arm/genassym.cf +++ b/lib/libpthread/arch/arm/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.6 2003/09/07 14:47:47 cl Exp $ +# $NetBSD: genassym.cf,v 1.7 2007/03/02 18:53:55 ad Exp $ # Copyright (c) 2001 Wasabi Systems, Inc. # All rights reserved. @@ -53,16 +53,6 @@ define _REG_CPSR offsetof(ucontext_t, uc_mcontext.__gregs[_REG_CPSR]) define _UC_CPU _UC_CPU define _UC_USER _UC_USER -#======================================================================== -# for pthread_switch.S -define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) - define RND_CTXSIZE ((sizeof(ucontext_t) + 7) & ~7) define STACKSPACE STACKSPACE define __SIMPLELOCK_UNLOCKED __SIMPLELOCK_UNLOCKED diff --git a/lib/libpthread/arch/arm/pthread_switch.S b/lib/libpthread/arch/arm/pthread_switch.S deleted file mode 100644 index 5790ff69323..00000000000 --- a/lib/libpthread/arch/arm/pthread_switch.S +++ /dev/null @@ -1,398 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.8 2004/08/21 11:31:44 rearnsha Exp $ */ - -/* - * Copyright (c) 2001 Wasabi Systems, Inc. - * All rights reserved. - * - * Written by Jason R. Thorpe for Wasabi Systems, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project by - * Wasabi Systems, Inc. - * 4. The name of Wasabi Systems, Inc. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <machine/asm.h> -#include "assym.h" - -#define NOTREACHED /* nothing, for now */ - -/* - * Define: - * void pthread__switch(pthread_t self, pthread_t next) - * void pthread__upcall_switch(pthread_t self, pthread_t next) - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock) - */ - -/* *** WARNING *** - * STACK_SWITCH is more subtle than it looks. Please go read the extended - * comment in the i386 pthread_switch.S file. - */ - -#define STACK_SWITCH(pt, tmp, z) \ - ldr tmp, [pt, #(PT_TRAPUC)] ; \ - teq tmp, #0x00000000 ; \ - bne 1f ; \ - ldr tmp, [pt, #(PT_UC)] ; \ -1: sub sp, tmp, #(STACKSPACE) ; \ - mov z, #00000000 ; \ - str z, [pt, #(PT_TRAPUC)] - -/* - * void - * pthread__switch(pthread_t self (r0), pthread_t next (r1)) - * - * Plain switch that doesn't do any special checking or handle spin- - * preemption. It isn't used much by normal code, actually; its main - * purpose is to be a basic switch engine when the MI code is already - * dealing with spin-preemption or other gunk. - * - * What we do here is allocate the ucontext for the 'self' thread on its - * stack, saving the pointer in self's pthread structure, then swapping - * context to 'next', effectively deallocating next's context on the way - * out. - */ -ENTRY(pthread__switch) - sub sp, sp, #(RND_CTXSIZE) /* push space for ucontext_t */ - - mov r3, sp /* r3 = &context */ - - /* Save r0-r2, r4-r5, lr */ - stmfd sp!, {r0-r2, r4-r5, lr} - - /* Now r5 will point to &context for the duration. */ - mov r5, r3 - -/* - * Stack is: - * context (RND_CTXSIZE bytes) - * saved lr ( 4 bytes) - * saved r5 ( 4 bytes) - * saved r4 ( 4 bytes) - * saved r2 ( 4 bytes) - * saved r1 ( 4 bytes) - * saved r0 ( 4 bytes) - * Note, no space needed - * for callees. - */ - - /* Get the current context. */ - mov r0, r5 /* r0 = &context */ - bl PIC_SYM(_C_LABEL(_getcontext_u), PLT) - - /* Edit the context to make it continue below, rather than here */ - add r0, pc, #pthread__switch_return_point - . - 8 - str r0, [r5, #(_REG_PC)] - - /* Get back r0-r2 */ - ldmfd sp, {r0-r2} - - str r5, [r0, #(PT_UC)] /* self->pt_uc = &context */ - - /* Side-effect: r4 = next->pt_uc */ - STACK_SWITCH(r1, r4, r3) - - /* NOTE: we can no longer recover registers stored on the stack */ - - mov r0, r4 /* r0 = next->pt_uc */ - b PIC_SYM(_C_LABEL(_setcontext_u), PLT) - NOTREACHED - -ENTRY_NP(pthread__switch_return_point) -/* - * Stack is: - * context (RND_CTXSIZE bytes) - * saved lr ( 4 bytes) - * saved r5 ( 4 bytes) - * saved r4 ( 4 bytes) - * saved r2 ( 4 bytes) - * saved r1 ( 4 bytes) - * saved r0 ( 4 bytes) - * Note, no space needed - * for callees. - */ - - add sp, sp, #12 /* skip over r0-r2 */ - ldmfd sp!, {r4-r5, lr} /* restore r4-r5, lr */ - add sp, sp, #(RND_CTXSIZE) /* pop ucontext_t */ - RET - -/* - * Helper routine; r0 = from, r1 = to, r2 = decr-spinlocks (boolean) - */ -pthread__switch_away: - /* Side-effect: r3 = r1->pt_uc */ - STACK_SWITCH(r1, r3, r14) - - /* - * If we're invoked from the switch-to-next provisions of - * pthread__locked_switch() or pthread__upcall_switch(), - * there may be a fake spinlock-count set. If so, they will - * set r2 to let us know, and we decrement it now that we're - * no longer using the old stack. - */ - teq r2, #0x00000000 - beq 1f - ldr r2, [r0, #(PT_SPINLOCKS)] - sub r2, r2, #1 - str r2, [r0, #(PT_SPINLOCKS)] - -1: mov r0, r3 - b PIC_SYM(_C_LABEL(_setcontext_u), PLT) - NOTREACHED - -/* - * void - * pthread__upcall_switch(pthread_t self (r0), pthread_t next (r1)) - * - * Quit an upcall, recycle it, and jump to the selected thread. - * - * Note: This code never returns, so we can use the callee-saved - * registers to our heart's content (and they will be preserved - * by functions that we call). - */ -ENTRY(pthread__upcall_switch) - /* Create a "fake" lock count so that this code will be continued */ - ldr r3, [r1, #(PT_SPINLOCKS)] - add r3, r3, #1 - str r3, [r1, #(PT_SPINLOCKS)] - - /* Side-effect: r7 = next->pt_uc */ - STACK_SWITCH(r1, r7, r2) - - /* Check if the upcall code was preempted and continued to here. */ - ldr r3, [r0, #(PT_NEXT)] - teq r3, #0x00000000 - beq 1f - - /* - * Yes, it was. Stash the tread we were going to switch to, - * and switch to the next thread in the continuation chain. - */ - str r7, [r0, #(PT_SWITCHTOUC)] - str r1, [r0, #(PT_SWITCHTO)] - mov r0, r1 /* from = next */ - mov r1, r3 /* to = self->pt_next */ - mov r2, #0x00000001 /* decr-spinlocks = TRUE */ - b pthread__switch_away - NOTREACHED - -1: /* No old-upcall-preemption */ - mov r4, r0 /* stash from */ - mov r5, r1 /* stash to */ - bl PIC_SYM(_C_LABEL(pthread__sa_recycle), PLT) - mov r0, r4 /* restore from */ - mov r1, r5 /* restore to */ - - /* We can now release the fake lock. */ - ldr r3, [r1, #(PT_SPINLOCKS)] - sub r3, r3, #1 - str r3, [r1, #(PT_SPINLOCKS)] - - /* Check if we were preempted and continued while faking the lock */ - ldr r3, [r1, #(PT_NEXT)] - teq r3, #0x00000000 - beq 2f - - /* - * Yes, we were. Stash the thread we were going to switch to - * in itself, and switch to the next thread in the continuation - * chain. - */ - str r7, [r1, #(PT_SWITCHTOUC)] - str r1, [r1, #(PT_SWITCHTO)] - mov r0, r1 /* from = next */ - mov r1, r3 /* to = next->pt_next */ - mov r2, #0x00000000 /* decr-spinlocks = FALSE */ - b pthread__switch_away - NOTREACHED - -2: /* No new-upcall-preemption */ - mov r0, r7 /* r0 = next->pt_uc */ - b PIC_SYM(_C_LABEL(_setcontext_u), PLT) - -/* - * void - * pthread__locked_switch(pthread_t self (r0), pthread_t next (r1), - * pt_spin_t *lock (r2)) - * - * Total stack is: - * context (RND_CTXSIZE bytes) - * saved lr ( 4 bytes) - * saved r5 ( 4 bytes) - * saved r4 ( 4 bytes) - * saved r2 ( 4 bytes) - * saved r1 ( 4 bytes) - * saved r0 ( 4 bytes) - * Note, no space needed - * for callees. - * - * STACKSPACE is the space between the bottom of the stack and - * the ucontext on the stack. i.e., (6 * sizeof(reg)). - * - * Note: We use r4 as a temporary register, and r5 as a pointer to - * the context on the stack. - */ -ENTRY(pthread__locked_switch) - sub sp, sp, #(RND_CTXSIZE) /* push space for ucontext_t */ - - /* Make sure we get continued */ - ldr r3, [r1, #(PT_SPINLOCKS)] - add r3, r3, #1 - str r3, [r1, #(PT_SPINLOCKS)] - - mov r3, sp /* r3 = &context */ - - /* Save r0-r2, r4-r5, lr */ - stmfd sp!, {r0-r2, r4-r5, lr} - - /* Now r5 will point to &context for the duration. */ - mov r5, r3 - -/* - * Stack is: - * context (RND_CTXSIZE bytes) - * saved lr ( 4 bytes) - * saved r5 ( 4 bytes) - * saved r4 ( 4 bytes) - * saved r2 ( 4 bytes) - * saved r1 ( 4 bytes) - * saved r0 ( 4 bytes) - * Note, no space needed - * for callees. - */ - - /* Get the current context. */ - mov r0, r5 /* r0 = &context */ - bl PIC_SYM(_C_LABEL(_getcontext_u), PLT) - - /* Edit the context to make it continue below, rather than here */ - add r0, pc, #locked_return_point - . - 8 - str r0, [r5, #(_REG_PC)] - - /* Get back r0-r2 */ - ldmfd sp, {r0-r2} - - str r5, [r0, #(PT_UC)] /* self->pt_uc = &context */ - - /* Side-effect: r4 = next->pt_uc */ - STACK_SWITCH(r1, r4, r3) - - /* NOTE: we can no longer recover registers stored on the stack */ - - /* Check if the switcher was preempted and continued to here. */ - ldr r3, [r0, #(PT_NEXT)] - teq r3, #0x00000000 - beq 1f - - /* - * Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, and switch to - * the next thread in the continuation chain. Mark the fact - * that this was a locked switch, and so the thread does not - * need to be put on a run queue. - * - * DO NOT RELEASE THE LOCK. It's possible that if we do so, - * PT_SWITCHTO will be stomped on by another switch_lock and - * preemption. - */ - str r2, [r0, #(PT_HELDLOCK)] - str r4, [r0, #(PT_SWITCHTOUC)] - str r1, [r0, #(PT_SWITCHTO)] - - ldr r4, [r0, #(PT_SPINLOCKS)] - sub r4, r4, #1 - str r4, [r0, #(PT_SPINLOCKS)] - - mov r0, r1 /* from = next */ - mov r1, r3 /* to = self->pt_next */ - mov r2, #0x00000001 /* decr-spinlocks = TRUE */ - b pthread__switch_away - NOTREACHED - -1: /* No locked-old-preemption */ - - /* - * Note: r4 == next->pt_uc still. We no longer need to - * reference the context on the stack, so put next->pt_uc - * in r5 so that we can use r4 as a temporary. - */ - mov r5, r4 - - /* - * We've moved to the new stack, and the old context has - * been saved. The queue lock can be released. - */ - ldr r4, [r0, #(PT_SPINLOCKS)] - sub r4, r4, #1 - str r4, [r0, #(PT_SPINLOCKS)] - - /* ...actually release the lock... */ - mov r4, #(__SIMPLELOCK_UNLOCKED) - str r4, [r2] - - /* ...and remove the fake lock... */ - ldr r4, [r1, #(PT_SPINLOCKS)] - sub r4, r4, #1 - str r4, [r1, #(PT_SPINLOCKS)] - - /* Check if we were preempted while holding the fake lock. */ - ldr r3, [r1, #(PT_NEXT)] - teq r3, #0x00000000 - beq 2f - - /* Yes, we were. Go to the next thread in the chain. */ - str r5, [r1, #(PT_SWITCHTOUC)] - str r1, [r1, #(PT_SWITCHTO)] - mov r0, r1 /* from = next */ - mov r1, r3 /* to = next->pt_next */ - mov r2, #0x00000000 /* decr-spinlocks = FALSE */ - b pthread__switch_away - -2: /* No locked-new-preemption */ - mov r0, r5 /* r0 = next->pt_uc */ - b PIC_SYM(_C_LABEL(_setcontext_u), PLT) - NOTREACHED - -locked_return_point: -/* - * Stack is: - * context (RND_CTXSIZE bytes) - * saved lr ( 4 bytes) - * saved r5 ( 4 bytes) - * saved r4 ( 4 bytes) - * saved r2 ( 4 bytes) - * saved r1 ( 4 bytes) - * saved r0 ( 4 bytes) - * Note, no space needed - * for callees. - */ - - add sp, sp, #12 /* skip over r0-r2 */ - ldmfd sp!, {r4-r5, lr} /* restore r4-r5, lr */ - add sp, sp, #(RND_CTXSIZE) /* pop ucontext_t */ - RET diff --git a/lib/libpthread/arch/hppa/genassym.cf b/lib/libpthread/arch/hppa/genassym.cf index 67a39890df0..5b931c369f4 100644 --- a/lib/libpthread/arch/hppa/genassym.cf +++ b/lib/libpthread/arch/hppa/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.1 2004/07/19 03:39:02 chs Exp $ +# $NetBSD: genassym.cf,v 1.2 2007/03/02 18:53:56 ad Exp $ # Copyright (c) 2001 The NetBSD Foundation, Inc. # All rights reserved. @@ -42,13 +42,6 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) -define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define CONTEXTSIZE sizeof(ucontext_t) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_REGS offsetof(ucontext_t, uc_mcontext.__gregs) diff --git a/lib/libpthread/arch/hppa/pthread_switch.S b/lib/libpthread/arch/hppa/pthread_switch.S deleted file mode 100644 index 6faa5d9b6d7..00000000000 --- a/lib/libpthread/arch/hppa/pthread_switch.S +++ /dev/null @@ -1,317 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.1 2004/07/19 03:39:02 chs Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Wayne Knowles. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -#include <machine/asm.h> -#include <machine/frame.h> -#include "assym.h" - -#define CTXFRAMESIZE \ - (HPPA_FRAME_SIZE * 2 + HPPA_FRAME_ROUND(CONTEXTSIZE)) - -/* Force an error when "notreached" code is reached. */ -#define NOTREACHED \ - break 0,0 ! \ - /* NOTREACHED */ - -/* *** WARNING *** - * STACK_SWITCH is more subtle than it looks. Please go read the extended - * comment in the i386 pthread_switch.S file. - */ - -#define STACK_SWITCH(pt,tmp) \ - ldw PT_TRAPUC(pt), tmp ! \ - comb,<>,n %r0, tmp, 99f ! \ - ldw PT_UC(pt), tmp ! \ -99: ldo CTXFRAMESIZE(tmp), %sp ! \ - stw %r0, PT_TRAPUC(pt) - -/* - * void pthread__switch(pthread_t self, pthread_t next); - */ - -ENTRY(pthread__switch, CTXFRAMESIZE) - stw %rp, HPPA_FRAME_CRP(%sp) - copy %sp, %r1 - ldo CTXFRAMESIZE(%sp), %sp - stw %arg0, HPPA_FRAME_ARG(0)(%sp) - stw %arg1, HPPA_FRAME_ARG(1)(%sp) - - copy %r1, %arg0 - stw %r19, HPPA_FRAME_ARG(2)(%sp) - PIC_CALL(_getcontext_u) - ldw HPPA_FRAME_ARG(2)(%sp), %r19 - - ldw HPPA_FRAME_ARG(0)(%sp), %arg0 - ldw HPPA_FRAME_ARG(1)(%sp), %arg1 - - /* Edit the context to make it continue below, rather than here */ - ldo -CTXFRAMESIZE(%sp), %t1 - stw %t1, PT_UC(%arg0) - addil LT%pthread__switch_return_point, %r19 - ldo RT%pthread__switch_return_point(%r1), %r1 - ldw 0(%r1), %t2 - stw %t2, UC_PCOQH(%t1) - - STACK_SWITCH(%arg1, %arg0) - - PIC_CALL(_setcontext_u) - NOTREACHED -EXIT(pthread__switch) -ENTRY_NOPROFILE(pthread__switch_return_point, 0) -9: - ldw (-CTXFRAMESIZE + HPPA_FRAME_CRP)(%sp), %rp - bv %r0(%rp) - ldo -CTXFRAMESIZE(%sp), %sp -EXIT(pthread__switch_return_point) - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - */ - -ENTRY(pthread__switch_away, HPPA_FRAME_SIZE) - STACK_SWITCH(%arg1, %t1) - - /* - * If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there may - * be a fake spinlock-count set. If so, they will set %arg2 to - * let us know, and we decrement it now that we're no longer - * using the old stack. - */ - comib,=,n 0, %arg2, 1f - ldw PT_SPINLOCKS(%arg0), %t2 - addi -1, %t2, %t2 - stw %t2, PT_SPINLOCKS(%arg0) - -1: copy %t1, %arg0 - - PIC_CALL(_setcontext_u) - NOTREACHED -EXIT(pthread__switch_away) - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pthread_spin_t *lock); - * - * Switch away from a thread that is holding a lock on a queue (to - * prevent being removed from the queue before being switched away). - */ - -ENTRY(pthread__locked_switch, CTXFRAMESIZE) - stw %rp, HPPA_FRAME_CRP(%sp) - ldo CTXFRAMESIZE(%sp), %sp - stw %arg0, HPPA_FRAME_ARG(0) - CTXFRAMESIZE(%sp) - stw %arg1, HPPA_FRAME_ARG(1) - CTXFRAMESIZE(%sp) - stw %arg2, HPPA_FRAME_ARG(2) - CTXFRAMESIZE(%sp) - - /* Make sure we get continued */ - ldw PT_SPINLOCKS(%arg1), %t1 - addi 1, %t1, %t1 - stw %t1, PT_SPINLOCKS(%arg1) - - /* Get the current context */ - ldo -CTXFRAMESIZE(%sp), %arg0 - PIC_CALL(_getcontext_u) - ldw HPPA_FRAME_ARG(0) - CTXFRAMESIZE(%sp), %arg0 - ldw HPPA_FRAME_ARG(1) - CTXFRAMESIZE(%sp), %arg1 - ldw HPPA_FRAME_ARG(2) - CTXFRAMESIZE(%sp), %arg2 - - /* Edit the context to make it continue below, rather than here */ - ldo -CTXFRAMESIZE(%sp), %t1 - bl 1f, %t2 - nop -1: ldo (locked_return_point - 1b)(%t2), %t2 - stw %t2, UC_PCOQH(%t1) - stw %t1, PT_UC(%arg0) - - STACK_SWITCH(%arg1, %t2) - - /* Check if the switcher was preempted and continued to here. */ - ldw PT_NEXT(%arg0), %t1 - comib,=,n 0, %t1, 1f - nop - - /* - * Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, - * and switch to the next thread in the continuation chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - - stw %arg2, PT_HELDLOCK(%arg0) - stw %t2, PT_SWITCHTOUC(%arg0) - stw %arg1, PT_SWITCHTO(%arg0) - - ldw PT_SPINLOCKS(%arg0), %t2 - addi -1, %t2, %t2 - stw %t2, PT_SPINLOCKS(%arg0) - - copy %arg1, %arg0 - copy %t1, %arg1 - ldi 1, %arg2 - b,n pthread__switch_away - NOTREACHED - - /* No locked old-preemption */ -1: /* We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - /* Reduce the lock count... */ - ldw PT_SPINLOCKS(%arg0), %t1 - addi -1, %t1, %t1 - stw %t1, PT_SPINLOCKS(%arg0) - /* ... actually release the lock.. */ - nop - ldi 1, %t1 - stw %t1, 0(%arg2) - /* .. and remove the fake lock */ - ldw PT_SPINLOCKS(%arg1), %t1 - addi -1, %t1, %t1 - stw %t1, PT_SPINLOCKS(%arg1) - - /* Check if we were preempted while holding the fake lock. */ - ldw PT_NEXT(%arg1), %t1 - comib,=,n 0, %t1, 2f - nop - - /* Yes, we were. Go to the next element in the chain. */ - stw %t2, PT_SWITCHTOUC(%arg1) - stw %arg1, PT_SWITCHTO(%arg1) - copy %arg1, %arg0 - copy %t1, %arg1 - copy %r0, %arg2 - b,n pthread__switch_away - NOTREACHED - -2: copy %t2, %arg0 - - PIC_CALL(_setcontext_u) - NOTREACHED - -locked_return_point: - ldo -CTXFRAMESIZE(%sp), %sp - ldw HPPA_FRAME_CRP(%sp), %rp - bv,n %r0(%rp) -EXIT(pthread__locked_switch) - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - */ - -ENTRY(pthread__upcall_switch, 0) - - /* - * This code never returns, so we don't need to save the - * callee-saved registers. - */ - - /* Create a "fake" lock count so that this code will be continued */ - ldw PT_SPINLOCKS(%arg1), %t1 - addi 1, %t1, %t1 - stw %t1, PT_SPINLOCKS(%arg1) - - STACK_SWITCH(%arg1, %r12) - - /* Check if the upcall code was preempted and continued to here. */ - ldw PT_NEXT(%arg0), %t1 - comib,=,n 0, %t1, 1f - - /* - * Yes, it was. Stash the thread we were going to switch to, - * and switch to the next thread in the continuation chain. - */ - stw %r12, PT_SWITCHTOUC(%arg0) - stw %arg1, PT_SWITCHTO(%arg0) - copy %arg1, %arg0 - copy %t1, %arg1 - ldi 1, %arg2 - b,n pthread__switch_away - NOTREACHED - - /* No old-upcall-preemption */ -1: copy %arg0, %r3 - copy %arg1, %r4 - PIC_CALL(pthread__sa_recycle) - copy %r3, %arg0 - copy %r4, %arg1 - - /* We can now release the fake lock. */ - ldw PT_SPINLOCKS(%arg1), %t1 - addi -1, %t1, %t1 - stw %t1, PT_SPINLOCKS(%arg1) - - /* Check if we were preempted and continued while faking the lock */ - ldw PT_NEXT(%arg1), %t1 - comib,=,n 0, %t1, 2f - - /* - * Yes, we were. Stash the to-be-switched-to context in our thread - * structure and go to the next link in the chain. - */ - stw %r12, PT_SWITCHTOUC(%arg1) - stw %arg1, PT_SWITCHTO(%arg1) - copy %arg1, %arg0 - copy %t1, %arg1 - copy %r0, %arg2 - b,n pthread__switch_away - - /* No new-upcall-preemption */ -2: copy %r12, %arg0 - - PIC_CALL(_setcontext_u) - NOTREACHED -EXIT(pthread__upcall_switch) diff --git a/lib/libpthread/arch/i386/genassym.cf b/lib/libpthread/arch/i386/genassym.cf index 4d54745522e..785ac65d261 100644 --- a/lib/libpthread/arch/i386/genassym.cf +++ b/lib/libpthread/arch/i386/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.5 2003/09/07 14:47:48 cl Exp $ +# $NetBSD: genassym.cf,v 1.6 2007/03/02 18:53:56 ad Exp $ # Copyright (c) 2001 The NetBSD Foundation, Inc. # All rights reserved. @@ -42,13 +42,7 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define CONTEXTSIZE sizeof(ucontext_t) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_REGS offsetof(ucontext_t, uc_mcontext.__gregs) diff --git a/lib/libpthread/arch/i386/pthread_switch.S b/lib/libpthread/arch/i386/pthread_switch.S deleted file mode 100644 index 9aa674f4383..00000000000 --- a/lib/libpthread/arch/i386/pthread_switch.S +++ /dev/null @@ -1,361 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.9 2006/01/04 12:43:43 skrll Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <machine/asm.h> -#include "assym.h" - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -/* Force an error when "notreached" code is reached. */ -#define NOTREACHED \ - int3 - - -/* - * Utility macro to switch to the stack of another thread. - * WARNING: This is more subtle than it looks. - * - * There are a couple of motivations for stack switching. One is that - * when exiting an upcall and running a thread, we want to recycle the - * state of the upcall before continuing the thread. However, the - * stack is part of the upcall state, and we can't be on the upcall - * stack when we want to recycle it. Therefore, we pre-switch to the - * stack of the thread we're about to switch to and borrow some space - * on its stack so that we can recycle the upcall. - * - * Another is that when performing the slightly sensitive operation of - * putting the currently running thread on a (locked) sleep queue then - * switching to another thread, we don't want to release the queue - * lock until we are no longer on the original stack - if we released - * it any earlier, it's possible (epecially on a multiprocessor - * system) that the original thread could get taken off the queue and - * restarted while we're still using its stack, which would be bad - * ("Important safety tip. Thanks, Egon"). - * - * The subtlety comes from the contents of the stack of the thread - * being switched to. Our convention is that the ucontext_t of the - * thread is stored near the top of the stack. When the kernel - * preempts a thread, it stores the ucontext_t just above the current - * top-of-stack and passes the upcall handler the pointer to the - * ucontext_t, and the upcall handler stores it in the pt_uc field - * of the thread structure. When user-level code voluntairly switches - * from one thread to another, the ucontext_t is just below the top of - * the stack, and we impose a limit on the amount of stack space above - * the ucontext_t that may be used. This way, we can perform the stack - * switch safely by setting the stack pointer to thread->pt_uc - - * STACKSPACE. - * Note carefully that we do the subtraction *before* putting the - * value in the stack pointer. Since preemption can occur at any time, - * and the kernel will happily write the new ucontext_t below the - * current stack pointer, it is unsafe for us to ever set the stack - * pointer above potentially valid data, even for one instruction. - * - * Got it? Good. Now go read it again. - * - */ - -#define STACK_SWITCH \ - movl PT_TRAPUC(%ecx), %esi ; \ - cmpl $0, %esi ; \ - jne 1f ; \ - movl PT_UC(%ecx), %esi ; \ -1: leal (-STACKSPACE)(%esi), %esp ; \ - movl $0, PT_TRAPUC(%ecx) - -/* - * void pthread__switch(pthread_t self, pthread_t next); - * - * Plain switch that doesn't do any special checking or handle - * spin-preemption. It isn't used much by normal code, actually; it's - * main purpose is to be a basic switch engine when the MI code is - * already dealing with spin-preemption or other gunk. - */ -ENTRY(pthread__switch) - pushl %ebp - movl %esp, %ebp - pushl %esi /* callee save */ - pushl %edi /* callee save */ - PIC_PROLOGUE - movl 8(%ebp), %eax /* eax holds the current thread */ - movl 12(%ebp), %ecx /* ecx holds the thread to switch to */ - subl $CONTEXTSIZE+12, %esp /* Allocate space for the ucontext_t */ - leal 12(%esp), %edi - andl $~(0xf), %edi /* 16-byte-align the ucontext_t area */ - /* - * Note: Alignment space below the ucontext_t can consume up to - * 12 bytes of STACKSPACE. - */ - pushl %eax /* caller save */ - pushl %ecx /* caller save */ - pushl %edi /* ucontext_t *ucp */ - call *PIC_GOTOFF(_C_LABEL(_md_getcontext_u)) - addl $4, %esp - popl %ecx - popl %eax - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below. - */ -#ifdef PIC - movl PIC_GOT(pthread__switch_return_point), %esi -#else - leal pthread__switch_return_point, %esi -#endif - movl %esi, UC_EIP(%edi) - - movl %edi, PT_UC(%eax) - - STACK_SWITCH - - pushl %esi /* ucontext_t *ucp */ - call *PIC_GOTOFF(_C_LABEL(_md_setcontext_u)) -NENTRY(pthread__switch_return_point) - /* We're back on the original stack. */ - addl $CONTEXTSIZE+24, %esp - PIC_EPILOGUE - popl %edi - popl %esi - movl %ebp, %esp - popl %ebp - ret - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - */ -pthread__switch_away: - STACK_SWITCH - - /* - * If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there - * may be a fake spinlock-count set. If so, they will set %edx - * to let us know, and we decrement it once we're no longer using - * the old stack. - */ - cmpl $0, %edx - jle pthread__switch_no_decrement - decl PT_SPINLOCKS(%eax) - -pthread__switch_no_decrement: - pushl %esi /* ucontext_t *ucp */ - call *PIC_GOTOFF(_C_LABEL(_md_setcontext_u)) - NOTREACHED - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * Switch away from a thread that is holding a lock on a queue (to - * prevent being removed from the queue before being switched away). - */ -ENTRY(pthread__locked_switch) - pushl %ebp - movl %esp, %ebp - pushl %esi /* callee save */ - pushl %edi /* callee save */ - PIC_PROLOGUE - movl 8(%ebp), %eax /* eax holds the current thread */ - movl 12(%ebp), %ecx /* ecx holds the thread to switch to */ - movl 16(%ebp), %edx /* edx holds the spinlock pointer */ - incl PT_SPINLOCKS(%ecx) /* Make sure we get continued */ - subl $CONTEXTSIZE+12, %esp /* Allocate space for the ucontext_t */ - leal 12(%esp), %edi - andl $~(0xf), %edi /* 16-byte-align the ucontext_t area */ - /* - * Note: Alignment space below the ucontext_t can consume up to - * 12 bytes of STACKSPACE. - */ - pushl %eax /* caller save */ - pushl %ecx /* caller save */ - pushl %edx /* caller save */ - pushl %edi /* ucontext_t *ucp */ - call *PIC_GOTOFF(_C_LABEL(_md_getcontext_u)) - addl $4, %esp - popl %edx - popl %ecx - popl %eax - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below. - */ -#ifdef PIC - movl PIC_GOT(locked_return_point), %esi -#else - leal locked_return_point, %esi -#endif - movl %esi, UC_EIP(%edi) - movl %edi, PT_UC(%eax) - - STACK_SWITCH - - /* - * Check if the original thread was preempted while holding - * its queue lock. - */ - cmpl $0, PT_NEXT(%eax) - je locked_no_old_preempt - - /* - * Yes, it was. Stash the thread we were going to - * switch to, the lock the original thread was holding, - * and go to the next thread in the chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - movl %esi, PT_SWITCHTOUC(%eax) - movl %ecx, PT_SWITCHTO(%eax) - movl %edx, PT_HELDLOCK(%eax) - decl PT_SPINLOCKS(%eax) - - movl PT_NEXT(%eax), %edx - movl %ecx, %eax - movl %edx, %ecx - movl $1, %edx - jmp pthread__switch_away - NOTREACHED - -locked_no_old_preempt: - /* - * We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - decl PT_SPINLOCKS(%eax) - /* We happen to know that this is the right way to release a lock. */ - movl $0, 0(%edx) - - decl PT_SPINLOCKS(%ecx) - /* Check if we were preempted while holding the fake lock. */ - cmpl $0, PT_NEXT(%ecx) - je locked_no_new_preempt - /* Yes, we were. Bummer. Go to the next element in the chain. */ - movl %esi, PT_SWITCHTOUC(%ecx) - movl %ecx, PT_SWITCHTO(%ecx) - movl %ecx, %eax - movl PT_NEXT(%ecx), %ecx - movl $-2, %edx - jmp pthread__switch_away - NOTREACHED - -locked_no_new_preempt: - pushl %esi /* ucontext_t *ucp */ - call *PIC_GOTOFF(_C_LABEL(_md_setcontext_u)) -locked_return_point: - /* We're back on the original stack. */ - addl $CONTEXTSIZE+28, %esp - PIC_EPILOGUE - popl %edi - popl %esi - movl %ebp, %esp - popl %ebp - ret - - - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - */ -ENTRY(pthread__upcall_switch) - /* Save args into registers so we can stop using the old stack. */ - pushl %ebp - movl %esp, %ebp - /* No need to save %esi, %edi; this function never returns */ - PIC_PROLOGUE - movl 8(%ebp), %eax /* eax holds the upcall thread */ - movl 12(%ebp), %ecx /* ecx holds the thread to switch to */ - incl PT_SPINLOCKS(%ecx) - - STACK_SWITCH - - /* Check if the upcall was preempted and continued. */ - cmpl $0, PT_NEXT(%eax) - je upcall_no_old_preempt - /* - * Yes, it was. Stash the thread we were going to - * switch to, and go to the next thread in the chain. - */ - movl %esi, PT_SWITCHTOUC(%eax) - movl %ecx, PT_SWITCHTO(%eax) - movl PT_NEXT(%eax), %edx - movl %ecx, %eax - movl %edx, %ecx - movl $1, %edx - jmp pthread__switch_away - NOTREACHED - -upcall_no_old_preempt: - pushl %eax /* caller save */ - pushl %ecx /* caller save */ - pushl %ecx /* pthread_t new */ - pushl %eax /* pthread_t old */ - call PIC_PLT(_C_LABEL(pthread__sa_recycle)) - addl $8, %esp - popl %ecx - popl %eax - decl PT_SPINLOCKS(%ecx) - /* Check if we were preempted while holding the fake lock. */ - cmpl $0, PT_NEXT(%ecx) - je upcall_no_new_preempt - /* Yes, we were. Bummer. Go to the next element in the chain. */ - movl %esi, PT_SWITCHTOUC(%ecx) - movl %ecx, PT_SWITCHTO(%ecx) - movl %ecx, %eax - movl PT_NEXT(%ecx), %ecx - movl $-1, %edx - jmp pthread__switch_away - NOTREACHED - -upcall_no_new_preempt: - pushl %esi - call *PIC_GOTOFF(_C_LABEL(_md_setcontext_u)) - NOTREACHED diff --git a/lib/libpthread/arch/m68k/genassym.cf b/lib/libpthread/arch/m68k/genassym.cf index 6d6b848132c..2afbf54e10d 100644 --- a/lib/libpthread/arch/m68k/genassym.cf +++ b/lib/libpthread/arch/m68k/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.5 2003/09/07 14:47:49 cl Exp $ +# $NetBSD: genassym.cf,v 1.6 2007/03/02 18:53:56 ad Exp $ # Copyright (c) 2001 The NetBSD Foundation, Inc. # All rights reserved. @@ -42,13 +42,6 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) -define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_REGS offsetof(ucontext_t, uc_mcontext.__gregs) define UC_FPREGS offsetof(ucontext_t, uc_mcontext.__fpregs) diff --git a/lib/libpthread/arch/m68k/pthread_switch.S b/lib/libpthread/arch/m68k/pthread_switch.S deleted file mode 100644 index 933ff317522..00000000000 --- a/lib/libpthread/arch/m68k/pthread_switch.S +++ /dev/null @@ -1,347 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.7 2004/04/23 02:58:27 simonb Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams and Steve C. Woodford. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Based on the i386 version. - */ - -#include <machine/asm.h> -#include "assym.h" - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -/* Force an error when "notreached" code is reached. */ -#define NOTREACHED \ - illegal - -/* - * Utility macro to switch to the stack of another thread. - * WARNING: This is more subtle than it looks. - * - * There are a couple of motivations for stack switching. One is that - * when exiting an upcall and running a thread, we want to recycle the - * state of the upcall before continuing the thread. However, the - * stack is part of the upcall state, and we can't be on the upcall - * stack when we want to recycle it. Therefore, we pre-switch to the - * stack of the thread we're about to switch to and borrow some space - * on its stack so that we can recycle the upcall. - * - * Another is that when performing the slightly sensitive operation of - * putting the currently running thread on a (locked) sleep queue then - * switching to another thread, we don't want to release the queue - * lock until we are no longer on the original stack - if we released - * it any earlier, it's possible (epecially on a multiprocessor - * system) that the original thread could get taken off the queue and - * restarted while we're still using its stack, which would be bad - * ("Important saftey tip. Thanks, Egon"). - * - * The subtlety comes from the contents of the stack of the thread - * being switched to. Our convention is that the ucontext_t of the - * thread is stored near the top of the stack. When the kernel - * preempts a thread, it stores the ucontext_t just above the current - * top-of-stack and passes the upcall handler the pointer to the - * ucontext_t, and the upcall handler stores it in the pt_uc field - * of the thread structure. When user-level code voluntairly switches - * from one thread to another, the ucontext_t is just below the top of - * the stack, and we impose a limit on the amount of stack space above - * the ucontext_t that may be used. This way, we can perform the stack - * switch safely by setting the stack pointer to thread->pt_uc - - * STACKSPACE. - * Note carefully that we do the subtraction *before* putting the - * value in the stack pointer. Since preemption can occur at any time, - * and the kernel will happily write the new ucontext_t below the - * current stack pointer, it is unsafe for us to ever set the stack - * pointer above potentially valid data, even for one instruction. - * - * Got it? Good. Now go read it again. - * - */ - -#define STACK_SWITCH(pt,tmp) \ - movl %pt@(PT_TRAPUC),%tmp ; \ - cmpl #0,%tmp ; \ - bne 1f ; \ - movl %pt@(PT_UC),%tmp ; \ -1: lea %tmp@(-STACKSPACE),%sp ; \ - clrl %pt@(PT_TRAPUC) - -/* - * void pthread__switch(pthread_t self, pthread_t next); - * - * Plain switch that doesn't do any special checking or handle - * spin-preemption. It isn't used much by normal code, actually; it's - * main purpose is to be a basic switch engine when the MI code is - * already dealing with spin-preemption or other gunk. - */ - -ENTRY(pthread__switch) - lea %sp@(-RND_CTXSIZE),%sp /* Allocate space for the ucontext_t */ - - /* - * Save `self's context - */ - movl %sp,%sp@- - jbsr PIC_PLT(_C_LABEL(_getcontext_u)) - addql #4,%sp - - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below. - */ - lea %pc@(Lswitch_return_point),%a0 - movl %a0,%sp@(UC_PC) - - movl %sp@(RND_CTXSIZE+4),%a0 /* `self': Thread to switch from */ - movl %sp@(RND_CTXSIZE+8),%a1 /* `next': Thread to switch to */ - movl %sp,%a2 /* a3 = &context */ - movl %a2,%a0@(PT_UC) /* self->pt_uc = &context */ - - STACK_SWITCH(a1,a3) /* side effect: a3 = next->pt_uc */ - - - /* - * Restore `next's context - */ - pea %a3@ - jbsr PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - -ENTRY_NOPROFILE(pthread__switch_return_point) -Lswitch_return_point: - /* We're back on the original stack. */ - lea %sp@(RND_CTXSIZE+4),%sp /* Ditch the ucontext_t */ - rts - - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - * - * Call with: - * a1 = from, a2 = to - */ -Lpthread__switch_away_decrement: - STACK_SWITCH(a2,a0) /* side effect: a0 = to->pt_uc */ - - /* If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there - * may be a fake spinlock-count set. If so, we decrement it - * once we're no longer using the old stack. - */ - subql #1, %a1@(PT_SPINLOCKS) - pea %a0@ - jbsr PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - -Lpthread__switch_away_no_decrement: - STACK_SWITCH(a2,a0) /* side effect: a0 = to->pt_uc */ - pea %a0@ - jbsr PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * Switch away from a thread that is holding a lock on a queue (to - * prevent being removed from the queue before being switched away). - */ -ENTRY(pthread__locked_switch) - lea %sp@(-RND_CTXSIZE),%sp /* Space for ucontext_t */ - movl %sp@(RND_CTXSIZE+8),%a0 /* `next': Thread to switch to */ - addql #1,%a0@(PT_SPINLOCKS) /* Make sure we get continued */ - movl %sp@(RND_CTXSIZE+4),%a0 /* `self': current thread */ - movl %sp,%a0@(PT_UC) /* self->pt_uc = &context */ - - /* - * Save `self's context - */ - movl %sp,%sp@- - jbsr PIC_PLT(_C_LABEL(_getcontext_u)) - addql #4,%sp - - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below. - */ - lea %pc@(Llocked_return_point),%a0 - movl %a0,%sp@(UC_PC) - - /* - * Fetch function parameters now that callee-saved registers - * are available. (They're saved in the context) - */ - movl %sp@(RND_CTXSIZE+4),%a2 /* a2 = self */ - movl %sp@(RND_CTXSIZE+8),%a1 /* a1 = next */ - movl %sp@(RND_CTXSIZE+12),%a0 /* a0 = lock */ - movl %sp,%a4 /* a4 = &context */ - - STACK_SWITCH(a1,a3) /* side effect: a3 = next->pt_uc */ - - /* Now running on `next's stack. */ - - /* Check if the original thread was preempted while holding - * its queue lock. - */ - movl %a2@(PT_NEXT),%d0 /* self->pt_next == 0? */ - beqs Llocked_no_old_preempt /* Yup */ - - /* Yes, it was. Stash the thread we were going to - * switch to, the lock the original thread was holding, - * and go to the next thread in the chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - movl %a0,%a2@(PT_HELDLOCK) - movl %a3,%a2@(PT_SWITCHTOUC) - movl %a1,%a2@(PT_SWITCHTO) - subql #1,%a2@(PT_SPINLOCKS) - - /* a1 already == from */ - movl %d0,%a2 /* to = self->pt_next */ - jbra Lpthread__switch_away_decrement - /* NOTREACHED */ - -Llocked_no_old_preempt: - /* a0 = lock, a1 = next, a2 = self, a3 = next->pt_uc */ - - /* - * We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - subql #1,%a2@(PT_SPINLOCKS) /* self->pt_spinlocks-- */ - - /* We happen to know that this is the right way to release a lock. */ - clrb %a0@ /* *lock = 0 */ - - /* Remove the fake lock */ - subql #1,%a1@(PT_SPINLOCKS) /* next->pt_spinlocks-- */ - - /* Check if we were preempted while holding the fake lock. */ - movl %a1@(PT_NEXT),%d0 /* (%d0 = next->pt_next) == NULL? */ - beqs Llocked_no_new_preempt /* Yup */ - - /* Yes, we were. Bummer. Go to the next element in the chain. */ - movl %a3,%a1@(PT_SWITCHTOUC) - movl %a1,%a1@(PT_SWITCHTO) /* next->pt_switchto = next */ - movl %d0,%a2 - jbra Lpthread__switch_away_no_decrement - -Llocked_no_new_preempt: - pea %a3@ /* _setcontext_u(next->pt_uc) */ - jbsr PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - -Llocked_return_point: - /* We're back on the original stack. */ - lea %sp@(RND_CTXSIZE+4),%sp /* Ditch the ucontext_t */ - rts - - - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - * Since this code never returns, we are free to use callee-saved - * registers. - */ -ENTRY(pthread__upcall_switch) - /* Save args into registers so we can stop using the old stack. */ - movl %sp@(4),%a2 /* a2 = self (the upcall thread) */ - movl %sp@(8),%a3 /* a3 = next */ - - /* Create a `fake' lock count so we are `continued' */ - addql #1,%a3@(PT_SPINLOCKS) - - STACK_SWITCH(a3,a4) /* side effect: a4 = next->pt_uc */ - - /* Check if the upcall was preempted and continued. */ - movl %a2@(PT_NEXT),%d0 - beqs Lupcall_no_old_preempt - - /* Yes, it was. Stash the thread we were going to - * switch to, and go to the next thread in the chain. - */ - movl %a4,%a2@(PT_SWITCHTOUC) - movl %a3,%a2@(PT_SWITCHTO) - movl %a3,%a1 /* from(a1) = next */ - movl %d0,%a2 /* to(a2) = self->pt_next */ - jbra Lpthread__switch_away_decrement - /* NOTREACHED */ - -Lupcall_no_old_preempt: - /* pthread__sa_recycle(old, new) */ - pea %a3@ /* new = next(a3) */ - pea %a2@ /* old = self(a2) */ - jbsr PIC_PLT(_C_LABEL(pthread__sa_recycle)) - addql #8,%sp - - /* Release the fake lock */ - subql #1,%a3@(PT_SPINLOCKS) - - /* Check if we were preempted while holding the fake lock. */ - movl %a3@(PT_NEXT),%d0 - beqs Lupcall_no_new_preempt - - /* Yes, we were. Bummer. Go to the next element in the chain. */ - movl %a4,%a3@(PT_SWITCHTOUC) - movl %a3,%a3@(PT_SWITCHTO) - movl %d0,%a2 /* to(a2) = self->pt_next */ - jbra Lpthread__switch_away_no_decrement - /* NOTREACHED */ - -Lupcall_no_new_preempt: - pea %a4@ - jbsr PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - diff --git a/lib/libpthread/arch/mips/genassym.cf b/lib/libpthread/arch/mips/genassym.cf index f072617abdd..07315e98fab 100644 --- a/lib/libpthread/arch/mips/genassym.cf +++ b/lib/libpthread/arch/mips/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.5 2003/09/07 14:47:50 cl Exp $ +# $NetBSD: genassym.cf,v 1.6 2007/03/02 18:53:57 ad Exp $ # Copyright (c) 2001 The NetBSD Foundation, Inc. # All rights reserved. @@ -42,13 +42,7 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define CONTEXTSIZE sizeof(ucontext_t) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_REGS offsetof(ucontext_t, uc_mcontext.__gregs) diff --git a/lib/libpthread/arch/mips/pthread_switch.S b/lib/libpthread/arch/mips/pthread_switch.S deleted file mode 100644 index 05eb48089f5..00000000000 --- a/lib/libpthread/arch/mips/pthread_switch.S +++ /dev/null @@ -1,311 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.6 2003/09/07 14:47:51 cl Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Wayne Knowles. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -#include <machine/asm.h> -#include "assym.h" - -#ifdef __ABICALLS__ - .abicalls -# define PIC_PROLOGUE(x,sr) \ - .set noreorder ; \ - .cpload sr ; \ - .set reorder - -# define PIC_CALL(l,sr) \ - la sr, _C_LABEL(l) ; \ - jalr sr - -#else -# define PIC_PROLOGUE(x,sr) -# define PIC_CALL(l,sr) \ - jalr _C_LABEL(l) - -#endif - -/* Force an error when "notreached" code is reached. */ -#define NOTREACHED \ - break 1 ; \ - /* NOTREACHED */ - -/* *** WARNING *** - * STACK_SWITCH is more subtle than it looks. Please go read the extended - * comment in the i386 pthread_switch.S file. - */ - -#define STACK_SWITCH(pt,tmp) \ - lw tmp, PT_TRAPUC(pt) ; \ - bnez tmp, 1f ; \ - lw tmp, PT_UC(pt) ; \ -1: la sp, -STACKSPACE(tmp) ; \ - sw zero, PT_TRAPUC(pt) - -NESTED(pthread__switch, CALLFRAME_SIZ+CONTEXTSIZE, ra) - .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) - PIC_PROLOGUE(pthread__switch, t9) - subu sp, sp, (CALLFRAME_SIZ+CONTEXTSIZE) - sw ra, CALLFRAME_RA(sp) - sw a0, 0(sp) - sw a1, 4(sp) - - la a0, CALLFRAME_SIZ(sp) - PIC_CALL(_getcontext_u, t9) - lw a0, 0(sp) - lw a1, 4(sp) - - /* Edit the context to make it continue below, rather than here */ - la t3, CALLFRAME_SIZ(sp) - la t1, pthread__switch_return_point - sw t1, UC_EPC(t3) - sw t3, PT_UC(a0) - - STACK_SWITCH(a1, t2) - - move a0, t2 - PIC_CALL(_setcontext_u, t9) - NOTREACHED -XNESTED(pthread__switch_return_point) - lw ra, CALLFRAME_RA(sp) - addiu sp, (CALLFRAME_SIZ+CONTEXTSIZE) - j ra - END(pthread__switch) - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - */ - -NESTED(pthread__switch_away, CALLFRAME_SIZ, ra) - .mask 0x00000000, (CALLFRAME_RA - CALLFRAME_SIZ) - STACK_SWITCH(a1, s2) - - /* If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there may - * be a fake spinlock-count set. If so, they will set a2 to - * let us know, and we decrement it now that we're no longer - * using the old stack. - */ - beqz a2, 1f - lw t0, PT_SPINLOCKS(a0) - subu t0, t0, 1 - sw t0, PT_SPINLOCKS(a0) - -1: move a0, s2 - PIC_CALL(_setcontext_u, t9) - NOTREACHED - END(pthread__switch_away) - -NESTED(pthread__locked_switch, CALLFRAME_SIZ+CONTEXTSIZE, ra) - .mask 0x80000070, (CALLFRAME_RA - CALLFRAME_SIZ) - PIC_PROLOGUE(pthread__locked_switch, t9) - subu sp, sp, (CALLFRAME_SIZ+CONTEXTSIZE) - sw ra, CALLFRAME_RA(sp) - sw a0, 0(sp) - sw a1, 4(sp) - sw a2, 8(sp) - - /* Make sure we get continuted */ - lw t0, PT_SPINLOCKS(a1) - addiu t0, t0, 1 - sw t0, PT_SPINLOCKS(a1) - - /* Get the current context */ - la a0, CALLFRAME_SIZ(sp) - PIC_CALL(_getcontext_u, t9) - lw a0, 0(sp) - lw a1, 4(sp) - lw a2, 8(sp) - - /* Edit the context to make it continue below, rather than here */ - la t3, CALLFRAME_SIZ(sp) - la t1, locked_return_point - sw t1, UC_EPC(t3) - sw t3, PT_UC(a0) - - STACK_SWITCH(a1, t2) - - /* Check if the switcher was preempted and continued to here. */ - lw t0, PT_NEXT(a0) - beqz t0, 1f - nop - - /* Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, - * and switch to the next thread in the continuation chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - sw a2, PT_HELDLOCK(a0) - sw t2, PT_SWITCHTOUC(a0) - sw a1, PT_SWITCHTO(a0) - lw t4, PT_SPINLOCKS(a0) - subu t4, t4, 1 - sw t4, PT_SPINLOCKS(a0) - - move a0, a1 - move a1, t0 - li a2, 1 - j pthread__switch_away - NOTREACHED - - /* No locked old-preemption */ -1: /* We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - /* Reduce the lock count... */ - lw t0, PT_SPINLOCKS(a0) - subu t0, t0, 1 - sw t0, PT_SPINLOCKS(a0) - /* ... actually release the lock.. */ - nop # sync - sw zero, 0(a2) - /* .. and remove the fake lock */ - lw t0, PT_SPINLOCKS(a1) - subu t0, t0, 1 - sw t0, PT_SPINLOCKS(a1) - - /* Check if we were preempted while holding the fake lock. */ - lw t0, PT_NEXT(a1) - beqz t0, 2f - nop - - /* Yes, we were. Go to the next element in the chain. */ - sw t2, PT_SWITCHTOUC(a1) - sw a1, PT_SWITCHTO(a1) - move a0, a1 - move a1, t0 - li a2, 0 - j pthread__switch_away - NOTREACHED - -2: move a0, t2 - PIC_CALL(_setcontext_u, t9) - NOTREACHED - -locked_return_point: - lw ra, CALLFRAME_RA(sp) - addiu sp, sp, (CALLFRAME_SIZ+CONTEXTSIZE) - j ra - END(pthread__locked_switch) - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - */ - -NESTED(pthread__upcall_switch, 0, ra) - .mask 0x00000000, (CALLFRAME_RA - CALLFRAME_SIZ) - PIC_PROLOGUE(pthread__upcall_switch, t9) - - /* Loading the global pointer is unnecessary; this routine - * is only ever called from the pthreads module, and the C - * code will have gp set up. - * - * Also, this code never returns, so we can treat s0-s6 as - * convenient registers that will be saved for us by callees, - * but that we do not have to save. - */ - - /* Create a "fake" lock count so that this code will be continued */ - lw t0, PT_SPINLOCKS(a1) - addiu t0, t0, 1 - sw t0, PT_SPINLOCKS(a1) - - STACK_SWITCH(a1,s2) - - /* Check if the upcall code was preempted and continued to here. */ - lw t0, PT_NEXT(a0) - beqz t0, 1f - - /* Yes, it was. Stash the thread we were going to switch to, - * and switch to the next thread in the continuation chain. - */ - sw s2, PT_SWITCHTOUC(a0) - sw a1, PT_SWITCHTO(a0) - move a0, a1 - move a1, t0 - li a2, 1 - j pthread__switch_away - NOTREACHED - - /* No old-upcall-preemption */ -1: move s0, a0 - move s1, a1 - PIC_CALL(pthread__sa_recycle, t9) - move a0, s0 - move a1, s1 - - /* We can now release the fake lock. */ - lw t0, PT_SPINLOCKS(a1) - subu t0, t0, 1 - sw t0, PT_SPINLOCKS(a1) - - /* Check if we were preempted and continued while faking the lock */ - lw t0, PT_NEXT(a1) - beqz t0, 2f - - /* Yes, we were. Stash the to-be-switched-to context in our thread - * structure and go to the next link in the chain. - */ - sw s2, PT_SWITCHTOUC(a1) - sw a1, PT_SWITCHTO(a1) - move a0, a1 - move a1, t0 - li a2, 0 - j pthread__switch_away - - /* No new-upcall-preemption */ -2: move a0, s2 - PIC_CALL(_setcontext_u, t9) - NOTREACHED - END(pthread__upcall_switch) diff --git a/lib/libpthread/arch/powerpc/genassym.cf b/lib/libpthread/arch/powerpc/genassym.cf index cf79795f707..0b16d6950dc 100644 --- a/lib/libpthread/arch/powerpc/genassym.cf +++ b/lib/libpthread/arch/powerpc/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.6 2003/09/07 14:47:51 cl Exp $ +# $NetBSD: genassym.cf,v 1.7 2007/03/02 18:53:58 ad Exp $ # Copyright (c) 2001 Wasabi Systems, Inc. # All rights reserved. @@ -61,12 +61,5 @@ define _UC_USER_BIT _UC_USER_BIT #======================================================================== # for pthread_switch.S define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) - define CONTEXTSIZE sizeof(ucontext_t) define STACKSPACE STACKSPACE diff --git a/lib/libpthread/arch/powerpc/pthread_switch.S b/lib/libpthread/arch/powerpc/pthread_switch.S deleted file mode 100644 index 548a4857e50..00000000000 --- a/lib/libpthread/arch/powerpc/pthread_switch.S +++ /dev/null @@ -1,346 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.10 2006/07/08 05:04:49 ross Exp $ */ - -/* - * Copyright (c) 2001 Wasabi Systems, Inc. - * All rights reserved. - * - * Written by Allen Briggs for Wasabi Systems, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project by - * Wasabi Systems, Inc. - * 4. The name of Wasabi Systems, Inc. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <machine/asm.h> -#include "assym.h" - -#define NOTREACHED - -/* - * PowerPC ABI says stack pointer must be 16-byte aligned. - */ -#define RND_CTXSIZE ((CONTEXTSIZE + 15) & 0xfffffff0) - -/* - * Define: - * void pthread__switch(pthread_t self, pthread_t next) - * void pthread__upcall_switch(pthread_t self, pthread_t next) - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock) - */ - - -/* - * Evil STACK_SWITCH() - * See comments in ../i386/pthread_switch.S. - */ -#define STACK_SWITCH(pt,tmp,z) \ - lwz tmp, PT_TRAPUC(pt) ; \ - or. tmp, tmp, tmp ; \ - bne 1f ; \ - lwz tmp, PT_UC(pt) ; \ -1: la %r1, -STACKSPACE(tmp) ; \ - li z, 0 ; \ - stw z, PT_TRAPUC(pt) - -/* - * void - * pthread__switch(pthread_t self (%r3), pthread_t next (%r4)) - * - * Plain switch that doesn't do any special checking or handle spin- - * preemption. It isn't used much by normal code, actually; its main - * purpose is to be a basic switch engine when the MI code is already - * dealing with spin-preemption or other gunk. - * - * What we do here is allocate the ucontext for the 'self' thread on its - * stack, saving the pointer in self's pthread structure, then swapping - * context to 'next', effectively deallocating next's context on the way - * out. - */ -ENTRY(pthread__switch) -#ifdef PIC - mflr %r10 - bl _GLOBAL_OFFSET_TABLE_@local-4 - mflr %r9 - mtlr %r10 -#endif - stwu %r1, -(RND_CTXSIZE + 48)(%r1) /* alloc stack space */ - mflr %r0 - stw %r31,(RND_CTXSIZE + 44)(%r1) /* saved %r31 */ -#ifdef PIC - stw %r9, (RND_CTXSIZE + 40)(%r1) -#endif - stw %r4, (RND_CTXSIZE + 32)(%r1) /* next */ - stw %r3, (RND_CTXSIZE + 28)(%r1) /* self */ - stw %r0, (RND_CTXSIZE + 52)(%r1) /* Save return address */ - addi %r31, %r1, 16 /* %r31 = ucontext */ - - /* Get the current context */ - mr %r3, %r31 - bl PIC_PLT(_C_LABEL(_getcontext_u)) - lwz %r3, (RND_CTXSIZE + 28)(%r1) - lwz %r4, (RND_CTXSIZE + 32)(%r1) -#ifdef PIC - lwz %r9, (RND_CTXSIZE + 40)(%r1) -#endif - - /* - * Edit the context to make it continue at switch_return instead of - * here. - */ -#ifdef PIC - lwz %r6, pthread__switch_return_point@got(%r9) -#else - lis %r6, pthread__switch_return_point@ha - addi %r6, %r6, pthread__switch_return_point@l -#endif - stw %r6, (_REG_PC + 16)(%r1) - stw %r31, PT_UC(%r3) - - STACK_SWITCH(%r4, %r7, %r6) - - mr %r3, %r7 - b PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - -ENTRY_NOPROFILE(pthread__switch_return_point) - lwz %r31, (RND_CTXSIZE + 44)(%r1) - addi %r1, %r1, (RND_CTXSIZE + 48) - lwz %r0, 4(%r1) - mtlr %r0 - blr - - - -pthread__switch_away: - STACK_SWITCH(%r4, %r6, %r7) - - or. %r5, %r5, %r5 - beq 1f - lwz %r7, PT_SPINLOCKS(%r3) - addi %r7, %r7, -1 - stw %r7, PT_SPINLOCKS(%r3) - -1: mr %r3, %r6 - b PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - -/* - * void - * pthread__upcall_switch(pthread_t self (%r3), pthread_t next (%r4)) - */ -ENTRY(pthread__upcall_switch) - lwz %r6, PT_SPINLOCKS(%r4) - addi %r6, %r6, 1 - stw %r6, PT_SPINLOCKS(%r4) - - STACK_SWITCH(%r4, %r5, %r6) - - lwz %r7, PT_NEXT(%r3) - or. %r7, %r7, %r7 - beq 1f - - stw %r5, PT_SWITCHTOUC(%r3) - stw %r4, PT_SWITCHTO(%r3) - mr %r3, %r4 - mr %r4, %r7 - li %r5, 1 - b pthread__switch_away - NOTREACHED - -1: mr %r14, %r3 - mr %r15, %r4 - mr %r16, %r5 - bl PIC_PLT(_C_LABEL(pthread__sa_recycle)) - mr %r3, %r14 - mr %r4, %r15 - mr %r5, %r16 - - lwz %r6, PT_SPINLOCKS(%r4) - addi %r6, %r6, -1 - stw %r6, PT_SPINLOCKS(%r4) - - lwz %r7, PT_NEXT(%r4) - or. %r7, %r7, %r7 - beq 2f - - stw %r5, PT_SWITCHTOUC(%r4) - stw %r4, PT_SWITCHTO(%r4) - mr %r3, %r4 - mr %r4, %r7 - li %r5, 0 - b pthread__switch_away - NOTREACHED - -2: mr %r3, %r16 - b PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - -/* - * void - * pthread__locked_switch(pthread_t self (%r3), pthread_t next (%r4), - * pt_spin_t *lock (%r5)) - * - * Stack is: - * high addr -- return addr ( 4 bytes) - * %r1@call caller saved %r1 ( 4 bytes) - * any padding to make %r1 a multiple of 16 ... * - * saved %r31 ( 4 bytes) * - * saved %r9 ( 4 bytes) * - * saved %r5 ( 4 bytes) * - * saved %r4 ( 4 bytes) * - * saved %r3 ( 4 bytes) * - * context (RND_CTXSIZE bytes) * - * padding to 16 bytes ( 20 bytes) * - * space for callee ra ( 4 bytes) * - * low addr p__l_s saved %r1 ( 4 bytes) * - * - * STACKSPACE is the space between the bottom of the stack and - * the ucontext on the stack. i.e., 8, but we want to keep the stack - * rounded to a multiple of 16, so it's really 16. - */ - - .type locked_return,@function - -ENTRY(pthread__locked_switch) -#ifdef PIC - mflr %r10 - bl _GLOBAL_OFFSET_TABLE_@local-4 - mflr %r9 - mtlr %r10 -#endif - stwu %r1, -(RND_CTXSIZE + 48)(%r1) /* alloc stack space */ - mflr %r0 - stw %r31,(RND_CTXSIZE + 44)(%r1) /* saved %r31 */ -#ifdef PIC - stw %r9, (RND_CTXSIZE + 40)(%r1) -#endif - stw %r5, (RND_CTXSIZE + 36)(%r1) /* lock */ - stw %r4, (RND_CTXSIZE + 32)(%r1) /* next */ - stw %r3, (RND_CTXSIZE + 28)(%r1) /* self */ - stw %r0, (RND_CTXSIZE + 52)(%r1) /* Save return address */ - addi %r31, %r1, 16 /* %r31 = ucontext */ - - /* increment spinlock to make sure that next gets continued */ - lwz %r6, PT_SPINLOCKS(%r4) - addi %r6, %r6, 1 - stw %r6, PT_SPINLOCKS(%r4) - - /* Get the current context */ - mr %r3, %r31 - bl PIC_PLT(_C_LABEL(_getcontext_u)) - lwz %r3, (RND_CTXSIZE + 28)(%r1) - lwz %r4, (RND_CTXSIZE + 32)(%r1) - lwz %r5, (RND_CTXSIZE + 36)(%r1) -#ifdef PIC - lwz %r9, (RND_CTXSIZE + 40)(%r1) -#endif - - /* - * Edit the context to make it continue at locked_return instead of - * here. - */ -#ifdef PIC - lwz %r6, locked_return@got(%r9) -#else - lis %r6, locked_return@ha - addi %r6, %r6, locked_return@l -#endif - stw %r6, (_REG_PC + 16)(%r1) - stw %r31, PT_UC(%r3) - - STACK_SWITCH(%r4, %r7, %r6) - - /* Check if the switcher was preempted and continued to here. */ - lwz %r8, PT_NEXT(%r3) - or. %r8, %r8, %r8 - beq 1f - - /* - * Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, and switch to the - * next thread in the continuation chain. Mark the fact that - * this was a locked switch, and so the thread does not need to - * be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and preemption. - */ - stw %r5, PT_HELDLOCK(%r3) - stw %r7, PT_SWITCHTOUC(%r3) - stw %r4, PT_SWITCHTO(%r3) - lwz %r6, PT_SPINLOCKS(%r3) - addi %r6, %r6, -1 - stw %r6, PT_SPINLOCKS(%r3) - - mr %r3, %r4 - mr %r4, %r8 - li %r5, 1 - b pthread__switch_away - NOTREACHED - - /* No locked old-preemption */ -1: /* - * We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - /* Reduce the lock count... */ - lwz %r6, PT_SPINLOCKS(%r3) - addi %r6, %r6, -1 - stw %r6, PT_SPINLOCKS(%r3) - /* ... actually release the lock ... */ - sync - xor %r9,%r9,%r9 - stw %r9, 0(%r5) - /* ... and remove the fake lock */ - lwz %r6, PT_SPINLOCKS(%r4) - addi %r6, %r6, -1 - stw %r6, PT_SPINLOCKS(%r4) - - /* Check to see if we were preempted while holding the fake lock */ - lwz %r8, PT_NEXT(%r4) - or. %r8, %r8, %r8 - beq 2f - - /* Yes, we were. Go to the next element in the chain. */ - stw %r7, PT_SWITCHTOUC(%r4) - stw %r4, PT_SWITCHTO(%r4) - mr %r3, %r4 - mr %r4, %r8 - li %r5, 0 - b pthread__switch_away - NOTREACHED - -2: mr %r3, %r7 - b PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - -locked_return: - lwz %r31, (RND_CTXSIZE + 44)(%r1) - addi %r1, %r1, (RND_CTXSIZE + 48) - lwz %r0, 4(%r1) - mtlr %r0 - blr diff --git a/lib/libpthread/arch/powerpc64/genassym.cf b/lib/libpthread/arch/powerpc64/genassym.cf index 827552bad4b..86df70b525b 100644 --- a/lib/libpthread/arch/powerpc64/genassym.cf +++ b/lib/libpthread/arch/powerpc64/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.1 2006/07/08 05:09:44 ross Exp $ +# $NetBSD: genassym.cf,v 1.2 2007/03/02 18:53:58 ad Exp $ # Copyright (c) 2001 Wasabi Systems, Inc. # All rights reserved. @@ -58,15 +58,5 @@ define _UC_CPU _UC_CPU define _UC_FPU _UC_FPU define _UC_USER_BIT _UC_USER_BIT -#======================================================================== -# for pthread_switch.S -define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) - define CONTEXTSIZE sizeof(ucontext_t) define STACKSPACE STACKSPACE diff --git a/lib/libpthread/arch/powerpc64/pthread_switch.S b/lib/libpthread/arch/powerpc64/pthread_switch.S deleted file mode 100644 index 876a7e8ac56..00000000000 --- a/lib/libpthread/arch/powerpc64/pthread_switch.S +++ /dev/null @@ -1,308 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.2 2006/07/09 01:07:38 ross Exp $ */ - -/* - * Copyright (c) 2001 Wasabi Systems, Inc. - * All rights reserved. - * - * Written by Allen Briggs for Wasabi Systems, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project by - * Wasabi Systems, Inc. - * 4. The name of Wasabi Systems, Inc. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <machine/asm.h> -#include "assym.h" - -#define NOTREACHED - -/* - * PowerPC ABI says stack pointer must be 16-byte aligned. - */ -#define RND_CTXSIZE ((CONTEXTSIZE + 15) & 0xfffffff0) - -/* - * Define: - * void pthread__switch(pthread_t self, pthread_t next) - * void pthread__upcall_switch(pthread_t self, pthread_t next) - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock) - */ - - -/* - * Evil STACK_SWITCH() - * See comments in ../i386/pthread_switch.S. - */ -#define STACK_SWITCH(pt,tmp,z) \ - ld tmp, PT_TRAPUC(pt) ; \ - or. tmp, tmp, tmp ; \ - bne 1f ; \ - ld tmp, PT_UC(pt) ; \ -1: la %r1, -STACKSPACE(tmp) ; \ - li z, 0 ; \ - std z, PT_TRAPUC(pt) - -/* - * void - * pthread__switch(pthread_t self (%r3), pthread_t next (%r4)) - * - * Plain switch that doesn't do any special checking or handle spin- - * preemption. It isn't used much by normal code, actually; its main - * purpose is to be a basic switch engine when the MI code is already - * dealing with spin-preemption or other gunk. - * - * What we do here is allocate the ucontext for the 'self' thread on its - * stack, saving the pointer in self's pthread structure, then swapping - * context to 'next', effectively deallocating next's context on the way - * out. - * - * Stack: - * ------------------------------------------------------------------ - * highest addresses - * saved r31 8 (offset is framesize - 8) - * pad 8 pad r31 space up to 16 - * pad to round ucontext_t up to a 16 byte boundary - * ucontext_t (offset is SF_SZ ) - * other elf stack frame (SF_PARAM_SZ ) - * elf stack frame header (SF_HEADER_SZ ) - * lowest addresses - * ------------------------------------------------------------------ - */ -ENTRY(pthread__switch) - frameSize = SF_SZ + RND_CTXSIZE + 16 # need +8 for r31, & align - saved31 = frameSize - 8 -.macro init_frame - stdu %r1, -frameSize(%r1) /* alloc stack space */ - mflr %r0 - std %r31,saved31(%r1) - std %r3, SF_PARAM+0(%r1) /* self */ - std %r4, SF_PARAM+8(%r1) /* next */ - std %r5, SF_PARAM+16(%r1) /* lock, for locked_switch */ - std %r0, frameSize+SF_LR(%r1) /* Save return address */ - la %r31, SF_SZ(%r1) /* %r31 = ucontext */ -.endm - init_frame - -.macro switch_context - /* Get the current context */ - mr %r3, %r31 - CALL(_getcontext_u) - ld %r3, SF_PARAM+0(%r1) - ld %r4, SF_PARAM+8(%r1) - ld %r5, SF_PARAM+16(%r1) - /* - * Edit the context to make it continue at switch_return instead of - * here. - */ - ld %r6, pthread__switch_return_point@got(%r2) - std %r6, SF_SZ+_REG_PC(%r1) - std %r31, PT_UC(%r3) - - STACK_SWITCH(%r4, %r7, %r6) -.endm - switch_context - -.macro set_context - mr %r3, %r7 - b ._setcontext_u -.endm - set_context - NOTREACHED - - - -pthread__switch_away: - STACK_SWITCH(%r4, %r6, %r7) - - or. %r5, %r5, %r5 - beq 1f - lwz %r7, PT_SPINLOCKS(%r3) # w OK - addi %r7, %r7, -1 - stw %r7, PT_SPINLOCKS(%r3) # w OK - -1: mr %r3, %r6 - b ._setcontext_u - NOTREACHED - -/* - * void - * pthread__upcall_switch(pthread_t self (%r3), pthread_t next (%r4)) - */ -ENTRY(pthread__upcall_switch) - lwz %r6, PT_SPINLOCKS(%r4) # w OK - addi %r6, %r6, 1 - stw %r6, PT_SPINLOCKS(%r4) # w OK - - STACK_SWITCH(%r4, %r5, %r6) - - ld %r7, PT_NEXT(%r3) - or. %r7, %r7, %r7 - beq 1f - - std %r5, PT_SWITCHTOUC(%r3) - std %r4, PT_SWITCHTO(%r3) - mr %r3, %r4 - mr %r4, %r7 - li %r5, 1 - b pthread__switch_away - NOTREACHED - -1: mr %r14, %r3 - mr %r15, %r4 - mr %r16, %r5 - CALL(pthread__sa_recycle) - mr %r3, %r14 - mr %r4, %r15 - mr %r5, %r16 - - lwz %r6, PT_SPINLOCKS(%r4) # w OK - addi %r6, %r6, -1 - stw %r6, PT_SPINLOCKS(%r4) # w OK - - ld %r7, PT_NEXT(%r4) - or. %r7, %r7, %r7 - beq 2f - - std %r5, PT_SWITCHTOUC(%r4) - std %r4, PT_SWITCHTO(%r4) - mr %r3, %r4 - mr %r4, %r7 - li %r5, 0 - b pthread__switch_away - NOTREACHED - -2: mr %r3, %r16 - b ._setcontext_u - NOTREACHED - -/* - * void - * pthread__locked_switch(pthread_t self (%r3), pthread_t next (%r4), - * pt_spin_t *lock (%r5)) - * - * THIS STACK FRAME APPLIES ONLY TO THE ORIGINAL ILP32 CODE - * - * Stack is: - * high addr -- return addr ( 4 bytes) - * %r1@call caller saved %r1 ( 4 bytes) - * any padding to make %r1 a multiple of 16 ... * - * saved %r31 ( 4 bytes) * - * saved %r9 ( 4 bytes) * - * saved %r5 ( 4 bytes) * - * saved %r4 ( 4 bytes) * - * saved %r3 ( 4 bytes) * - * context (RND_CTXSIZE bytes) * - * padding to 16 bytes ( 20 bytes) * - * space for callee ra ( 4 bytes) * - * low addr p__l_s saved %r1 ( 4 bytes) * - * - * STACKSPACE is the space between the bottom of the stack and - * the ucontext on the stack. i.e., 8, but we want to keep the stack - * rounded to a multiple of 16, so it's really 16. - */ - -ENTRY(pthread__locked_switch) - - init_frame - - /* increment spinlock to make sure that next gets continued */ - lwz %r6, PT_SPINLOCKS(%r4) # w OK - addi %r6, %r6, 1 - stw %r6, PT_SPINLOCKS(%r4) # w OK - - switch_context - - /* Check if the switcher was preempted and continued to here. */ - ld %r8, PT_NEXT(%r3) - or. %r8, %r8, %r8 - beq 1f - - /* - * Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, and switch to the - * next thread in the continuation chain. Mark the fact that - * this was a locked switch, and so the thread does not need to - * be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and preemption. - */ - std %r5, PT_HELDLOCK(%r3) - std %r7, PT_SWITCHTOUC(%r3) - std %r4, PT_SWITCHTO(%r3) - lwz %r6, PT_SPINLOCKS(%r3) # w OK - addi %r6, %r6, -1 - stw %r6, PT_SPINLOCKS(%r3) # w OK - - mr %r3, %r4 - mr %r4, %r8 - li %r5, 1 - b pthread__switch_away - NOTREACHED - - /* No locked old-preemption */ -1: /* - * We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - /* Reduce the lock count... */ - lwz %r6, PT_SPINLOCKS(%r3) # w OK - addi %r6, %r6, -1 - stw %r6, PT_SPINLOCKS(%r3) # w OK - /* ... actually release the lock ... */ - sync - xor %r9,%r9,%r9 - std %r9, 0(%r5) - /* ... and remove the fake lock */ - lwz %r6, PT_SPINLOCKS(%r4) # w OK - addi %r6, %r6, -1 - stw %r6, PT_SPINLOCKS(%r4) # w OK - - /* Check to see if we were preempted while holding the fake lock */ - ld %r8, PT_NEXT(%r4) - or. %r8, %r8, %r8 - beq 2f - - /* Yes, we were. Go to the next element in the chain. */ - std %r7, PT_SWITCHTOUC(%r4) - std %r4, PT_SWITCHTO(%r4) - mr %r3, %r4 - mr %r4, %r8 - li %r5, 0 - b pthread__switch_away - NOTREACHED - -2: set_context - NOTREACHED - - -ENTRY(pthread__switch_return_point) - ld %r31, saved31(%r1) - ld %r0, frameSize+SF_LR(%r1) - la %r1, frameSize(%r1) - mtlr %r0 - blr diff --git a/lib/libpthread/arch/sh3/genassym.cf b/lib/libpthread/arch/sh3/genassym.cf index 0b08c5f7769..7c49b5b15ce 100644 --- a/lib/libpthread/arch/sh3/genassym.cf +++ b/lib/libpthread/arch/sh3/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.5 2003/11/18 03:07:29 uwe Exp $ +# $NetBSD: genassym.cf,v 1.6 2007/03/02 18:53:59 ad Exp $ # Copyright (c) 2001 The NetBSD Foundation, Inc. # All rights reserved. @@ -40,12 +40,6 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define PT_UC offsetof(struct __pthread_st, pt_uc) define UC_FLAGS offsetof(ucontext_t, uc_flags) diff --git a/lib/libpthread/arch/sh3/pthread_switch.S b/lib/libpthread/arch/sh3/pthread_switch.S deleted file mode 100644 index 4b4d9c5a1d7..00000000000 --- a/lib/libpthread/arch/sh3/pthread_switch.S +++ /dev/null @@ -1,453 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.7 2006/01/06 22:46:14 uwe Exp $ */ - -/*- - * Copyright (c) 2003 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams and Steve C. Woodford. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <machine/asm.h> -#include "assym.h" - - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - - -/* - * Enter debugger or die with SIGTRAP if "notreached" code is reached - */ -#define NOTREACHED trapa #0xc3 - - -/* - * To avoid superfluous memory loads, or consuming extra registers - * this code makes assumptions that certain constants are small - * enough to be used as immediate data in certain instructions or - * addressing formats. It is expected that the layout of pthread - * internal structure is not going to be changed frequently. - */ -#define ASSERT_LONG_DISPLACEMENT_OK(i) .ifgt (i) - 60; .err; .endif -#define ASSERT_IMMEDIATE_7BIT_OK(i) .ifgt (i) - 127; .err; .endif -#define ASSERT_IMMEDIATE_8BIT_OK(i) .ifgt (i) - 255; .err; .endif - -ASSERT_LONG_DISPLACEMENT_OK(UC_PC) -ASSERT_LONG_DISPLACEMENT_OK(PT_SPINLOCKS) - -ASSERT_IMMEDIATE_7BIT_OK(PT_UC) -ASSERT_IMMEDIATE_7BIT_OK(PT_TRAPUC) - - -/* - * Utility macro to switch to the stack of another thread. - * Sets tmp to the thread's ucontext to switch to. - * Clobbers r0 and r1. - * - * *** WARNING *** - * STACK_SWITCH is more subtle than it looks. Please go read the extended - * comment in the i386 pthread_switch.S file. - */ -#define STACK_SWITCH(pt,tmp) \ - mov #PT_TRAPUC, r0 ; \ - mov.l @(r0,pt), tmp /* check pt_trapuc first */ ; \ - mov #0, r1 ; \ - tst tmp, tmp /* pt_trapuc == NULL? */ ; \ - bf/s 100f /* if not, use it */ ; \ - mov.l r1, @(r0,pt) /* clear pt_trapuc */ ; \ - mov #PT_UC, r0 ; \ - mov.l @(r0,pt), tmp /* else, switch to pt_uc */ ; \ -100: \ -.ifeq STACKSPACE ; \ - mov tmp, sp ; \ -.else ; \ - mov tmp, r0 ; \ - add #-STACKSPACE, r0 ; \ - mov r0, sp ; \ -.endif - - - -/* - * void pthread__switch(pthread_t self, pthread_t next); - * - * Plain switch that doesn't do any special checking or handle - * spin-preemption. It isn't used much by normal code, actually; it's - * main purpose is to be a basic switch engine when the MI code is - * already dealing with spin-preemption or other gunk. - */ -NENTRY(pthread__switch) - PIC_PROLOGUE(.L_GOT_1) - sts.l pr, @-sp - mov r4, r7 /* free r4 for function calls */ - - mov.l .L_rnd_ctxsize, r0 - sub r0, sp /* auto ucontext_t cntx; */ - - mov.l .L__getcontext_u_11, r0 -11: CALL r0 /* _getcontext_u(&cntx); */ - mov sp, r4 - - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below: - */ - mova pthread__switch_return_point, r0 - mov.l r0, @(UC_PC, sp) - - mov #PT_UC, r0 - mov.l sp, @(r0, r7) /* self->pt_uc = &cntx; */ - - STACK_SWITCH(r5, r4) /* r4 = next->pt_uc; */ - - mov.l .L__setcontext_u_12, r0 -12: CALL r0 /* _setcontext_u(next->pt_uc); */ - nop /* r4 already set by STACK_SWITCH */ - NOTREACHED - - - .align 2 /* mova target */ -ALTENTRY(pthread__switch_return_point) - /* we're back on the original stack */ - mov.l .L_rnd_ctxsize, r0 - add r0, sp /* ditch the ucontext_t */ - lds.l @sp+, pr - rts - PIC_EPILOGUE_SLOT - - - .align 2 -.L_GOT_1: - PIC_GOT_DATUM -.L__getcontext_u_11: - CALL_DATUM(_C_LABEL(_getcontext_u), 11b) -.L__setcontext_u_12: - CALL_DATUM(_C_LABEL(_setcontext_u), 12b) - - - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - * - * Call with: - * r2 = from, r3 = to - */ -Lpthread__switch_away_decrement: - STACK_SWITCH(r3, r4) /* side effect: r4 = to->pt_uc */ - - /* - * If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there - * may be a fake spinlock-count set. If so, we decrement it - * once we're no longer using the old stack. - */ - mov.l @(PT_SPINLOCKS, r2), r0 - mov.l .L__setcontext_u_21, r1 - add #-1, r0 /* --from->pt_spinlocks; */ -21: CALL r1 /* _setcontext_u(to->pt_uc); */ - mov.l r0, @(PT_SPINLOCKS, r2) - NOTREACHED - - .align 2 -.L__setcontext_u_21: - CALL_DATUM(_C_LABEL(_setcontext_u), 21b) - - - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch(). - * - * Call with: - * r3 = to - */ -Lpthread__switch_away_no_decrement: - STACK_SWITCH(r3, r4) /* side effect: r4 = to->pt_uc */ - - mov.l .L__setcontext_u_31, r1 -31: CALL r1 /* _setcontext_u(to->pt_uc); */ - nop - NOTREACHED - - .align 2 -.L__setcontext_u_31: - CALL_DATUM(_C_LABEL(_setcontext_u), 31b) - - - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, pt_spin_t *lock); - * - * Switch away from a thread that is holding a lock on a queue (to - * prevent being removed from the queue before being switched away). - */ -NENTRY(pthread__locked_switch) - PIC_PROLOGUE(.L_GOT_4) - sts.l pr, @-sp - mov r4, r7 /* free r4 for function calls */ - - mov.l .L_rnd_ctxsize, r0 - sub r0, sp /* auto ucontext_t cntx; */ - - mov.l @(PT_SPINLOCKS, r5), r0 /* make sure we get continued */ - add #1, r0 - mov.l r0, @(PT_SPINLOCKS, r5) /* ++next->pt_spinlocks */ - - mov.l .L__getcontext_u_41, r0 -41: CALL r0 /* _getcontext_u(self->pt_uc); */ - mov sp, r4 - - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below. - */ - mova Lpthread__locked_switch_return_point, r0 - mov.l r0, @(UC_PC, sp) - - mov #PT_UC, r0 - mov.l sp, @(r0, r7) /* self->pt_uc = &cntx; */ - - STACK_SWITCH(r5, r4) /* r4 = next->pt_uc; */ - - /* - * Check if the original thread was preempted while holding - * its queue lock. - */ - mov.l .L_pt_next, r0 - mov.l @(r0, r7), r3 - tst r3, r3 /* self->pt_next == NULL? */ - bt Llocked_no_old_preempt - - /* - * Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, and go to the - * next thread in the chain. Mark the fact that this was a - * locked switch, and so the thread does not need to be put on - * a run queue. Don't release the lock. It's possible that - * if we do so, PT_SWITCHTO will be stomped by another - * switch_lock and preemption. - */ - - mov.l .L_pt_heldlock, r0 - mov.l r6, @(r0, r7) /* self->pt_heldlock = lock; */ - - mov.l .L_pt_switchtouc, r0 - mov.l r4, @(r0, r7) /* self->pt_switchtouc= next->pt_uc; */ - - mov.l .L_pt_switchto, r0 - mov.l r5, @(r0, r7) /* self->pt_switchto = next; */ - - mov.l @(PT_SPINLOCKS, r7), r0 - add #-1, r0 - mov.l r0, @(PT_SPINLOCKS, r7) /* --self->pt_spinlocks */ - - /* - * r2: from = next - * r3: to = self->pt_next (already) - */ - bra Lpthread__switch_away_decrement - mov r5, r2 - NOTREACHED - - -Llocked_no_old_preempt: - /* - * We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - mov.l @(PT_SPINLOCKS, r7), r0 - add #-1, r0 - mov.l r0, @(PT_SPINLOCKS, r7) /* --self->pt_spinlocks */ - - /* We happen to know that this is the right way to release a lock. */ - mov #0, r0 - mov.b r0, @r6 /* *lock = 0; */ - - /* Remove the fake lock. */ - mov.l @(PT_SPINLOCKS, r5), r0 - add #-1, r0 - mov.l r0, @(PT_SPINLOCKS, r5) /* --next->pt_spinlocks */ - - /* Check if we were preempted while holding the fake lock. */ - mov.l .L_pt_next, r0 - mov.l @(r0, r5), r3 - tst r3, r3 /* next->pt_next == NULL? */ - bt Llocked_no_new_preempt - - /* Yes, we were. Bummer. Go to the next element in the chain. */ - mov.l .L_pt_switchtouc, r0 - mov.l r4, @(r0, r5) /* next->pt_switchtouc= next->pt_uc; */ - - mov.l .L_pt_switchto, r0 - mov.l r5, @(r0, r5) /* next->pt_switchto = next; */ - - /* r3: to = next->pt_next (already) */ - bra Lpthread__switch_away_no_decrement - nop - NOTREACHED - - -Llocked_no_new_preempt: - mov.l .L__setcontext_u_42, r0 -42: CALL r0 /* _setcontext_u(next->pt_uc) */ - nop - NOTREACHED - - - .align 2 /* mova target */ -Lpthread__locked_switch_return_point: - /* we're back on the original stack */ - mov.l .L_rnd_ctxsize, r0 - add r0, sp /* ditch the ucontext_t */ - lds.l @sp+, pr - rts - PIC_EPILOGUE_SLOT - - - .align 2 -.L_GOT_4: - PIC_GOT_DATUM -.L__getcontext_u_41: - CALL_DATUM(_C_LABEL(_getcontext_u), 41b) -.L__setcontext_u_42: - CALL_DATUM(_C_LABEL(_setcontext_u), 42b) - - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - * Since this code never returns, we are free to use callee-saved - * registers. - */ -NENTRY(pthread__upcall_switch) - PIC_PROLOGUE_NOSAVE(.L_GOT_5) - mov r4, r8 /* self */ - mov r5, r9 /* next */ - - /* Create a `fake' lock count so we are `continued' */ - mov.l @(PT_SPINLOCKS, r9), r0 - add #1, r0 - mov.l r0, @(PT_SPINLOCKS, r9) /* ++next->pt_spinlocks */ - - STACK_SWITCH(r9, r11) /* r11 = next->pt_uc; */ - - /* Check if the upcall was preempted and continued. */ - mov.l .L_pt_next, r0 - mov.l @(r0, r8), r3 - tst r3, r3 /* self->pt_next == NULL? */ - bt Lupcall_no_old_preempt - - /* - * Yes, it was. Stash the thread we were going to switch to, - * and go to the next thread in the chain. - */ - mov.l .L_pt_switchtouc, r0 - mov.l r11, @(r0, r8) /* self->pt_switchtouc= next->pt_uc; */ - - mov.l .L_pt_switchto, r0 - mov.l r9, @(r0, r8) /* self->pt_switchto = next; */ - - /* - * r2: from = next - * r3: to = self->pt_next (already) - */ - bra Lpthread__switch_away_decrement - mov r9, r2 - NOTREACHED - - -Lupcall_no_old_preempt: - /* pthread__sa_recycle(old, new) */ - mov.l .L_pthread__sa_recycle_51, r0 - mov r8, r4 /* old = self */ -51: CALL r0 - mov r9, r5 /* new = next */ - - /* Release the fake lock */ - mov.l @(PT_SPINLOCKS, r9), r0 - add #-1, r0 - mov.l r0, @(PT_SPINLOCKS, r9) /* --next->pt_spinlocks */ - - /* Check if we were preempted while holding the fake lock. */ - mov.l .L_pt_next, r0 - mov.l @(r0, r9), r3 - tst r3, r3 /* next->pt_next == NULL? */ - bt Lupcall_no_new_preempt - - /* Yes, we were. Bummer. Go to the next element in the chain. */ - mov.l .L_pt_switchtouc, r0 - mov.l r11, @(r0, r9) /* next->pt_switchtouc= next->pt_uc; */ - - mov.l .L_pt_switchto, r0 - mov.l r9, @(r0, r9) /* next->pt_switchto = next; */ - - /* r3: to = next->pt_next (already) */ - bra Lpthread__switch_away_no_decrement - nop - NOTREACHED - - -Lupcall_no_new_preempt: - mov.l .L__setcontext_u_52, r0 -52: CALL r0 /* _setcontext_u(next->pt_uc); */ - mov r11, r4 - NOTREACHED - - .align 2 -.L_GOT_5: - PIC_GOT_DATUM -.L_pthread__sa_recycle_51: - CALL_DATUM(_C_LABEL(pthread__sa_recycle), 51b) -.L__setcontext_u_52: - CALL_DATUM(_C_LABEL(_setcontext_u), 52b) - - -/* - * Data shared by all the functions in this file - */ - .align 2 -.L_rnd_ctxsize: .long RND_CTXSIZE - -.L_pt_heldlock: .long PT_HELDLOCK -.L_pt_next: .long PT_NEXT -.L_pt_switchto: .long PT_SWITCHTO -.L_pt_switchtouc: .long PT_SWITCHTOUC diff --git a/lib/libpthread/arch/sh5/genassym.cf b/lib/libpthread/arch/sh5/genassym.cf index d7b5b1e5ab1..a78edf88d63 100644 --- a/lib/libpthread/arch/sh5/genassym.cf +++ b/lib/libpthread/arch/sh5/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.6 2003/09/07 14:47:53 cl Exp $ +# $NetBSD: genassym.cf,v 1.7 2007/03/02 18:53:59 ad Exp $ # Copyright (c) 2001 The NetBSD Foundation, Inc. # All rights reserved. @@ -43,13 +43,7 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_REGS_PC offsetof(ucontext_t, uc_mcontext.__gregs[_REG_PC]) diff --git a/lib/libpthread/arch/sh5/pthread_switch.S b/lib/libpthread/arch/sh5/pthread_switch.S deleted file mode 100644 index ac3b00a6695..00000000000 --- a/lib/libpthread/arch/sh5/pthread_switch.S +++ /dev/null @@ -1,303 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.8 2003/09/07 14:47:53 cl Exp $ */ - -/*- - * Copyright (c) 2001, 2003 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams and Steve C. Woodford. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <machine/asm.h> -#include "assym.h" - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -/* - * Utility macro to switch to the stack of another thread. - */ -#define STACK_SWITCH(pt,tmp,tmp2) \ - LDPTR pt, PT_TRAPUC, tmp ;\ - LDPTR pt, PT_UC, tmp2 ;\ - cmveq tmp, tmp2, tmp ;\ - addi tmp, -STACKSPACE, r15 ;\ - STPTR pt, PT_TRAPUC, r63 - - -/* - * void pthread__switch(pthread_t self, pthread_t next); - * - * Plain switch that doesn't do any special checking or handle - * spin-preemption. It isn't used much by normal code, actually; it's - * main purpose is to be a basic switch engine when the MI code is - * already dealing with spin-preemption or other gunk. - */ -ENTRY(pthread__switch) - PIC_PROLOGUE - movi RND_CTXSIZE+24, r0 - sub r15, r0, r15 - st.q r15, RND_CTXSIZE, r28 - st.q r15, RND_CTXSIZE+8, r29 - st.q r15, RND_CTXSIZE+16, r18 - - /* - * Keep r2-r3 safe for later. - */ - PIC_PTAL(_C_LABEL(_getcontext_u), r0, tr0) - or r2, r63, r28 /* self */ - or r3, r63, r29 /* next */ - - /* Save the current context */ - or r15, r63, r2 - blink tr0, r18 - - /* - * Edit the context so that it continues below, rather than here. - */ - PIC_LEAF(_C_LABEL(pthread__switch_return_point), r0) - or r15, r63 ,r3 - st.q r15, UC_REGS_PC, r0 - - PIC_PTAL(_C_LABEL(_setcontext_u), r0, tr0) - - STPTR r28, PT_UC, r3 /* self->pt_uc = ctx */ - STACK_SWITCH(r29, r2, r0) /* r2 = next->pt_uc */ - - /* - * Restore 'next's context - */ - blink tr0, r63 - /* NOTREACHED */ - -ENTRY_NOPROFILE(pthread__switch_return_point) - /* We're back on the original stack. */ - ld.q r15, RND_CTXSIZE+16, r18 - movi RND_CTXSIZE+24, r0 - ptabs/l r18, tr0 - ld.q r15, RND_CTXSIZE+8, r29 - ld.q r15, RND_CTXSIZE, r28 - add r15, r0, r15 - PIC_EPILOGUE - blink tr0, r63 - - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, pt_spin_t *lock); - * - * Switch away from a thread that is holding a lock on a queue (to - * prevent being removed from the queue before being switched away). - * - * r2 = self, r3 = next, r4 = lock - */ -ENTRY(pthread__locked_switch) - PIC_PROLOGUE - movi RND_CTXSIZE+32, r0 - sub r15, r0, r15 - st.q r15, RND_CTXSIZE, r28 - st.q r15, RND_CTXSIZE+8, r29 - st.q r15, RND_CTXSIZE+16, r30 - st.q r15, RND_CTXSIZE+24, r18 - - /* Make sure we get continued */ - ld.l r3, PT_SPINLOCKS, r0 - addi r0, 1, r0 - st.l r3, PT_SPINLOCKS, r0 - - /* - * Keep r2-r4, and r15 safe for later. - */ - PIC_PTAL(_C_LABEL(_getcontext_u), r0, tr0) - or r2, r63, r28 /* self */ - or r3, r63, r29 /* next */ - or r4, r63, r30 /* lock */ - STPTR r2, PT_UC, r15 /* self->pt_uc = ctx */ - - /* Save the current context */ - or r15, r63, r2 - blink tr0, r18 - - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below. - */ - pta/u Llocked_return_point, tr0 - gettr tr0, r0 - st.q r15, UC_REGS_PC, r0 - or r15, r63 ,r3 - - pta/l Llocked_no_old_preempt, tr0 - STACK_SWITCH(r29, r2, r0) /* r2 = next->pt_uc */ - - /* Now running on `next's stack. */ - - /* Check if the original thread was preempted while holding - * its queue lock. - */ - LDPTR r28, PT_NEXT, r1 /* self->pt_next == NULL? */ - beq/l r1, r63, tr0 /* Jump if not preempted */ - - /* Yes, it was. Stash the thread we were going to - * switch to, the lock the original thread was holding, - * and go to the next thread in the chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - STPTR r28, PT_HELDLOCK, r30 /* self->pt_heldlock = lock */ - STPTR r28, PT_SWITCHTOUC, r2 /* self->pt_switchtouc = uc */ - STPTR r28, PT_SWITCHTO, r29 /* self->pt_switchto = next */ - ld.l r28, PT_SPINLOCKS, r0 - addi r0, -1, r0 - st.l r28, PT_SPINLOCKS, r0 - - PIC_PTAL(_C_LABEL(_setcontext_u), r0, tr0) - STACK_SWITCH(r1, r2, r0) - - /* If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there - * may be a fake spinlock-count set. If so, we decrement it - * once we're no longer using the old stack. - */ - ld.l r29, PT_SPINLOCKS, r0 - addi r0, -1, r0 - st.l r29, PT_SPINLOCKS, r0 - blink tr0, r63 - /* NOTREACHED */ - -Llocked_no_old_preempt: - /* r30 = lock, r29 = next, r28 = self, r2 = next->pt_uc */ - - /* We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - ld.l r28, PT_SPINLOCKS, r0 /* self->pt_spinlocks-- */ - addi r0, -1, r0 - st.l r28, PT_SPINLOCKS, r0 - - /* We happen to know that this is the right way to release a lock. */ - st.q r30, 0, r63 /* *lock = 0 */ - PIC_PTAL(_C_LABEL(_setcontext_u), r0, tr0) - - /* Remove the fake lock */ - ld.l r29, PT_SPINLOCKS, r0 /* next->pt_spinlocks-- */ - addi r0, -1, r0 - st.l r29, PT_SPINLOCKS, r0 - - /* Check if we were preempted while holding the fake lock. */ - LDPTR r29, PT_NEXT, r1 /* next->pt_next == NULL? */ - beq/l r1, r63, tr0 /* _setcontext() if not preempted */ - - /* Yes, we were. Bummer. Go to the next element in the chain. */ - STPTR r29, PT_SWITCHTOUC, r2 - STPTR r29, PT_SWITCHTO, r29 /* next->pt_switchto = next */ - STACK_SWITCH(r1, r2, r0) - blink tr0, r63 - /* NOTREACHED */ - -Llocked_return_point: - /* We're back on the original stack. */ - ld.q r15, RND_CTXSIZE+24, r18 - movi RND_CTXSIZE+32, r0 - ld.q r15, RND_CTXSIZE+16, r30 - ptabs/l r18, tr0 - ld.q r15, RND_CTXSIZE+8, r29 - ld.q r15, RND_CTXSIZE, r28 - add r15, r0, r15 - PIC_EPILOGUE - blink tr0, r63 - - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - * Since this code never returns, we are free to use callee-saved - * registers. - */ -ENTRY(pthread__upcall_switch) - PIC_GET_GOT(tr0) - /* Create a `fake' lock count so we are `continued' */ - ld.l r3, PT_SPINLOCKS, r0 - pta/l Lupcall_no_old_preempt, tr0 - addi r0, 1, r0 - st.l r3, PT_SPINLOCKS, r0 - - STACK_SWITCH(r3, r28, r0) /* r28 = next->pt_uc */ - - /* Check if the upcall was preempted and continued. */ - PIC_PTAL(_C_LABEL(pthread__sa_recycle), r0, tr1) - LDPTR r2, PT_NEXT, r1 - beq/l r1, r63, tr0 - - /* Yes, it was. Stash the thread we were going to - * switch to, and go to the next thread in the chain. - */ - STPTR r2, PT_SWITCHTOUC, r28 - STPTR r2, PT_SWITCHTO, r3 - PIC_PTAL(_C_LABEL(_setcontext_u), r0, tr0) - STACK_SWITCH(r1, r2, r0) - ld.l r3, PT_SPINLOCKS, r0 - addi r0, -1, r0 - st.l r3, PT_SPINLOCKS, r0 - blink tr0, r63 - -Lupcall_no_old_preempt: - or r3, r63, r29 - /* pthread__sa_recycle(old, new) */ - blink tr1, r18 - - /* Release the fake lock */ - ld.l r29, PT_SPINLOCKS, r0 - PIC_PTAL(_C_LABEL(_setcontext_u), r1, tr0) - addi r0, -1, r0 - st.l r29, PT_SPINLOCKS, r0 - - /* Check if we were preempted while holding the fake lock. */ - or r28, r63, r2 - LDPTR r29, PT_NEXT, r1 - beq/l r1, r63, tr0 - - /* Yes, we were. Bummer. Go to the next element in the chain. */ - STPTR r29, PT_SWITCHTOUC, r2 - STPTR r29, PT_SWITCHTO, r29 - STACK_SWITCH(r1, r2, r0) - blink tr0, r63 diff --git a/lib/libpthread/arch/sparc/genassym.cf b/lib/libpthread/arch/sparc/genassym.cf index c82f64656ab..74ba683cf71 100644 --- a/lib/libpthread/arch/sparc/genassym.cf +++ b/lib/libpthread/arch/sparc/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.7 2003/09/07 14:47:53 cl Exp $ +# $NetBSD: genassym.cf,v 1.8 2007/03/02 18:54:00 ad Exp $ include <ucontext.h> @@ -11,13 +11,7 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define CONTEXTSIZE sizeof(ucontext_t) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_GREGS offsetof(ucontext_t, uc_mcontext.__gregs) diff --git a/lib/libpthread/arch/sparc/pthread_switch.S b/lib/libpthread/arch/sparc/pthread_switch.S deleted file mode 100644 index 8ce4c8dd175..00000000000 --- a/lib/libpthread/arch/sparc/pthread_switch.S +++ /dev/null @@ -1,310 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.8 2006/01/04 12:43:43 skrll Exp $ */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -#include <machine/asm.h> -#include <machine/trap.h> -#include "assym.h" - -#define STACK_ALIGN(x) (((x) + 0x7) & ~0x7) - -#define NOTREACHED t T_DIV0 - - -/* *** WARNING *** - * STACK_SWITCH is more subtle than it looks. Please go read the extended - * comment in the i386 pthread_switch.S file. - */ - -/* - * pt - register which contains *pthread, which stack will be used - * tmp - temporary register which will have *ucontext_t for that pthread - */ -#define STACK_SWITCH(pt, tmp) \ - ld [pt + PT_TRAPUC], tmp ; \ - tst tmp ; \ - bnz 1f ; \ - clr [pt + PT_TRAPUC] ; \ - ld [pt + PT_UC], tmp ; \ -1: add tmp, -STACK_ALIGN(STACKSPACE + CONTEXTSIZE), %sp ; \ - - -/* - * void pthread__switch(pthread_t self, pthread_t next); - * - * Plain switch that doesn't do any special checking or handle - * spin-preemption. It isn't used much by normal code, actually; it's - * main purpose is to be a basic switch engine when the MI code is - * already dealing with spin-preemption or other gunk. - */ -ENTRY(pthread__switch) - save %sp, -STACK_ALIGN(CCFSZ + CONTEXTSIZE), %sp - - /* Get the current context */ - add %fp, -CONTEXTSIZE, %l3 - call _C_LABEL(_getcontext_u) - mov %l3, %o0 - - /* Edit the context to make it continue below, rather than here */ -#ifdef PIC - PICCY_SET(pthread__switch_return_point, %l1, %l5) -#else - set pthread__switch_return_point, %l1 -#endif - st %l1, [%l3 + UC_GREGS + _REG_PC * 4] - st %l3, [%i0 + PT_UC] - - STACK_SWITCH(%i1, %l2) - - /* %l2 points to next thread's ucontext */ - call _C_LABEL(_setcontext_u) - mov %l2, %o0 - NOTREACHED - -ENTRY_NOPROFILE(pthread__switch_return_point) - ret - restore - - - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - */ - -/* - * pthread__switch_away - * %i0 who's lock to release - * %i1 thread to switch to - * %i2 flag to clear lock - */ - -pthread__switch_away: - - STACK_SWITCH(%i1, %l2) - - /* If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there may - * be a fake spinlock-count set. If so, they will set i2 to - * let us know, and we decrement it now that we're no longer - * using the old stack. - */ - tst %i2 - bz 1f - nop - ld [%i0 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i0 + PT_SPINLOCKS] - -1: call _C_LABEL(_setcontext_u) - mov %l2, %o0 - NOTREACHED - - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - */ -ENTRY(pthread__upcall_switch) - save %sp, -CCFSZ, %sp - - /* Create a "fake" lock count so that this code will be continued */ - ld [%i1 + PT_SPINLOCKS], %l0 - inc %l0 - st %l0, [%i1 + PT_SPINLOCKS] - - /* - * switch to next thread stack so we could recycle self's one - */ - STACK_SWITCH(%i1, %l2) - - /* Check if the upcall code was preempted and continued to here. */ - ld [%i0 + PT_NEXT], %l0 - tst %l0 - bz 1f - nop - - /* Yes, it was. Stash the thread we were going to switch to, - * and switch to the next thread in the continuation chain. - */ - st %l2, [%i0 + PT_SWITCHTOUC] - st %i1, [%i0 + PT_SWITCHTO] - mov %i1, %i0 - mov %l0, %i1 - ba pthread__switch_away - mov 1, %i2 - - /* No old-upcall-preemption */ -1: mov %i0, %o0 - call _C_LABEL(pthread__sa_recycle) - mov %i1, %o1 - - /* We can now release the fake lock. */ - ld [%i1 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i1 + PT_SPINLOCKS] - - /* Check if we were preempted and continued while faking the lock. */ - ld [%i1 + PT_NEXT], %l0 - tst %l0 - bz 2f - nop - - /* Yes, we were. Stash the to-be-switched-to context in our thread - * structure and go to the next link in the chain. - */ - st %l2, [%i1 + PT_SWITCHTOUC] - st %i1, [%i1 + PT_SWITCHTO] - mov %i1, %i0 - mov %l0, %i1 - ba pthread__switch_away - mov 0, %i2 - - /* No new-upcall-preemption */ -2: call _C_LABEL(_setcontext_u) - mov %l2, %o0 - NOTREACHED - - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * Switch away from a thread that is holding a lock on a queue (to - * prevent being removed from the queue before being switched away). - */ -ENTRY(pthread__locked_switch) - save %sp, -STACK_ALIGN(CCFSZ + CONTEXTSIZE), %sp - - /* Make sure we get continuted */ - ld [%i1 + PT_SPINLOCKS], %l0 - inc %l0 - st %l0, [%i1 + PT_SPINLOCKS] - - /* Get the current context */ - add %fp, -CONTEXTSIZE, %l3 - call _C_LABEL(_getcontext_u) - mov %l3, %o0 - - /* Edit the context to make it continue below, rather than here */ -#ifdef PIC - PICCY_SET(locked_return_point, %l1, %l5) -#else - set locked_return_point, %l1 -#endif - st %l1, [%l3 + UC_GREGS + _REG_PC * 4] - st %l3, [%i0 + PT_UC] - - STACK_SWITCH(%i1, %l2) - - /* Check if the switcher was preempted and continued to here. */ - ld [%i0 + PT_NEXT], %l4 - tst %l4 - bz 1f - nop - - /* Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, - * and switch to the next thread in the continuation chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - st %i2, [%i0 + PT_HELDLOCK] - st %l2, [%i0 + PT_SWITCHTOUC] - st %i1, [%i0 + PT_SWITCHTO] - ld [%i0 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i0 + PT_SPINLOCKS] - - mov %i1, %i0 - mov %l4, %i1 - ba pthread__switch_away - mov 1, %i2 - - /* No locked old-preemption */ -1: /* We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - /* Reduce the lock count... */ - ld [%i0 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i0 + PT_SPINLOCKS] - - /* ... actually release the lock.. */ -! membar #Sync - - clr [%i2] - /* .. and remove the fake lock */ - ld [%i1 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i1 + PT_SPINLOCKS] - - /* Check if we were preempted while holding the fake lock. */ - ld [%i1 + PT_NEXT], %l0 - tst %l0 - bz 2f - nop - - /* Yes, we were. Go to the next element in the chain. */ - st %l2, [%i1 + PT_SWITCHTOUC] - st %i1, [%i1 + PT_SWITCHTO] - mov %i1, %i0 - mov %l0, %i1 - ba pthread__switch_away - mov 0, %i2 - -2: /* %l2 points to next thread's ucontext */ - call _C_LABEL(_setcontext_u) - mov %l2, %o0 - NOTREACHED - -locked_return_point: - ret - restore diff --git a/lib/libpthread/arch/sparc64/genassym.cf b/lib/libpthread/arch/sparc64/genassym.cf index 20647638bbe..90e1d95e3a1 100644 --- a/lib/libpthread/arch/sparc64/genassym.cf +++ b/lib/libpthread/arch/sparc64/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.6 2003/09/07 14:47:54 cl Exp $ +# $NetBSD: genassym.cf,v 1.7 2007/03/02 18:54:00 ad Exp $ # # Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -43,13 +43,7 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define CONTEXTSIZE sizeof(ucontext_t) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_GREGS offsetof(ucontext_t, uc_mcontext.__gregs) diff --git a/lib/libpthread/arch/sparc64/pthread_switch.S b/lib/libpthread/arch/sparc64/pthread_switch.S deleted file mode 100644 index ac40ef8f90d..00000000000 --- a/lib/libpthread/arch/sparc64/pthread_switch.S +++ /dev/null @@ -1,299 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.9 2006/01/04 12:43:43 skrll Exp $ */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -#include <machine/asm.h> -#include "assym.h" - -#define STACK_ALIGN(x) (((x) + 0xf) & ~0xf) - -#define NOTREACHED illtrap 10 - -/* *** WARNING *** - * STACK_SWITCH is more subtle than it looks. Please go read the extended - * comment in the i386 pthread_switch.S file. - */ - - -/* - * pt register which contains *pthread, which stack will be used - * tmp temporary register which will have *ucontext_t for that pthread - */ -#define STACK_SWITCH(pt,tmp) \ - ldx [pt + PT_TRAPUC], tmp ; \ - brnz tmp, 8f ; \ - stx %g0, [pt + PT_TRAPUC] ; \ - ldx [pt + PT_UC], tmp ; \ -8: add tmp, - STACK_ALIGN(STACKSPACE + CONTEXTSIZE) - BIAS, %sp ; \ - - -ENTRY(pthread__switch) - save %sp, -STACK_ALIGN(CC64FSZ + CONTEXTSIZE), %sp - - /* Get the current context */ - add %fp, BIAS - CONTEXTSIZE, %l3 - call _C_LABEL(_getcontext_u) - mov %l3, %o0 - - /* Edit the context to make it continue below, rather than here */ -#ifdef PIC - PICCY_SET(pthread__switch_return_point,%l1,%l5) -#else - set pthread__switch_return_point, %l1 -#endif - stx %l1, [%l3 + UC_GREGS + _REG_PC * 8] - stx %l3, [%i0 + PT_UC] - - STACK_SWITCH(%i1, %l2) - - /* %l2 points to next thread's ucontext */ - call _C_LABEL(_setcontext_u) - mov %l2, %o0 - NOTREACHED - -ENTRY_NOPROFILE(pthread__switch_return_point) - ret - restore - - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - */ - -/* - * pthread__switch_away - * %i0 who's lock to release - * %i1 thread to switch to - * %i2 flag to clear lock - */ - -pthread__switch_away: - - STACK_SWITCH(%i1,%l2) - - /* If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there may - * be a fake spinlock-count set. If so, they will set i2 to - * let us know, and we decrement it now that we're no longer - * using the old stack. - */ - brz,a %i2, 1f - nop - ld [%i0 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i0 + PT_SPINLOCKS] - -1: call _C_LABEL(_setcontext_u) - mov %l2, %o0 - NOTREACHED - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - */ -ENTRY(pthread__upcall_switch) - save %sp, -CC64FSZ, %sp - - /* Create a "fake" lock count so that this code will be continued */ - ld [%i1 + PT_SPINLOCKS], %l0 - inc %l0 - st %l0, [%i1 + PT_SPINLOCKS] - - /* - * switch to next thread stack so we could recycle self's one - */ - STACK_SWITCH(%i1,%l2) - - /* Check if the upcall code was preempted and continued to here. */ - ldx [%i0 + PT_NEXT], %l0 - brz,a %l0, 1f - nop - - /* Yes, it was. Stash the thread we were going to switch to, - * and switch to the next thread in the continuation chain. - */ - stx %l2, [%i0 + PT_SWITCHTOUC] - stx %i1, [%i0 + PT_SWITCHTO] - mov %i1, %i0 - mov %l0, %i1 - ba pthread__switch_away - mov 1, %i2 - NOTREACHED - - /* No old-upcall-preemption */ -1: mov %i0, %o0 - call _C_LABEL(pthread__sa_recycle) - mov %i1, %o1 - - /* We can now release the fake lock. */ - ld [%i1 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i1 + PT_SPINLOCKS] - - /* Check if we were preempted and continued while faking the lock */ - ldx [%i1 + PT_NEXT], %l0 - brz,a %l0, 2f - nop - - /* Yes, we were. Stash the to-be-switched-to context in our thread - * structure and go to the next link in the chain. - */ - stx %l2, [%i1 + PT_SWITCHTOUC] - stx %i1, [%i1 + PT_SWITCHTO] - mov %i1, %i0 - mov %l0, %i1 - ba pthread__switch_away - mov 0, %i2 - - /* No new-upcall-preemption */ -2: - call _C_LABEL(_setcontext_u) - mov %l2, %o0 - NOTREACHED - - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * Switch away from a thread that is holding a lock on a queue (to - * prevent being removed from the queue before being switched away). - */ -ENTRY(pthread__locked_switch) - save %sp, -STACK_ALIGN(CC64FSZ + CONTEXTSIZE), %sp - - /* Make sure we get continuted */ - ld [%i1 + PT_SPINLOCKS], %l0 - inc %l0 - st %l0, [%i1 + PT_SPINLOCKS] - - /* Get the current context */ - add %fp, BIAS - CONTEXTSIZE, %l3 - call _C_LABEL(_getcontext_u) - mov %l3, %o0 - - /* Edit the context to make it continue below, rather than here */ -#ifdef PIC - PICCY_SET(locked_return_point,%l1,%l5) -#else - set locked_return_point, %l1 -#endif - stx %l1, [%l3 + UC_GREGS + _REG_PC * 8] - stx %l3, [%i0 + PT_UC] - - STACK_SWITCH(%i1, %l2) - - /* Check if the switcher was preempted and continued to here. */ - ldx [%i0 + PT_NEXT], %l4 - brz,a %l4, 1f - nop - - /* Yes, it was. Stash the thread we were going to switch to, - * the lock the original thread was holding, - * and switch to the next thread in the continuation chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - stx %i2, [%i0 + PT_HELDLOCK] - stx %l2, [%i0 + PT_SWITCHTOUC] - stx %i1, [%i0 + PT_SWITCHTO] - ld [%i0 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i0 + PT_SPINLOCKS] - - mov %i1, %i0 - mov %l4, %i1 - ba pthread__switch_away - mov 1, %i2 - NOTREACHED - - /* No locked old-preemption */ -1: /* We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - /* Reduce the lock count... */ - ld [%i0 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i0 + PT_SPINLOCKS] - - /* ... actually release the lock.. */ -! membar #Sync - - st %g0, [%i2] - /* .. and remove the fake lock */ - ld [%i1 + PT_SPINLOCKS], %l0 - dec %l0 - st %l0, [%i1 + PT_SPINLOCKS] - - /* Check if we were preempted while holding the fake lock. */ - ldx [%i1 + PT_NEXT], %l0 - brz,a %l0, 2f - nop - - /* Yes, we were. Go to the next element in the chain. */ - stx %l2, [%i1 + PT_SWITCHTOUC] - stx %i1, [%i1 + PT_SWITCHTO] - mov %i1, %i0 - mov %l0, %i1 - ba pthread__switch_away - mov %g0, %i2 - NOTREACHED - -2: /* %l2 points to next thread's ucontext */ - call _C_LABEL(_setcontext_u) - mov %l2, %o0 - NOTREACHED - -locked_return_point: - ret - restore - - diff --git a/lib/libpthread/arch/vax/genassym.cf b/lib/libpthread/arch/vax/genassym.cf index 726ce72ca6b..b97e88635c8 100644 --- a/lib/libpthread/arch/vax/genassym.cf +++ b/lib/libpthread/arch/vax/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.6 2005/04/09 20:50:27 matt Exp $ +# $NetBSD: genassym.cf,v 1.7 2007/03/02 18:54:01 ad Exp $ # # Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -43,13 +43,7 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define CONTEXTSIZE sizeof(ucontext_t) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_GREGS offsetof(ucontext_t, uc_mcontext.__gregs) diff --git a/lib/libpthread/arch/vax/pthread_switch.S b/lib/libpthread/arch/vax/pthread_switch.S deleted file mode 100644 index b9497924764..00000000000 --- a/lib/libpthread/arch/vax/pthread_switch.S +++ /dev/null @@ -1,251 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.6 2005/04/09 20:53:19 matt Exp $ */ - -/*- - * Copyright (c) 2001, 2003 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams and Matt Thomas. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -#include <machine/asm.h> -#include "assym.h" - -/* Force an error when "notreached" code is reached. */ -#define NOTREACHED \ - halt; \ - /* NOTREACHED */ - -/* *** WARNING *** - * STACK_SWITCH is more subtle than it looks. Please go read the extended - * comment in the i386 pthread_switch.S file. - */ - -#define STACK_SWITCH(pt) \ - movl PT_TRAPUC(pt),%sp; \ - bneq 1f; \ - movl PT_UC(pt),%sp; \ -1: subl2 $STACKSPACE,%sp; \ - clrl PT_TRAPUC(pt) - -/* - * void pthread__switch(pthread_t self, pthread_t next); - */ -ENTRY(pthread__switch, 0) - subl2 $CONTEXTSIZE, %sp - - /* Get the current context */ - pushl %sp - calls $1,_getcontext_u - - /* Edit the context to make it continue below, rather than here */ - movab switch_return_point,(UC_GREGS + _REG_PC)(%sp) - - movq 4(%ap),%r2 - movl %sp,PT_UC(%r2) /* self->pt_uc = &context */ - - STACK_SWITCH(%r3) /* r2 = self; r3 = next */ -pthread__switch_return_point: .globl pthread__switch_return_point -setcontext: - pushl %sp /* sp = &context */ - calls $1,_setcontext_u - NOTREACHED -switch_return_point: - ret - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - * - * r3 = new pthread_t - * r4 = lock flags - * r5 = old pthread_t - */ - - .globl pthread__switch_away -pthread__switch_away: -switch_away: - STACK_SWITCH(%r3) - - /* If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there may - * be a fake spinlock-count set. If so, they will set r4 to - * let us know, and we decrement it now that we're no longer - * using the old stack. - */ - subl2 %r4,PT_SPINLOCKS(%r5) - jbr setcontext /* sp = &context */ - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - */ -ENTRY(pthread__locked_switch, 0) - subl2 $CONTEXTSIZE,%sp - movl 8(%ap),%r5 /* r5 = next */ - - /* Make sure we get continuted */ - incl PT_SPINLOCKS(%r5) - - /* Get the current context */ - pushl %sp - calls $1, _getcontext_u - - movl 4(%ap),%r4 /* r4 = self */ - - /* Edit the context to make it continue below, rather than here */ - movab locked_return_point, (UC_GREGS + _REG_PC)(%sp) - movl %sp, PT_UC(%r4) - - STACK_SWITCH(%r5) /* sp = next->pt_uc */ - - /* - * Check if the original thread was preempted while holding - * its queue lock. - */ - movl PT_NEXT(%r4),%r3 - beql 1f - - /* - * Yes, it was. Stash the thread we were going to - * switch to, the lock the original thread was holding, - * and go to the next thread in the chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - movl %sp, PT_SWITCHTOUC(%r4) - movl %r5, PT_SWITCHTO(%r4) - movl 12(%ap), PT_HELDLOCK(%r4) - decl PT_SPINLOCKS(%r4) - - movl %r3, %r5 /* r3 = self->pt_next */ - movl $1, %r4 - jbr switch_away /* r3 = next, r5 = next */ - - /* No locked old-preemption */ -1: /* We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - /* Reduce the lock count... */ - decl PT_SPINLOCKS(%r4) - - /* ... actually release the lock.. */ - clrl *12(%ap) - - /* .. and remove the fake lock */ - decl PT_SPINLOCKS(%r5) - - /* Check if we were preempted while holding the fake lock. */ - movl PT_NEXT(%r5),%r3 - jeql setcontext - - /* Yes, we were. Bummer. Go to the next element in the chain. */ - movl %sp, PT_SWITCHTOUC(%r5) - movl %r5, PT_SWITCHTO(%r5) - movl PT_NEXT(%r5), %r3 - movl $2, %r4 - jbr switch_away - NOTREACHED - -locked_return_point: - ret - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - */ - -ENTRY(pthread__upcall_switch, 0) - movq 4(%ap),%r4 /* r4 = self, r5 = next */ - - /* - * this code never returns, so we can treat r0-r5 as - * convenient registers that will be saved for us by callees, - * but that we do not have to save. - */ - - /* Create a "fake" lock count so that this code will be continued */ - incl PT_SPINLOCKS(%r5) - - STACK_SWITCH(%r5) - - /* Check if the upcall code was preempted and continued to here. */ - movl PT_NEXT(%r4),%r3 - beql 1f - - /* Yes, it was. Stash the thread we were going to switch to, - * and switch to the next thread in the continuation chain. - */ - movl %sp,PT_SWITCHTOUC(%r4) - movq %r5,PT_SWITCHTO(%r4) - movl PT_NEXT(%r4), %r3 - movl %r4, %r5 - movl $1, %r4 - jbr switch_away - - /* No old-upcall-preemption */ -1: movq %r4,-(%sp) - calls $2, pthread__sa_recycle - - /* grab the arguments again */ - movq 4(%ap),%r4 - - /* We can now release the fake lock. */ - decl PT_SPINLOCKS(%r5) - - /* Check if we were preempted and continued while faking the lock */ - movl PT_NEXT(%r5),%r3 - jeql setcontext /* No new-upcall-preemption */ - - /* Yes, we were. Stash the to-be-switched-to context in our thread - * structure and go to the next link in the chain. - */ - movl %sp, PT_SWITCHTOUC(%r5) - movl %r5, PT_SWITCHTO(%r5) - movl PT_NEXT(%r5), %r3 - movl $1, %r4 - jbr switch_away diff --git a/lib/libpthread/arch/x86_64/genassym.cf b/lib/libpthread/arch/x86_64/genassym.cf index 0c09b1fe8a7..fc951a9221a 100644 --- a/lib/libpthread/arch/x86_64/genassym.cf +++ b/lib/libpthread/arch/x86_64/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.4 2003/09/07 14:47:56 cl Exp $ +# $NetBSD: genassym.cf,v 1.5 2007/03/02 18:54:01 ad Exp $ # Copyright (c) 2001 The NetBSD Foundation, Inc. # All rights reserved. @@ -42,13 +42,7 @@ include "pthread.h" include "pthread_int.h" include "pthread_md.h" -define PT_NEXT offsetof(struct __pthread_st, pt_next) -define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto) -define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc) -define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks) -define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock) define PT_UC offsetof(struct __pthread_st, pt_uc) -define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc) define CONTEXTSIZE sizeof(ucontext_t) define UC_FLAGS offsetof(ucontext_t, uc_flags) define UC_REGS offsetof(ucontext_t, uc_mcontext.__gregs) diff --git a/lib/libpthread/arch/x86_64/pthread_switch.S b/lib/libpthread/arch/x86_64/pthread_switch.S deleted file mode 100644 index 6bca9861a73..00000000000 --- a/lib/libpthread/arch/x86_64/pthread_switch.S +++ /dev/null @@ -1,330 +0,0 @@ -/* $NetBSD: pthread_switch.S,v 1.12 2006/01/09 22:17:16 skrll Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Adapted for x86_64 by fvdl@NetBSD.org - */ - -#include <machine/asm.h> -#include "assym.h" - -/* - * This file implements low-level routines that are exported to - * the machine-independent parts of the thread library. The routines are: - * - * void pthread__switch(pthread_t self, pthread_t next); - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * as well as some utility code used by these routines. - */ - -/* Force an error when "notreached" code is reached. */ -#define NOTREACHED \ - int3 - - -/* - * Utility macro to switch to the stack of another thread. - * WARNING: This is more subtle than it looks. - * - * There are a couple of motivations for stack switching. One is that - * when exiting an upcall and running a thread, we want to recycle the - * state of the upcall before continuing the thread. However, the - * stack is part of the upcall state, and we can't be on the upcall - * stack when we want to recycle it. Therefore, we pre-switch to the - * stack of the thread we're about to switch to and borrow some space - * on its stack so that we can recycle the upcall. - * - * Another is that when performing the slightly sensitive operation of - * putting the currently running thread on a (locked) sleep queue then - * switching to another thread, we don't want to release the queue - * lock until we are no longer on the original stack - if we released - * it any earlier, it's possible (epecially on a multiprocessor - * system) that the original thread could get taken off the queue and - * restarted while we're still using its stack, which would be bad - * ("Important safety tip. Thanks, Egon"). - * - * The subtlety comes from the contents of the stack of the thread - * being switched to. Our convention is that the ucontext_t of the - * thread is stored near the top of the stack. When the kernel - * preempts a thread, it stores the ucontext_t just above the current - * top-of-stack and passes the upcall handler the pointer to the - * ucontext_t, and the upcall handler stores it in the pt_uc field - * of the thread structure. When user-level code voluntairly switches - * from one thread to another, the ucontext_t is just below the top of - * the stack, and we impose a limit on the amount of stack space above - * the ucontext_t that may be used. This way, we can perform the stack - * switch safely by setting the stack pointer to thread->pt_uc - - * STACKSPACE. - * Note carefully that we do the subtraction *before* putting the - * value in the stack pointer. Since preemption can occur at any time, - * and the kernel will happily write the new ucontext_t below the - * current stack pointer, it is unsafe for us to ever set the stack - * pointer above potentially valid data, even for one instruction. - * - * Got it? Good. Now go read it again. - * - */ - -#define STACK_SWITCH \ - movq PT_TRAPUC(%r13), %r15 ; \ - cmpq $0, %r15 ; \ - jne 1f ; \ - movq PT_UC(%r13), %r15 ; \ -1: leaq (-STACKSPACE)(%r15), %rsp ; \ - movq $0, PT_TRAPUC(%r13) - - -/* - * void pthread__switch(pthread_t self, pthread_t next); - * - * Plain switch that doesn't do any special checking or handle - * spin-preemption. It isn't used much by normal code, actually; it's - * main purpose is to be a basic switch engine when the MI code is - * already dealing with spin-preemption or other gunk. - */ -ENTRY(pthread__switch) - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - movq %rdi,%r12 - movq %rsi,%r13 - /* r12 (eax) holds the current thread */ - /* r13 (ecx) holds the thread to switch to */ - subq $CONTEXTSIZE+8, %rsp /* Allocate space for the ucontext_t */ - leaq 8(%rsp), %r14 - andq $~(0xf), %r14 /* 16-byte-align the ucontext_t area */ - movq %r14,%rdi - call PIC_PLT(_C_LABEL(_getcontext_u)) - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below. - */ -#ifdef PIC - movq PIC_GOT(pthread__switch_return_point), %r15 -#else - leaq pthread__switch_return_point(%rip), %r15 -#endif - movq %r15, UC_RIP(%r14) - movq %r14, PT_UC(%r12) - - STACK_SWITCH - - movq %r15, %rdi /* ucontext_t *ucp */ - call PIC_PLT(_C_LABEL(_setcontext_u)) -NENTRY(pthread__switch_return_point) - /* We're back on the original stack. */ - addq $CONTEXTSIZE+8, %rsp - popq %r15 - popq %r14 - popq %r13 - popq %r12 - ret - -/* - * Helper switch code used by pthread__locked_switch() and - * pthread__upcall_switch() when they discover spinlock preemption. - */ -pthread__switch_away: - STACK_SWITCH - - /* - * If we're invoked from the switch-to-next provisions of - * pthread__locked_switch or pthread__upcall_switch, there - * may be a fake spinlock-count set. If so, they will set %edx - * to let us know, and we decrement it once we're no longer using - * the old stack. - */ - cmpl $0, %ebx - jle pthread__switch_no_decrement - decl PT_SPINLOCKS(%r12) - -pthread__switch_no_decrement: - movq %r15,%rdi /* ucontext_t *ucp */ - call PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED - -/* - * void pthread__locked_switch(pthread_t self, pthread_t next, - * pt_spin_t *lock); - * - * Switch away from a thread that is holding a lock on a queue (to - * prevent being removed from the queue before being switched away). - */ -ENTRY(pthread__locked_switch) - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - pushq %rbx - - movq %rdi, %r12 - movq %rsi, %r13 - movq %rdx, %rbx - incl PT_SPINLOCKS(%r13) /* Make sure we get continued */ - subq $CONTEXTSIZE+8, %rsp /* Allocate space for the ucontext_t */ - leaq 8(%rsp), %r14 - andq $~(0xf), %r14 /* 16-byte-align the ucontext_t area */ - movq %r14, %rdi - call PIC_PLT(_C_LABEL(_getcontext_u)) - /* - * Edit the context so that it continues as if returning from - * the _setcontext_u below. - */ - leaq locked_return_point(%rip), %r15 - movq %r15, UC_RIP(%r14) - movq %r14, PT_UC(%r12) - - STACK_SWITCH - - /* - * Check if the original thread was preempted while holding - * its queue lock. - */ - cmpq $0, PT_NEXT(%r12) - je locked_no_old_preempt - - /* - * Yes, it was. Stash the thread we were going to - * switch to, the lock the original thread was holding, - * and go to the next thread in the chain. - * Mark the fact that this was a locked switch, and so the - * thread does not need to be put on a run queue. - * Don't release the lock. It's possible that if we do so, - * PT_SWITCHTO will be stomped by another switch_lock and - * preemption. - */ - movq %r15, PT_SWITCHTOUC(%r12) - movq %r13, PT_SWITCHTO(%r12) - movq %rbx, PT_HELDLOCK(%r12) - decl PT_SPINLOCKS(%r12) - - movq PT_NEXT(%r12), %rbx - movq %r13, %r12 - movq %rbx, %r13 - movl $1, %ebx - jmp pthread__switch_away - NOTREACHED - -locked_no_old_preempt: - /* - * We've moved to the new stack, and the old context has been - * saved. The queue lock can be released. - */ - decl PT_SPINLOCKS(%r12) - /* We happen to know that this is the right way to release a lock. */ - movl $0, 0(%rbx) - - decl PT_SPINLOCKS(%r13) - /* Check if we were preempted while holding the fake lock. */ - cmpq $0, PT_NEXT(%r13) - je locked_no_new_preempt - /* Yes, we were. Bummer. Go to the next element in the chain. */ - movq %r15, PT_SWITCHTOUC(%r13) - movq %r13, PT_SWITCHTO(%r13) - movq %r13, %r12 - movq PT_NEXT(%r13), %r13 - movl $-2, %ebx - jmp pthread__switch_away - NOTREACHED - -locked_no_new_preempt: - movq %r15, %rdi /* ucontext_t *ucp */ - call PIC_PLT(_C_LABEL(_setcontext_u)) -locked_return_point: - /* We're back on the original stack. */ - addq $CONTEXTSIZE+8, %rsp - popq %rbx - popq %r15 - popq %r14 - popq %r13 - popq %r12 - ret - - - -/* - * void pthread__upcall_switch(pthread_t self, pthread_t next); - * - * Quit an upcall, recycle it, and jump to the selected thread. - */ -ENTRY(pthread__upcall_switch) - movq %rdi, %r12 - movq %rsi, %r13 - incl PT_SPINLOCKS(%r13) - - STACK_SWITCH - - /* Check if the upcall was preempted and continued. */ - cmpq $0, PT_NEXT(%r12) - je upcall_no_old_preempt - /* - * Yes, it was. Stash the thread we were going to - * switch to, and go to the next thread in the chain. - */ - movq %r15, PT_SWITCHTOUC(%r12) - movq %r13, PT_SWITCHTO(%r12) - movq PT_NEXT(%r12), %rbx - movq %r13, %r12 - movq %rbx, %r13 - movl $1, %ebx - jmp pthread__switch_away - NOTREACHED - -upcall_no_old_preempt: - movq %r12,%rdi - movq %r13,%rsi - call PIC_PLT(_C_LABEL(pthread__sa_recycle)) - decl PT_SPINLOCKS(%r13) - /* Check if we were preempted while holding the fake lock. */ - cmpq $0, PT_NEXT(%r13) - je upcall_no_new_preempt - /* Yes, we were. Bummer. Go to the next element in the chain. */ - movq %r15, PT_SWITCHTOUC(%r13) - movq %r13, PT_SWITCHTO(%r13) - movq %r13, %r12 - movq PT_NEXT(%r13), %r13 - movl $-1, %ebx - jmp pthread__switch_away - NOTREACHED - -upcall_no_new_preempt: - movq %r15, %rdi - call PIC_PLT(_C_LABEL(_setcontext_u)) - NOTREACHED diff --git a/lib/libpthread/debuglog.c b/lib/libpthread/debuglog.c index fd3a112956c..48de75665f7 100644 --- a/lib/libpthread/debuglog.c +++ b/lib/libpthread/debuglog.c @@ -1,4 +1,4 @@ -/* $NetBSD: debuglog.c,v 1.6 2006/12/14 20:39:04 ad Exp $ */ +/* $NetBSD: debuglog.c,v 1.7 2007/03/02 18:53:51 ad Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -145,7 +145,7 @@ pthread__debuglog_read(int follow, int trunc) debugbuf->msg_bufr = writep; if (follow) - sleep(1); + sched_yield(); } while (follow); } diff --git a/lib/libpthread/pthread.c b/lib/libpthread/pthread.c index 8419853a6ff..6b737d263dd 100644 --- a/lib/libpthread/pthread.c +++ b/lib/libpthread/pthread.c @@ -1,4 +1,4 @@ -/* $NetBSD: pthread.c,v 1.63 2007/03/02 17:40:55 ad Exp $ */ +/* $NetBSD: pthread.c,v 1.64 2007/03/02 18:53:51 ad Exp $ */ /*- * Copyright (c) 2001, 2002, 2003, 2006, 2007 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread.c,v 1.63 2007/03/02 17:40:55 ad Exp $"); +__RCSID("$NetBSD: pthread.c,v 1.64 2007/03/02 18:53:51 ad Exp $"); #include <err.h> #include <errno.h> @@ -51,9 +51,6 @@ __RCSID("$NetBSD: pthread.c,v 1.63 2007/03/02 17:40:55 ad Exp $"); #include <unistd.h> #include <sys/param.h> #include <sys/sysctl.h> -#ifdef PTHREAD_MLOCK_KLUDGE -#include <sys/mman.h> -#endif #include <sched.h> #include "pthread.h" @@ -96,13 +93,6 @@ enum { static int pthread__diagassert = DIAGASSERT_ABORT | DIAGASSERT_STDERR; -#ifdef PTHREAD_SA -pthread_spin_t pthread__runqueue_lock = __SIMPLELOCK_UNLOCKED; -struct pthread_queue_t pthread__runqueue; -struct pthread_queue_t pthread__idlequeue; -struct pthread_queue_t pthread__suspqueue; -#endif - int pthread__concurrency, pthread__maxconcurrency, pthread__nspins; int pthread__unpark_max = PTHREAD__UNPARK_MAX; @@ -119,10 +109,6 @@ __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate) * file which does not already have a reference here. */ extern int pthread__cancel_stub_binder; -#ifdef PTHREAD_SA -extern int pthread__sched_binder; -extern struct pthread_queue_t pthread__nanosleeping; -#endif void *pthread__static_lib_binder[] = { &pthread__cancel_stub_binder, @@ -132,10 +118,6 @@ void *pthread__static_lib_binder[] = { pthread_barrier_init, pthread_key_create, pthread_setspecific, -#ifdef PTHREAD_SA - &pthread__sched_binder, - &pthread__nanosleeping -#endif }; /* @@ -152,9 +134,6 @@ pthread_init(void) int i, mib[2], ncpu; size_t len; extern int __isthreaded; -#ifdef PTHREAD_MLOCK_KLUDGE - int ret; -#endif mib[0] = CTL_HW; mib[1] = HW_NCPU; @@ -165,24 +144,6 @@ pthread_init(void) /* Initialize locks first; they're needed elsewhere. */ pthread__lockprim_init(ncpu); -#ifdef PTHREAD_SA - /* Find out requested/possible concurrency */ - p = getenv("PTHREAD_CONCURRENCY"); - pthread__maxconcurrency = p ? atoi(p) : 1; - - if (pthread__maxconcurrency < 1) - pthread__maxconcurrency = 1; - if (pthread__maxconcurrency > ncpu) - pthread__maxconcurrency = ncpu; - - /* Allocate data structures */ - pthread__reidlequeue = (struct pthread_queue_t *)malloc - (pthread__maxconcurrency * sizeof(struct pthread_queue_t)); - if (pthread__reidlequeue == NULL) - err(1, "Couldn't allocate memory for pthread__reidlequeue"); - - pthread__nspins = PTHREAD__NSPINS; -#else /* * Get number of CPUs, and maximum number of LWPs that can be * unparked at once. @@ -196,39 +157,21 @@ pthread_init(void) err(1, "_lwp_unpark_all"); if (i < pthread__unpark_max) pthread__unpark_max = i; -#endif /* Basic data structure setup */ pthread_attr_init(&pthread_default_attr); PTQ_INIT(&pthread__allqueue); PTQ_INIT(&pthread__deadqueue); -#ifdef PTHREAD_MLOCK_KLUDGE - ret = mlock(&pthread__deadqueue, sizeof(pthread__deadqueue)); - pthread__assert(ret == 0); -#endif -#ifdef PTHREAD_SA - PTQ_INIT(&pthread__runqueue); - PTQ_INIT(&pthread__idlequeue); - for (i = 0; i < pthread__maxconcurrency; i++) - PTQ_INIT(&pthread__reidlequeue[i]); -#endif nthreads = 1; /* Create the thread structure corresponding to main() */ pthread__initmain(&first); pthread__initthread(first, first); first->pt_state = PT_STATE_RUNNING; -#ifdef PTHREAD_SA - _sys___sigprocmask14(0, NULL, &first->pt_sigmask); -#else first->pt_lid = _lwp_self(); -#endif PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq); /* Start subsystems */ -#ifdef PTHREAD_SA - pthread__signal_init(); -#endif PTHREAD_MD_INIT #ifdef PTHREAD__DEBUG pthread__debug_init(ncpu); @@ -282,10 +225,6 @@ static void pthread__start(void) { pthread_t self; -#ifdef PTHREAD_SA - pthread_t idle; - int i, ret; -#endif self = pthread__self(); /* should be the "main()" thread */ @@ -294,34 +233,7 @@ pthread__start(void) * various restrictions on fork() and threads, it's legal to * fork() before creating any threads. */ -#ifdef PTHREAD_SA - pthread__alarm_init(); - - pthread__signal_start(); -#endif - pthread_atfork(NULL, NULL, pthread__child_callback); - -#ifdef PTHREAD_SA - /* - * Create idle threads - * XXX need to create more idle threads if concurrency > 3 - */ - for (i = 0; i < NIDLETHREADS; i++) { - ret = pthread__stackalloc(&idle); - if (ret != 0) - err(1, "Couldn't allocate stack for idle thread!"); - pthread__initthread(self, idle); - sigfillset(&idle->pt_sigmask); - idle->pt_type = PT_THREAD_IDLE; - PTQ_INSERT_HEAD(&pthread__allqueue, idle, pt_allq); - pthread__sched_idle(self, idle); - } - - /* Start up the SA subsystem */ - pthread__sa_start(); -#endif - SDPRINTF(("(pthread__start %p) Started.\n", self)); } @@ -345,21 +257,7 @@ pthread__initthread(pthread_t self, pthread_t t) t->pt_flags = 0; t->pt_cancel = 0; t->pt_errno = 0; - -#ifdef PTHREAD_SA - t->pt_type = PT_THREAD_NORMAL; - t->pt_state = PT_STATE_RUNNABLE; - t->pt_heldlock = NULL; - t->pt_next = NULL; - t->pt_parent = NULL; - t->pt_switchto = NULL; - t->pt_trapuc = NULL; - sigemptyset(&t->pt_siglist); - sigemptyset(&t->pt_sigmask); - pthread_lockinit(&t->pt_siglock); -#else t->pt_state = PT_STATE_RUNNING; -#endif pthread_lockinit(&t->pt_statelock); @@ -368,12 +266,6 @@ pthread__initthread(pthread_t self, pthread_t t) PTQ_INIT(&t->pt_cleanup_stack); memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX); t->pt_name = NULL; - -#if defined(PTHREAD__DEBUG) && defined(PTHREAD_SA) - t->blocks = 0; - t->preempts = 0; - t->rescheds = 0; -#endif } @@ -385,10 +277,7 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr, pthread_attr_t nattr; struct pthread_attr_private *p; char * volatile name; - int ret; -#ifndef PTHREAD_SA - int flag; -#endif + int ret, flag; PTHREADD_ADD(PTHREADD_CREATE); @@ -420,12 +309,10 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr, pthread_spinlock(self, &pthread__deadqueue_lock); newthread = PTQ_FIRST(&pthread__deadqueue); if (newthread != NULL) { -#ifndef PTHREAD_SA if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0 && (_lwp_kill(newthread->pt_lid, 0) == 0 || errno != ESRCH)) newthread = NULL; else -#endif PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq); } pthread_spinunlock(self, &pthread__deadqueue_lock); @@ -442,9 +329,6 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr, /* 2. Set up state. */ pthread__initthread(self, newthread); newthread->pt_flags = nattr.pta_flags; -#ifdef PTHREAD_SA - newthread->pt_sigmask = self->pt_sigmask; -#endif /* 3. Set up misc. attributes. */ newthread->pt_name = name; @@ -470,7 +354,6 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr, nthreads++; pthread_spinunlock(self, &pthread__allqueue_lock); -#ifndef PTHREAD_SA /* 5a. Create the new LWP. */ newthread->pt_sleeponq = 0; flag = 0; @@ -492,23 +375,10 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr, pthread_spinunlock(self, &pthread__deadqueue_lock); return ret; } -#endif -#ifdef PTHREAD_SA - SDPRINTF(("(pthread_create %p) new thread %p (name pointer %p).\n", - self, newthread, newthread->pt_name)); - /* 6. Put on appropriate queue. */ - if (newthread->pt_flags & PT_FLAG_SUSPENDED) { - pthread_spinlock(self, &newthread->pt_statelock); - pthread__suspend(self, newthread); - pthread_spinunlock(self, &newthread->pt_statelock); - } else - pthread__sched(self, newthread); -#else SDPRINTF(("(pthread_create %p) new thread %p (name %p, lid %d).\n", self, newthread, newthread->pt_name, (int)newthread->pt_lid)); -#endif *thread = newthread; @@ -542,48 +412,9 @@ pthread_suspend_np(pthread_t thread) if (pthread__find(self, thread) != 0) return ESRCH; #endif -#ifdef PTHREAD_SA - SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p (state %d).\n", - self, thread, thread->pt_state)); - pthread_spinlock(self, &thread->pt_statelock); - if (thread->pt_blockgen != thread->pt_unblockgen) { - /* XXX flaglock? */ - thread->pt_flags |= PT_FLAG_SUSPENDED; - pthread_spinunlock(self, &thread->pt_statelock); - return 0; - } - switch (thread->pt_state) { - case PT_STATE_RUNNING: - pthread__abort(); /* XXX */ - break; - case PT_STATE_SUSPENDED: - pthread_spinunlock(self, &thread->pt_statelock); - return 0; - case PT_STATE_RUNNABLE: - pthread_spinlock(self, &pthread__runqueue_lock); - PTQ_REMOVE(&pthread__runqueue, thread, pt_runq); - pthread_spinunlock(self, &pthread__runqueue_lock); - break; - case PT_STATE_BLOCKED_QUEUE: - pthread_spinlock(self, thread->pt_sleeplock); - PTQ_REMOVE(thread->pt_sleepq, thread, pt_sleep); - pthread_spinunlock(self, thread->pt_sleeplock); - break; - case PT_STATE_ZOMBIE: - goto out; - default: - break; /* XXX */ - } - pthread__suspend(self, thread); - -out: - pthread_spinunlock(self, &thread->pt_statelock); - return 0; -#else SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p.\n", self, thread)); return _lwp_suspend(thread->pt_lid); -#endif } int @@ -596,71 +427,11 @@ pthread_resume_np(pthread_t thread) if (pthread__find(self, thread) != 0) return ESRCH; #endif -#ifdef PTHREAD_SA - SDPRINTF(("(pthread_resume_np %p) Resume thread %p (state %d).\n", - self, thread, thread->pt_state)); - pthread_spinlock(self, &thread->pt_statelock); - /* XXX flaglock? */ - thread->pt_flags &= ~PT_FLAG_SUSPENDED; - if (thread->pt_state == PT_STATE_SUSPENDED) { - pthread_spinlock(self, &pthread__runqueue_lock); - PTQ_REMOVE(&pthread__suspqueue, thread, pt_runq); - pthread_spinunlock(self, &pthread__runqueue_lock); - pthread__sched(self, thread); - } - pthread_spinunlock(self, &thread->pt_statelock); - return 0; -#else SDPRINTF(("(pthread_resume_np %p) Resume thread %p.\n", self, thread)); return _lwp_continue(thread->pt_lid); -#endif } -#ifdef PTHREAD_SA -/* - * Other threads will switch to the idle thread so that they - * can dispose of any awkward locks or recycle upcall state. - */ -void -pthread__idle(void) -{ - pthread_t self; - - PTHREADD_ADD(PTHREADD_IDLE); - self = pthread__self(); - SDPRINTF(("(pthread__idle %p).\n", self)); - - /* - * The drill here is that we want to yield the processor, - * but for the thread itself to be recovered, we need to be on - * a list somewhere for the thread system to know about us. - */ - pthread_spinlock(self, &pthread__deadqueue_lock); - PTQ_INSERT_TAIL(&pthread__reidlequeue[self->pt_vpid], self, pt_runq); - pthread__concurrency--; - SDPRINTF(("(yield %p concurrency) now %d\n", self, - pthread__concurrency)); - /* Don't need a flag lock; nothing else has a handle on this thread */ - self->pt_flags |= PT_FLAG_IDLED; - pthread_spinunlock(self, &pthread__deadqueue_lock); - - /* - * If we get to run this, then no preemption has happened - * (because the upcall handler will not continue an idle thread with - * PT_FLAG_IDLED set), and so we can yield the processor safely. - */ - SDPRINTF(("(pthread__idle %p) yielding.\n", self)); - sa_yield(); - - /* NOTREACHED */ - self->pt_spinlocks++; /* XXX make sure we get to finish the assert! */ - SDPRINTF(("(pthread__idle %p) Returned! Error.\n", self)); - pthread__abort(); -} -#endif - - void pthread_exit(void *retval) { @@ -719,15 +490,8 @@ pthread_exit(void *retval) /* Yeah, yeah, doing work while we're dead is tacky. */ pthread_spinlock(self, &pthread__deadqueue_lock); PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_allq); - -#ifdef PTHREAD_SA - pthread__block(self, &pthread__deadqueue_lock); - SDPRINTF(("(pthread_exit %p) walking dead\n", self)); - pthread_spinunlock(self, &pthread__allqueue_lock); -#else pthread_spinunlock(self, &pthread__deadqueue_lock); _lwp_exit(); -#endif } else { self->pt_state = PT_STATE_ZOMBIE; @@ -740,19 +504,8 @@ pthread_exit(void *retval) /* Whoah, we're the last one. Time to go. */ exit(0); } - -#ifdef PTHREAD_SA - /* - * Wake up all the potential joiners. Only one can win. - * (Can you say "Thundering Herd"? I knew you could.) - */ - pthread__sched_sleepers(self, &self->pt_joiners); - pthread__block(self, &self->pt_join_lock); - SDPRINTF(("(pthread_exit %p) walking zombie\n", self)); -#else pthread_spinunlock(self, &self->pt_join_lock); _lwp_exit(); -#endif } /*NOTREACHED*/ @@ -780,65 +533,6 @@ pthread_join(pthread_t thread, void **valptr) if (thread == self) return EDEADLK; -#ifdef PTHREAD_SA - pthread_spinlock(self, &thread->pt_flaglock); - - if (thread->pt_flags & PT_FLAG_DETACHED) { - pthread_spinunlock(self, &thread->pt_flaglock); - return EINVAL; - } - - num = thread->pt_num; - pthread_spinlock(self, &thread->pt_join_lock); - while (thread->pt_state != PT_STATE_ZOMBIE) { - if ((thread->pt_state == PT_STATE_DEAD) || - (thread->pt_flags & PT_FLAG_DETACHED) || - (thread->pt_num != num)) { - /* - * Another thread beat us to the join, or called - * pthread_detach(). If num didn't match, the - * thread died and was recycled before we got - * another chance to run. - */ - pthread_spinunlock(self, &thread->pt_join_lock); - pthread_spinunlock(self, &thread->pt_flaglock); - return ESRCH; - } - /* - * "I'm not dead yet!" - * "You will be soon enough." - */ - pthread_spinunlock(self, &thread->pt_flaglock); - pthread_spinlock(self, &self->pt_statelock); - if (self->pt_cancel) { - pthread_spinunlock(self, &self->pt_statelock); - pthread_spinunlock(self, &thread->pt_join_lock); - pthread_exit(PTHREAD_CANCELED); - } - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = thread; - self->pt_sleepq = &thread->pt_joiners; - self->pt_sleeplock = &thread->pt_join_lock; - pthread_spinunlock(self, &self->pt_statelock); - - PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep); - pthread__block(self, &thread->pt_join_lock); - pthread_spinlock(self, &thread->pt_flaglock); - pthread_spinlock(self, &thread->pt_join_lock); - } - - /* All ours. */ - thread->pt_state = PT_STATE_DEAD; - name = thread->pt_name; - thread->pt_name = NULL; - pthread_spinunlock(self, &thread->pt_join_lock); - pthread_spinunlock(self, &thread->pt_flaglock); - - if (valptr != NULL) - *valptr = thread->pt_exitval; - - retval = 0; -#else /* PTHREAD_SA */ retval = 0; name = NULL; again: @@ -871,7 +565,6 @@ pthread_join(pthread_t thread, void **valptr) pthread_spinunlock(self, &thread->pt_join_lock); return EINVAL; } -#endif /* PTHREAD_SA */ SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread)); @@ -897,10 +590,6 @@ int pthread_detach(pthread_t thread) { pthread_t self; -#ifdef PTHREAD_SA - int doreclaim = 0; - char *name = NULL; -#endif self = pthread__self(); @@ -910,44 +599,11 @@ pthread_detach(pthread_t thread) if (thread->pt_magic != PT_MAGIC) return EINVAL; -#ifdef PTHREAD_SA - pthread_spinlock(self, &thread->pt_flaglock); - pthread_spinlock(self, &thread->pt_join_lock); - - if (thread->pt_flags & PT_FLAG_DETACHED) { - pthread_spinunlock(self, &thread->pt_join_lock); - pthread_spinunlock(self, &thread->pt_flaglock); - return EINVAL; - } - - thread->pt_flags |= PT_FLAG_DETACHED; - - /* Any joiners have to be punted now. */ - pthread__sched_sleepers(self, &thread->pt_joiners); - - if (thread->pt_state == PT_STATE_ZOMBIE) { - thread->pt_state = PT_STATE_DEAD; - name = thread->pt_name; - thread->pt_name = NULL; - doreclaim = 1; - } - - pthread_spinunlock(self, &thread->pt_join_lock); - pthread_spinunlock(self, &thread->pt_flaglock); - - if (doreclaim) { - pthread__dead(self, thread); - if (name != NULL) - free(name); - } - - return 0; -#else pthread_spinlock(self, &self->pt_join_lock); thread->pt_flags |= PT_FLAG_DETACHED; pthread_spinunlock(self, &self->pt_join_lock); + return _lwp_detach(thread->pt_lid); -#endif } @@ -956,9 +612,6 @@ pthread__dead(pthread_t self, pthread_t thread) { SDPRINTF(("(pthread__dead %p) Reclaimed %p.\n", self, thread)); -#ifdef PTHREAD_SA - pthread__assert(thread != self); -#endif pthread__assert(thread->pt_state == PT_STATE_DEAD); pthread__assert(thread->pt_name == NULL); @@ -1020,15 +673,6 @@ pthread_setname_np(pthread_t thread, const char *name, void *arg) return ENOMEM; pthread_spinlock(self, &thread->pt_join_lock); - -#ifdef PTHREAD_SA - if (thread->pt_state == PT_STATE_DEAD) { - pthread_spinunlock(self, &thread->pt_join_lock); - free(cp); - return EINVAL; - } -#endif - oldname = thread->pt_name; thread->pt_name = cp; @@ -1064,51 +708,6 @@ pthread_cancel(pthread_t thread) if (pthread__find(self, thread) != 0) return ESRCH; #endif -#ifdef PTHREAD_SA - if (!(thread->pt_state == PT_STATE_RUNNING || - thread->pt_state == PT_STATE_RUNNABLE || - thread->pt_state == PT_STATE_BLOCKED_QUEUE)) - return ESRCH; - - pthread_spinlock(self, &thread->pt_flaglock); - thread->pt_flags |= PT_FLAG_CS_PENDING; - if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { - thread->pt_cancel = 1; - pthread_spinunlock(self, &thread->pt_flaglock); - pthread_spinlock(self, &thread->pt_statelock); - if (thread->pt_blockgen != thread->pt_unblockgen) { - /* - * It's sleeping in the kernel. If we can wake - * it up, it will notice the cancellation when - * it returns. If it doesn't wake up when we - * make this call, then it's blocked - * uninterruptably in the kernel, and there's - * not much to be done about it. - */ - _lwp_wakeup(thread->pt_blockedlwp); - } else if (thread->pt_state == PT_STATE_BLOCKED_QUEUE) { - /* - * We're blocked somewhere (pthread__block() - * was called). Cause it to wake up; it will - * check for the cancellation if the routine - * is a cancellation point, and loop and reblock - * otherwise. - */ - pthread_spinlock(self, thread->pt_sleeplock); - PTQ_REMOVE(thread->pt_sleepq, thread, - pt_sleep); - pthread_spinunlock(self, thread->pt_sleeplock); - pthread__sched(self, thread); - } else { - /* - * Nothing. The target thread is running and will - * notice at the next deferred cancellation point. - */ - } - pthread_spinunlock(self, &thread->pt_statelock); - } else - pthread_spinunlock(self, &thread->pt_flaglock); -#else pthread_spinlock(self, &thread->pt_flaglock); thread->pt_flags |= PT_FLAG_CS_PENDING; if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { @@ -1117,7 +716,6 @@ pthread_cancel(pthread_t thread) _lwp_wakeup(thread->pt_lid); } else pthread_spinunlock(self, &thread->pt_flaglock); -#endif return 0; } @@ -1351,8 +949,6 @@ pthread__errorfunc(const char *file, int line, const char *function, } } -#ifndef PTHREAD_SA - /* * Thread park/unpark operations. The kernel operations are * modelled after a brief description from "Multithreading in @@ -1537,5 +1133,3 @@ pthread__unpark_all(pthread_t self, pthread_spin_t *lock, void *obj, } #undef OOPS - -#endif /* !PTHREAD_SA */ diff --git a/lib/libpthread/pthread_alarms.c b/lib/libpthread/pthread_alarms.c deleted file mode 100644 index bdff7861211..00000000000 --- a/lib/libpthread/pthread_alarms.c +++ /dev/null @@ -1,233 +0,0 @@ -/* $NetBSD: pthread_alarms.c,v 1.14 2006/12/23 05:14:46 ad Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef PTHREAD_SA - -#include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_alarms.c,v 1.14 2006/12/23 05:14:46 ad Exp $"); - -#include <err.h> -#include <sys/time.h> -#include <stdlib.h> - -#include "pthread.h" -#include "pthread_int.h" - -timer_t pthread_alarmtimer; -PTQ_HEAD(, pt_alarm_t) pthread_alarmqueue = PTQ_HEAD_INITIALIZER; -pthread_spin_t pthread_alarmqlock = __SIMPLELOCK_UNLOCKED; - -#ifdef PTHREAD_ALARM_DEBUG -#define SDPRINTF(x) DPRINTF(x) -#else -#define SDPRINTF(x) -#endif - -void -pthread__alarm_init(void) -{ - struct sigevent ev; - int retval; - - ev.sigev_notify = SIGEV_SA; - ev.sigev_signo = 0; - ev.sigev_value.sival_int = (int)PT_ALARMTIMER_MAGIC; - retval = timer_create(CLOCK_REALTIME, &ev, &pthread_alarmtimer); - pthread__assert(retval == 0); - -} - -void -pthread__alarm_add(pthread_t self, struct pt_alarm_t *alarm, - const struct timespec *ts, void (*func)(void *), void *arg) -{ - struct pt_alarm_t *iterator, *prev; - struct itimerspec it; - int retval; - - pthread_lockinit(&alarm->pta_lock); - alarm->pta_time = ts; - alarm->pta_func = func; - alarm->pta_arg = arg; - alarm->pta_fired = 0; - - SDPRINTF(("(alarm_add %p) alarm %p for %d.%06ld\n", - self, alarm, ts->tv_sec, ts->tv_nsec/1000)); - prev = NULL; - pthread_spinlock(self, &pthread_alarmqlock); - PTQ_FOREACH(iterator, &pthread_alarmqueue, pta_next) { - if (timespeccmp(ts, iterator->pta_time, <)) - break; - prev = iterator; - } - - if (iterator == PTQ_FIRST(&pthread_alarmqueue)) { - PTQ_INSERT_HEAD(&pthread_alarmqueue, alarm, pta_next); - timespecclear(&it.it_interval); - /* - * A zero-valued timespec will disarm the timer, but is - * a legitimate value for the _timedwait functions to - * pass in. Correct for this here and in other timer-resetting - * code by setting it_value to a small value that is - * safely in the past. - */ - if (timespecisset(ts)) { - it.it_value = *ts; - } else { - it.it_value.tv_sec = 1; - it.it_value.tv_nsec = 0; - } - SDPRINTF(("(add %p) resetting alarm timer to %d.%06d\n", - self, it.it_value.tv_sec, it.it_value.tv_nsec/1000)); - retval = timer_settime(pthread_alarmtimer, TIMER_ABSTIME, - &it, NULL); - pthread__assert(retval == 0); - - } else if (prev != NULL) { - PTQ_INSERT_AFTER(&pthread_alarmqueue, prev, alarm, pta_next); - } - pthread_spinunlock(self, &pthread_alarmqlock); - -} - -void -pthread__alarm_del(pthread_t self, struct pt_alarm_t *alarm) -{ - struct pt_alarm_t *next; - struct itimerspec it; - int retval; - - next = NULL; - pthread_spinlock(self, &pthread_alarmqlock); - pthread_spinlock(self, &alarm->pta_lock); - SDPRINTF(("(del %p) alarm %p\n", self, alarm)); - if (alarm->pta_fired == 0) { - if (alarm == PTQ_FIRST(&pthread_alarmqueue)) { - next = PTQ_NEXT(alarm, pta_next); - timespecclear(&it.it_interval); - if (next != NULL) - /* See comment in pthread__alarm_add() */ - if (timespecisset(next->pta_time)) { - it.it_value = *next->pta_time; - } else { - it.it_value.tv_sec = 1; - it.it_value.tv_nsec = 0; - } - else - timespecclear(&it.it_value); - SDPRINTF(("(del %p) resetting alarm timer to %d.%06d\n", - self, it.it_value.tv_sec, it.it_value.tv_nsec/1000)); - retval = timer_settime(pthread_alarmtimer, TIMER_ABSTIME, &it, - NULL); - pthread__assert(retval == 0); - } - PTQ_REMOVE(&pthread_alarmqueue, alarm, pta_next); - } - pthread_spinunlock(self, &alarm->pta_lock); - pthread_spinunlock(self, &pthread_alarmqlock); -} - -int -pthread__alarm_fired(struct pt_alarm_t *alarm) -{ - - return alarm->pta_fired; -} - -void -/*ARGSUSED*/ -pthread__alarm_process(pthread_t self, void *arg) -{ - struct timespec ts; - struct itimerspec it; - struct pt_alarm_t *iterator, *next; - PTQ_HEAD(, pt_alarm_t) runq; - int retval; - - clock_gettime(CLOCK_REALTIME, &ts); - - SDPRINTF(("(pro %p) alarm time %d.%06ld\n", - self, ts.tv_sec, ts.tv_nsec / 1000)); - - PTQ_INIT(&runq); - pthread_spinlock(self, &pthread_alarmqlock); - - /* 1. Collect a list of all alarms whose time has passed. */ - for (iterator = next = PTQ_FIRST(&pthread_alarmqueue); - iterator; - iterator = next) { - if (timespeccmp(&ts, iterator->pta_time, <=)) - break; - pthread_spinlock(self, &iterator->pta_lock); - next = PTQ_NEXT(iterator, pta_next); - PTQ_REMOVE(&pthread_alarmqueue, iterator, pta_next); - PTQ_INSERT_TAIL(&runq, iterator, pta_next); - SDPRINTF(("(pro %p) collect alarm %p\n", self, iterator)); - } - - /* 2. Reset the timer for the next element in the queue. */ - if (next) { - timespecclear(&it.it_interval); - /* See comment in pthread__alarm_add() */ - if (timespecisset(next->pta_time)) { - it.it_value = *next->pta_time; - } else { - it.it_value.tv_sec = 1; - it.it_value.tv_nsec = 0; - } - SDPRINTF(("(pro %p) resetting alarm timer to %d.%09d\n", self, - it.it_value.tv_sec, it.it_value.tv_nsec)); - retval = timer_settime(pthread_alarmtimer, TIMER_ABSTIME, &it, NULL); - pthread__assert(retval == 0); - } - pthread_spinunlock(self, &pthread_alarmqlock); - - /* 3. Call the functions for all passed alarms. */ - for (iterator = next = PTQ_FIRST(&runq); - iterator; - iterator = next) { - SDPRINTF(("(pro %p) calling function for alarm %p\n", self, iterator)); - (*iterator->pta_func)(iterator->pta_arg); - iterator->pta_fired = 1; - next = PTQ_NEXT(iterator, pta_next); - pthread_spinunlock(self, &iterator->pta_lock); - } - SDPRINTF(("(pro %p) done\n", self, iterator)); -} - -#endif diff --git a/lib/libpthread/pthread_barrier.c b/lib/libpthread/pthread_barrier.c index 625f8ee2b5e..130d041f190 100644 --- a/lib/libpthread/pthread_barrier.c +++ b/lib/libpthread/pthread_barrier.c @@ -1,7 +1,7 @@ -/* $NetBSD: pthread_barrier.c,v 1.9 2007/01/17 23:24:22 hubertf Exp $ */ +/* $NetBSD: pthread_barrier.c,v 1.10 2007/03/02 18:53:52 ad Exp $ */ /*- - * Copyright (c) 2001, 2003 The NetBSD Foundation, Inc. + * Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_barrier.c,v 1.9 2007/01/17 23:24:22 hubertf Exp $"); +__RCSID("$NetBSD: pthread_barrier.c,v 1.10 2007/03/02 18:53:52 ad Exp $"); #include <errno.h> @@ -163,28 +163,12 @@ pthread_barrier_wait(pthread_barrier_t *barrier) * but instead is responsible for waking everyone else up. */ if (barrier->ptb_curcount + 1 == barrier->ptb_initcount) { -#ifdef PTHREAD_SA - struct pthread_queue_t blockedq; - - SDPRINTF(("(barrier wait %p) Satisfied %p\n", - self, barrier)); - - blockedq = barrier->ptb_waiters; - PTQ_INIT(&barrier->ptb_waiters); - barrier->ptb_curcount = 0; - barrier->ptb_generation++; - - pthread__sched_sleepers(self, &blockedq); - - pthread_spinunlock(self, &barrier->ptb_lock); -#else SDPRINTF(("(barrier wait %p) Satisfied %p\n", self, barrier)); barrier->ptb_generation++; pthread__unpark_all(self, &barrier->ptb_lock, barrier, &barrier->ptb_waiters); -#endif return PTHREAD_BARRIER_SERIAL_THREAD; } @@ -193,26 +177,8 @@ pthread_barrier_wait(pthread_barrier_t *barrier) while (gen == barrier->ptb_generation) { SDPRINTF(("(barrier wait %p) Waiting on %p\n", self, barrier)); - -#ifdef PTHREAD_SA - pthread_spinlock(self, &self->pt_statelock); - - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = barrier; - self->pt_sleepq = &barrier->ptb_waiters; - self->pt_sleeplock = &barrier->ptb_lock; - - pthread_spinunlock(self, &self->pt_statelock); - - PTQ_INSERT_TAIL(&barrier->ptb_waiters, self, pt_sleep); - - pthread__block(self, &barrier->ptb_lock); - /* Spinlock is unlocked on return */ - pthread_spinlock(self, &barrier->ptb_lock); -#else /* PTHREAD_SA */ (void)pthread__park(self, &barrier->ptb_lock, barrier, &barrier->ptb_waiters, NULL, 1, 0); -#endif /* PTHREAD_SA */ SDPRINTF(("(barrier wait %p) Woke up on %p\n", self, barrier)); } diff --git a/lib/libpthread/pthread_cond.c b/lib/libpthread/pthread_cond.c index f140a3b5ebf..0c1a16680fd 100644 --- a/lib/libpthread/pthread_cond.c +++ b/lib/libpthread/pthread_cond.c @@ -1,7 +1,7 @@ -/* $NetBSD: pthread_cond.c,v 1.21 2007/03/02 17:47:40 ad Exp $ */ +/* $NetBSD: pthread_cond.c,v 1.22 2007/03/02 18:53:52 ad Exp $ */ /*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. + * Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_cond.c,v 1.21 2007/03/02 17:47:40 ad Exp $"); +__RCSID("$NetBSD: pthread_cond.c,v 1.22 2007/03/02 18:53:52 ad Exp $"); #include <errno.h> #include <sys/time.h> @@ -56,9 +56,6 @@ int _sys_nanosleep(const struct timespec *, struct timespec *); extern int pthread__started; -#ifdef PTHREAD_SA -static void pthread_cond_wait__callback(void *); -#endif static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *, const struct timespec *); @@ -119,38 +116,6 @@ pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) if (__predict_false(pthread__started == 0)) return pthread_cond_wait_nothread(self, mutex, NULL); -#ifdef PTHREAD_SA - pthread_spinlock(self, &cond->ptc_lock); - SDPRINTF(("(cond wait %p) Waiting on %p, mutex %p\n", - self, cond, mutex)); - -#ifdef ERRORCHECK - if (cond->ptc_mutex == NULL) - cond->ptc_mutex = mutex; - else - pthread__error(EINVAL, - "Multiple mutexes used for condition wait", - cond->ptc_mutex == mutex); -#endif - - pthread_spinlock(self, &self->pt_statelock); - if (__predict_false(self->pt_cancel)) { - pthread_spinunlock(self, &self->pt_statelock); - pthread_spinunlock(self, &cond->ptc_lock); - pthread_exit(PTHREAD_CANCELED); - } - - self->pt_sleepobj = cond; - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepq = &cond->ptc_waiters; - self->pt_sleeplock = &cond->ptc_lock; - pthread_spinunlock(self, &self->pt_statelock); - PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep); - pthread_mutex_unlock(mutex); - - pthread__block(self, &cond->ptc_lock); - /* Spinlock is unlocked on return */ -#else /* PTHREAD_SA */ SDPRINTF(("(cond wait %p) Waiting on %p, mutex %p\n", self, cond, mutex)); if (__predict_false(self->pt_cancel)) @@ -168,7 +133,6 @@ pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) (void)pthread__park(self, &cond->ptc_lock, cond, &cond->ptc_waiters, NULL, 0, 1); pthread_spinunlock(self, &cond->ptc_lock); -#endif /* PTHREAD_SA */ pthread_mutex_lock(mutex); #ifdef ERRORCHECK @@ -198,9 +162,6 @@ pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, { pthread_t self; struct pthread_cond__waitarg wait; -#ifdef PTHREAD_SA - struct pt_alarm_t alarm; -#endif int retval; pthread__error(EINVAL, "Invalid condition variable", @@ -224,43 +185,6 @@ pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, wait.ptw_cond = cond; retval = 0; -#ifdef PTHREAD_SA - pthread_spinlock(self, &cond->ptc_lock); - SDPRINTF(("(cond timed wait %p) Waiting on %p until %d.%06ld\n", - self, cond, abstime->tv_sec, abstime->tv_nsec/1000)); - - pthread_spinlock(self, &self->pt_statelock); - if (__predict_false(self->pt_cancel)) { - pthread_spinunlock(self, &self->pt_statelock); - pthread_spinunlock(self, &cond->ptc_lock); - pthread_exit(PTHREAD_CANCELED); - } -#ifdef ERRORCHECK - if (cond->ptc_mutex == NULL) - cond->ptc_mutex = mutex; - else - pthread__error(EINVAL, - "Multiple mutexes used for condition wait", - cond->ptc_mutex == mutex); -#endif - - pthread__alarm_add(self, &alarm, abstime, pthread_cond_wait__callback, - &wait); - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = cond; - self->pt_sleepq = &cond->ptc_waiters; - self->pt_sleeplock = &cond->ptc_lock; - pthread_spinunlock(self, &self->pt_statelock); - - PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep); - pthread_mutex_unlock(mutex); - - pthread__block(self, &cond->ptc_lock); - /* Spinlock is unlocked on return */ - pthread__alarm_del(self, &alarm); - if (pthread__alarm_fired(&alarm)) - retval = ETIMEDOUT; -#else /* PTHREAD_SA */ SDPRINTF(("(cond timed wait %p) Waiting on %p until %d.%06ld\n", self, cond, abstime->tv_sec, abstime->tv_nsec/1000)); @@ -279,7 +203,6 @@ pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, retval = pthread__park(self, &cond->ptc_lock, cond, &cond->ptc_waiters, abstime, 0, 1); pthread_spinunlock(self, &cond->ptc_lock); -#endif /* PTHREAD_SA */ SDPRINTF(("(cond timed wait %p) Woke up on %p, mutex %p\n", self, cond)); @@ -298,35 +221,6 @@ pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, return retval; } -#ifdef PTHREAD_SA -static void -pthread_cond_wait__callback(void *arg) -{ - struct pthread_cond__waitarg *a; - pthread_t self; - - a = arg; - self = pthread__self(); - - /* - * Don't dequeue and schedule the thread if it's already been - * queued up by a signal or broadcast (but hasn't yet run as far - * as pthread__alarm_del(), or we wouldn't be here, and hence can't - * have become blocked on some *other* queue). - */ - pthread_spinlock(self, &a->ptw_cond->ptc_lock); - if (a->ptw_thread->pt_state == PT_STATE_BLOCKED_QUEUE) { - PTQ_REMOVE(&a->ptw_cond->ptc_waiters, a->ptw_thread, pt_sleep); -#ifdef ERRORCHECK - if (PTQ_EMPTY(&a->ptw_cond->ptc_waiters)) - a->ptw_cond->ptc_mutex = NULL; -#endif - pthread__sched(self, a->ptw_thread); - } - pthread_spinunlock(self, &a->ptw_cond->ptc_lock); -} -#endif /* PTHREAD_SA */ - int pthread_cond_signal(pthread_cond_t *cond) { @@ -339,23 +233,6 @@ pthread_cond_signal(pthread_cond_t *cond) SDPRINTF(("(cond signal %p) Signaling %p\n", pthread__self(), cond)); -#ifdef PTHREAD_SA - if (!PTQ_EMPTY(&cond->ptc_waiters)) { - self = pthread__self(); - pthread_spinlock(self, &cond->ptc_lock); - signaled = PTQ_FIRST(&cond->ptc_waiters); - if (signaled != NULL) { - PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep); - pthread__sched(self, signaled); - PTHREADD_ADD(PTHREADD_COND_WOKEUP); - } -#ifdef ERRORCHECK - if (PTQ_EMPTY(&cond->ptc_waiters)) - cond->ptc_mutex = NULL; -#endif - pthread_spinunlock(self, &cond->ptc_lock); - } -#else /* PTHREAD_SA */ if (!PTQ_EMPTY(&cond->ptc_waiters)) { self = pthread__self(); pthread_spinlock(self, &cond->ptc_lock); @@ -375,7 +252,7 @@ pthread_cond_signal(pthread_cond_t *cond) pthread_spinunlock(self, &cond->ptc_lock); } } -#endif + return 0; } @@ -384,9 +261,6 @@ int pthread_cond_broadcast(pthread_cond_t *cond) { pthread_t self; -#ifdef PTHREAD_SA - struct pthread_queue_t blockedq; -#endif pthread__error(EINVAL, "Invalid condition variable", cond->ptc_magic == _PT_COND_MAGIC); @@ -400,16 +274,8 @@ pthread_cond_broadcast(pthread_cond_t *cond) #ifdef ERRORCHECK cond->ptc_mutex = NULL; #endif -#ifdef PTHREAD_SA - blockedq = cond->ptc_waiters; - PTQ_INIT(&cond->ptc_waiters); - pthread__sched_sleepers(self, &blockedq); - PTHREADD_ADD(PTHREADD_COND_WOKEUP); - pthread_spinunlock(self, &cond->ptc_lock); -#else /* PTHREAD_SA */ pthread__unpark_all(self, &cond->ptc_lock, cond, &cond->ptc_waiters); PTHREADD_ADD(PTHREADD_COND_WOKEUP); -#endif /* PTHREAD_SA */ } return 0; diff --git a/lib/libpthread/pthread_debug.c b/lib/libpthread/pthread_debug.c index 283a04a2dce..cd61d7316b5 100644 --- a/lib/libpthread/pthread_debug.c +++ b/lib/libpthread/pthread_debug.c @@ -1,7 +1,7 @@ -/* $NetBSD: pthread_debug.c,v 1.11 2007/01/20 18:57:41 christos Exp $ */ +/* $NetBSD: pthread_debug.c,v 1.12 2007/03/02 18:53:52 ad Exp $ */ /*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. + * Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_debug.c,v 1.11 2007/01/20 18:57:41 christos Exp $"); +__RCSID("$NetBSD: pthread_debug.c,v 1.12 2007/03/02 18:53:52 ad Exp $"); #include <err.h> #include <errno.h> @@ -160,15 +160,7 @@ pthread__debuglog_printf(const char *fmt, ...) if (debugbuf == NULL || linebuf == NULL) return; -#ifdef PTHREAD_SA - if (pthread__maxconcurrency > 1) { - vpid = pthread_self()->pt_vpid; - } else - vpid = 0; -#else vpid = (int)_lwp_self(); -#endif - tmpbuf = linebuf[vpid].buf; len = linebuf[vpid].len; @@ -236,15 +228,9 @@ pthread__debuglog_newline(void) if (debugbuf == NULL) return 1; -#ifdef PTHREAD_SA - if (pthread__maxconcurrency > 1) - vpid = pthread_self()->pt_vpid; - else - vpid = 0; -#else vpid = (int)_lwp_self(); -#endif - return (linebuf[vpid].len == 0); } -#endif + +#endif /* PTHREAD__DEBUG */ + diff --git a/lib/libpthread/pthread_debug.h b/lib/libpthread/pthread_debug.h index 55942808720..b437e9e165a 100644 --- a/lib/libpthread/pthread_debug.h +++ b/lib/libpthread/pthread_debug.h @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_debug.h,v 1.8 2004/03/14 01:19:42 cl Exp $ */ +/* $NetBSD: pthread_debug.h,v 1.9 2007/03/02 18:53:52 ad Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -114,13 +114,9 @@ int pthread__debuglog_newline(void); #undef PTHREAD_ALARM_DEBUG #undef PTHREAD_COND_DEBUG #define PTHREAD_MAIN_DEBUG -#undef PTHREAD_RUN_DEBUG #undef PTHREAD_PID_DEBUG -#define PTHREAD_SA_DEBUG -#undef PTHREAD_SIG_DEBUG #define PTHREAD_SPIN_DEBUG #undef PTHREAD_SPIN_DEBUG_PRINT -#undef PTHREAD_VP_DEBUG extern int pthread__debug_counters[PTHREADD_NCOUNTERS]; diff --git a/lib/libpthread/pthread_int.h b/lib/libpthread/pthread_int.h index 17572eb93a4..d05a0b1f8b8 100644 --- a/lib/libpthread/pthread_int.h +++ b/lib/libpthread/pthread_int.h @@ -1,11 +1,11 @@ -/* $NetBSD: pthread_int.h,v 1.37 2007/02/06 15:24:37 ad Exp $ */ +/* $NetBSD: pthread_int.h,v 1.38 2007/03/02 18:53:52 ad Exp $ */ /*- - * Copyright (c) 2001,2002,2003 The NetBSD Foundation, Inc. + * Copyright (c) 2001, 2002, 2003, 2006, 2007 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. + * by Nathan J. Williams and Andrew Doran. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,12 +47,7 @@ #include "pthread_debug.h" #include "pthread_md.h" -#ifndef PTHREAD_SA #include <lwp.h> -#else -#include <sa.h> -#endif - #include <signal.h> #define PTHREAD_KEYS_MAX 256 @@ -66,15 +61,6 @@ struct pt_clean_t { void *ptc_arg; }; -struct pt_alarm_t { - PTQ_ENTRY(pt_alarm_t) pta_next; - pthread_spin_t pta_lock; - const struct timespec *pta_time; - void (*pta_func)(void *); - void *pta_arg; - int pta_fired; -}; - /* Private data for pthread_attr_t */ struct pthread_attr_private { char ptap_name[PTHREAD_MAX_NAMELEN_NP]; @@ -89,30 +75,16 @@ struct __pthread_st { /* Identifier, for debugging and for preventing recycling. */ int pt_num; -#ifdef PTHREAD_SA - int pt_type; /* normal, upcall, or idle */ -#else lwpid_t pt_lid; /* LWP ID */ -#endif int pt_state; /* running, blocked, etc. */ pthread_spin_t pt_statelock; /* lock on pt_state */ int pt_flags; /* see PT_FLAG_* below */ pthread_spin_t pt_flaglock; /* lock on pt_flag */ int pt_cancel; /* Deferred cancellation */ int pt_spinlocks; /* Number of spinlocks held. */ - int pt_blockedlwp; /* LWP/SA number when blocked */ - int pt_vpid; /* VP number */ - int pt_blockgen; /* SA_UPCALL_BLOCKED counter */ -#ifdef PTHREAD_SA - int pt_unblockgen; /* SA_UPCALL_UNBLOCKED counter */ -#else int pt_sleeponq; /* on a sleep queue */ -#endif - int pt_errno; /* Thread-specific errno. */ - /* Entry on the run queue */ - PTQ_ENTRY(__pthread_st) pt_runq; /* Entry on the list of all threads */ PTQ_ENTRY(__pthread_st) pt_allq; /* Entry on the sleep queue (xxx should be same as run queue?) */ @@ -125,29 +97,15 @@ struct __pthread_st { void *pt_sleepobj; /* Queue we're sleeping on */ struct pthread_queue_t *pt_sleepq; - /* Lock protecting that queue */ - pthread_spin_t *pt_sleeplock; stack_t pt_stack; /* Our stack */ ucontext_t *pt_uc; /* Saved context when we're stopped */ - ucontext_t *pt_trapuc; /* Kernel-saved context */ - ucontext_t *__pt_blockuc; /* Kernel-saved context when blocked */ - - sigset_t pt_sigmask; /* Signals we won't take. */ - sigset_t pt_siglist; /* Signals pending for us. */ - sigset_t pt_sigblocked; /* Signals delivered while blocked. */ - sigset_t *pt_sigwait; /* Signals waited for in sigwait */ - siginfo_t *pt_wsig; - pthread_spin_t pt_siglock; /* Lock on above */ - - void * pt_exitval; /* Read by pthread_join() */ + void *pt_exitval; /* Read by pthread_join() */ + char *pt_name; /* Thread's name, set by the app. */ /* Stack of cancellation cleanup handlers and their arguments */ PTQ_HEAD(, pt_clean_t) pt_cleanup_stack; - /* Thread's name, set by the application. */ - char* pt_name; - /* Other threads trying to pthread_join() us. */ struct pthread_queue_t pt_joiners; /* Lock for above, and for changing pt_state to ZOMBIE or DEAD, @@ -155,42 +113,8 @@ struct __pthread_st { */ pthread_spin_t pt_join_lock; - /* Thread we were going to switch to before we were preempted - * ourselves. Will be used by the upcall that's continuing us. - */ - pthread_t pt_switchto; - ucontext_t* pt_switchtouc; - - /* Threads that are preempted with spinlocks held will be - * continued until they unlock their spinlock. When they do - * so, they should jump ship to the thread pointed to by - * pt_next. - */ - pthread_t pt_next; - - /* The upcall that is continuing this thread */ - pthread_t pt_parent; - - /* A queue lock that this thread held while trying to - * context switch to another process. - */ - pthread_spin_t* pt_heldlock; - -#ifdef PTHREAD_SA - /* Upcall stack information shared between kernel and - * userland. - */ - struct sa_stackinfo_t pt_stackinfo; -#endif - /* Thread-specific data */ void* pt_specific[PTHREAD_KEYS_MAX]; - -#ifdef PTHREAD__DEBUG - int blocks; - int preempts; - int rescheds; -#endif }; struct pthread_lock_ops { @@ -199,43 +123,20 @@ struct pthread_lock_ops { void (*plo_unlock)(__cpu_simple_lock_t *); }; -#ifdef PTHREAD_SA - -/* Thread types */ -#define PT_THREAD_NORMAL 1 -#define PT_THREAD_UPCALL 2 -#define PT_THREAD_IDLE 3 - -/* Thread states */ -#define PT_STATE_RUNNING 1 -#define PT_STATE_RUNNABLE 2 -#define _PT_STATE_BLOCKED_SYS 3 /* Only used in libpthread_dbg */ -#define PT_STATE_BLOCKED_QUEUE 4 -#define PT_STATE_ZOMBIE 5 -#define PT_STATE_DEAD 6 -#define PT_STATE_SUSPENDED 7 - -#else /* PTHREAD_SA */ - /* Thread states */ #define PT_STATE_RUNNING 1 #define PT_STATE_ZOMBIE 5 #define PT_STATE_DEAD 6 -#endif /* PTHREAD_SA */ - /* Flag values */ #define PT_FLAG_DETACHED 0x0001 -#define PT_FLAG_IDLED 0x0002 #define PT_FLAG_CS_DISABLED 0x0004 /* Cancellation disabled */ #define PT_FLAG_CS_ASYNC 0x0008 /* Cancellation is async */ #define PT_FLAG_CS_PENDING 0x0010 -#define PT_FLAG_SIGDEFERRED 0x0020 /* There are signals to take */ #define PT_FLAG_SCOPE_SYSTEM 0x0040 #define PT_FLAG_EXPLICIT_SCHED 0x0080 #define PT_FLAG_SUSPENDED 0x0100 /* In the suspended queue */ -#define PT_FLAG_SIGNALED 0x0200 #define PT_MAGIC 0x11110001 #define PT_DEAD 0xDEAD0001 @@ -261,13 +162,6 @@ extern vaddr_t pthread_stackmask; #endif /* PT_FIXEDSTACKSIZE_LG */ - -#define PT_UPCALLSTACKS 16 - -#define PT_ALARMTIMER_MAGIC 0x88880010 -#define PT_RRTIMER_MAGIC 0x88880020 -#define NIDLETHREADS 4 - /* Flag to be used in a ucontext_t's uc_flags indicating that * the saved register state is "user" state only, not full * trap state. @@ -284,24 +178,6 @@ void pthread__initthread(pthread_t self, pthread_t t); /* Get offset from stack start to struct sa_stackinfo */ ssize_t pthread__stackinfo_offset(void); -/* Go do something else. Don't go back on the run queue */ -void pthread__block(pthread_t self, pthread_spin_t* queuelock); -/* Put a thread back on the suspended queue */ -void pthread__suspend(pthread_t self, pthread_t thread); -/* Put a thread back on the run queue */ -void pthread__sched(pthread_t self, pthread_t thread); -void pthread__sched_sleepers(pthread_t self, struct pthread_queue_t *threadq); -void pthread__sched_idle(pthread_t self, pthread_t thread); -void pthread__sched_idle2(pthread_t self); - -void pthread__sched_bulk(pthread_t self, pthread_t qhead); - -void pthread__idle(void); - -/* Get the next thread */ -pthread_t pthread__next(pthread_t self); - -#ifndef PTHREAD_SA void pthread__unpark_all(pthread_t self, pthread_spin_t *lock, void *obj, struct pthread_queue_t *threadq); void pthread__unpark(pthread_t self, pthread_spin_t *lock, @@ -310,23 +186,10 @@ int pthread__park(pthread_t self, pthread_spin_t *lock, void *obj, struct pthread_queue_t *threadq, const struct timespec *abs_timeout, int tail, int cancelpt); -#endif int pthread__stackalloc(pthread_t *t); void pthread__initmain(pthread_t *t); -void pthread__sa_start(void); -void pthread__sa_recycle(pthread_t old, pthread_t new); -void pthread__setconcurrency(int); - -/* Alarm code */ -void pthread__alarm_init(void); -void pthread__alarm_add(pthread_t, struct pt_alarm_t *, - const struct timespec *, void (*)(void *), void *); -void pthread__alarm_del(pthread_t, struct pt_alarm_t *); -int pthread__alarm_fired(struct pt_alarm_t *); -void pthread__alarm_process(pthread_t self, void *arg); - /* Internal locking primitives */ void pthread__lockprim_init(int ncpu); void pthread_lockinit(pthread_spin_t *lock); @@ -393,21 +256,6 @@ int pthread__find(pthread_t self, pthread_t target); } \ } while (/*CONSTCOND*/0) - - -/* These three routines are defined in processor-specific code. */ -void pthread__upcall_switch(pthread_t self, pthread_t next); -void pthread__switch(pthread_t self, pthread_t next); -void pthread__locked_switch(pthread_t self, pthread_t next, - pthread_spin_t *lock); - -void pthread__signal_init(void); -void pthread__signal_start(void); - -void pthread__signal(pthread_t self, pthread_t t, siginfo_t *si); -void pthread__deliver_signal(pthread_t self, pthread_t t, siginfo_t *si); -void pthread__signal_deferred(pthread_t self, pthread_t t); - void pthread__destroy_tsd(pthread_t self); void pthread__assertfunc(const char *file, int line, const char *function, const char *expr); diff --git a/lib/libpthread/pthread_lock.c b/lib/libpthread/pthread_lock.c index 007f86402a8..d246abc7b9d 100644 --- a/lib/libpthread/pthread_lock.c +++ b/lib/libpthread/pthread_lock.c @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_lock.c,v 1.17 2007/03/02 17:34:21 ad Exp $ */ +/* $NetBSD: pthread_lock.c,v 1.18 2007/03/02 18:53:52 ad Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_lock.c,v 1.17 2007/03/02 17:34:21 ad Exp $"); +__RCSID("$NetBSD: pthread_lock.c,v 1.18 2007/03/02 18:53:52 ad Exp $"); #include <sys/types.h> #include <sys/lock.h> @@ -195,16 +195,8 @@ pthread_spinlock(pthread_t thread, pthread_spin_t *lock) * (in case (a), we should let the code finish and * we will bail out in pthread_spinunlock()). */ -#ifdef PTHREAD_SA - if (thread->pt_next != NULL) { - PTHREADD_ADD(PTHREADD_SPINPREEMPT); - pthread__assert(thread->pt_blockgen == thread->pt_unblockgen); - pthread__switch(thread, thread->pt_next); - } -#else /* XXXLWP far from ideal */ sched_yield(); -#endif /* try again */ count = pthread__nspins; SDPRINTF(("(pthread_spinlock %p) incrementing spinlock from %d\n", @@ -224,24 +216,11 @@ pthread_spintrylock(pthread_t thread, pthread_spin_t *lock) SDPRINTF(("(pthread_spinlock %p) incrementing spinlock from %d\n", thread, thread->pt_spinlocks)); - ++thread->pt_spinlocks; + ++thread->pt_spinlocks; ret = pthread__simple_lock_try(lock); - -#ifdef PTHREAD_SA - if (ret == 0) { - SDPRINTF(("(pthread_spintrylock %p) decrementing spinlock from %d\n", - thread, thread->pt_spinlocks)); + if (!ret) --thread->pt_spinlocks; - /* See above. */ - if (thread->pt_next != NULL) { - PTHREADD_ADD(PTHREADD_SPINPREEMPT); - pthread__assert(thread->pt_blockgen == thread->pt_unblockgen); - pthread__switch(thread, thread->pt_next); - } - } -#endif - return ret; } @@ -258,22 +237,6 @@ pthread_spinunlock(pthread_t thread, pthread_spin_t *lock) pthread__assert(thread->pt_spinlocks >= 0); #endif PTHREADD_ADD(PTHREADD_SPINUNLOCKS); - -#ifdef PTHREAD_SA - /* - * If we were preempted while holding a spinlock, the - * scheduler will notice this and continue us. To be good - * citzens, we must now get out of here if that was our - * last spinlock. - * XXX when will we ever have more than one? - */ - - if ((thread->pt_spinlocks == 0) && (thread->pt_next != NULL)) { - PTHREADD_ADD(PTHREADD_SPINPREEMPT); - /* pthread__assert(thread->pt_blockgen == thread->pt_unblockgen); */ - pthread__switch(thread, thread->pt_next); - } -#endif } diff --git a/lib/libpthread/pthread_misc.c b/lib/libpthread/pthread_misc.c new file mode 100644 index 00000000000..5e3ef1313e7 --- /dev/null +++ b/lib/libpthread/pthread_misc.c @@ -0,0 +1,114 @@ +/* $NetBSD: pthread_misc.c,v 1.1 2007/03/02 18:53:52 ad Exp $ */ + +/*- + * Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nathan J. Williams. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: pthread_misc.c,v 1.1 2007/03/02 18:53:52 ad Exp $"); + +#include <sys/types.h> +#include <sys/signal.h> +#include <sys/time.h> + +#include <errno.h> +#include <lwp.h> + +#include "pthread.h" +#include "pthread_int.h" + +int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); +int _sys_nanosleep(const struct timespec *, struct timespec *); + +__strong_alias(_nanosleep, nanosleep) +__strong_alias(__libc_thr_sigsetmask,pthread_sigmask) +__strong_alias(__sigprocmask14,pthread_sigmask) +__strong_alias(__libc_thr_yield,_sys_sched_yield) + +/*ARGSUSED*/ +int +pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param) +{ + if (param == NULL || policy == NULL) + return EINVAL; + param->sched_priority = 0; + *policy = SCHED_RR; + return 0; +} + +/*ARGSUSED*/ +int +pthread_setschedparam(pthread_t thread, int policy, + const struct sched_param *param) +{ + if (param == NULL || policy < SCHED_FIFO || policy > SCHED_RR) + return EINVAL; + if (param->sched_priority > 0 || policy != SCHED_RR) + return ENOTSUP; + return 0; +} + +int +pthread_kill(pthread_t thread, int sig) +{ + pthread_t self; + + self = pthread__self(); + + if ((sig < 0) || (sig >= _NSIG)) + return EINVAL; + if (pthread__find(self, thread) != 0) + return ESRCH; + + return _lwp_kill(thread->pt_lid, sig); +} + +int +pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + + return _sys___sigprocmask14(how, set, oset); +} + +int +nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + + /* + * For now, just nanosleep. In the future, maybe pass a ucontext_t + * to _lwp_nanosleep() and allow it to recycle our kernel stack. + */ + return _sys_nanosleep(rqtp, rmtp); +} diff --git a/lib/libpthread/pthread_mutex.c b/lib/libpthread/pthread_mutex.c index ed192a3695d..17799a10079 100644 --- a/lib/libpthread/pthread_mutex.c +++ b/lib/libpthread/pthread_mutex.c @@ -1,7 +1,7 @@ -/* $NetBSD: pthread_mutex.c,v 1.24 2006/12/24 18:39:46 ad Exp $ */ +/* $NetBSD: pthread_mutex.c,v 1.25 2007/03/02 18:53:52 ad Exp $ */ /*- - * Copyright (c) 2001, 2003 The NetBSD Foundation, Inc. + * Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_mutex.c,v 1.24 2006/12/24 18:39:46 ad Exp $"); +__RCSID("$NetBSD: pthread_mutex.c,v 1.25 2007/03/02 18:53:52 ad Exp $"); #include <errno.h> #include <limits.h> @@ -267,21 +267,9 @@ pthread_mutex_lock_slow(pthread_mutex_t *mutex) * but it's okay since we're just going to * retry. */ -#ifdef PTHREAD_SA - pthread_spinlock(self, &self->pt_statelock); - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = mutex; - self->pt_sleepq = &mutex->ptm_blocked; - self->pt_sleeplock = &mutex->ptm_interlock; - pthread_spinunlock(self, &self->pt_statelock); - - pthread__block(self, &mutex->ptm_interlock); - /* interlock is not held when we return */ -#else /* PTHREAD_SA */ (void)pthread__park(self, &mutex->ptm_interlock, mutex, NULL, NULL, 0, 0); pthread_spinunlock(self, &mutex->ptm_interlock); -#endif /* PTHREAD_SA */ } else { PTQ_REMOVE(&mutex->ptm_blocked, self, pt_sleep); pthread_spinunlock(self, &mutex->ptm_interlock); @@ -389,13 +377,7 @@ pthread_mutex_unlock(pthread_mutex_t *mutex) if ((blocked = PTQ_FIRST(&mutex->ptm_blocked)) != NULL) { PTQ_REMOVE(&mutex->ptm_blocked, blocked, pt_sleep); PTHREADD_ADD(PTHREADD_MUTEX_UNLOCK_UNBLOCK); -#ifdef PTHREAD_SA - /* Give the head of the blocked queue another try. */ - pthread__sched(self, blocked); - pthread_spinunlock(self, &mutex->ptm_interlock); -#else /* PTHREAD_SA */ pthread__unpark(self, &mutex->ptm_interlock, mutex, blocked); -#endif /* PTHREAD_SA */ } else pthread_spinunlock(self, &mutex->ptm_interlock); diff --git a/lib/libpthread/pthread_run.c b/lib/libpthread/pthread_run.c deleted file mode 100644 index 0b18d5bda51..00000000000 --- a/lib/libpthread/pthread_run.c +++ /dev/null @@ -1,332 +0,0 @@ -/* $NetBSD: pthread_run.c,v 1.23 2007/01/20 18:00:15 christos Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_run.c,v 1.23 2007/01/20 18:00:15 christos Exp $"); - -#include <ucontext.h> -#include <errno.h> - -#include "pthread.h" -#include "pthread_int.h" - -#ifdef PTHREAD_RUN_DEBUG -#define SDPRINTF(x) DPRINTF(x) -#else -#define SDPRINTF(x) -#endif - -#ifdef PTHREAD_SA - -extern pthread_spin_t pthread__runqueue_lock; -extern struct pthread_queue_t pthread__runqueue; -extern struct pthread_queue_t pthread__idlequeue; -extern struct pthread_queue_t pthread__suspqueue; - -extern pthread_spin_t pthread__deadqueue_lock; -extern struct pthread_queue_t *pthread__reidlequeue; - -extern int pthread__concurrency, pthread__maxconcurrency; - -__strong_alias(__libc_thr_yield,sched_yield) - -int -sched_yield(void) -{ - pthread_t self, next; - extern int pthread__started; - - if (pthread__started) { - self = pthread__self(); - SDPRINTF(("(sched_yield %p) yielding\n", self)); - pthread_spinlock(self, &pthread__runqueue_lock); - self->pt_state = PT_STATE_RUNNABLE; - PTQ_INSERT_TAIL(&pthread__runqueue, self, pt_runq); - /* - * There will always be at least one thread on the runqueue, - * because we just put ourselves there. - */ - next = PTQ_FIRST(&pthread__runqueue); - PTQ_REMOVE(&pthread__runqueue, next, pt_runq); - next->pt_state = PT_STATE_RUNNING; - if (next != self) { - next->pt_vpid = self->pt_vpid; - pthread__locked_switch(self, next, - &pthread__runqueue_lock); - } else - pthread_spinunlock(self, &pthread__runqueue_lock); - } - - return 0; -} - - -/* Go do another thread, without putting us on the run queue. */ -void -pthread__block(pthread_t self, pthread_spin_t *queuelock) -{ - pthread_t next; - - next = pthread__next(self); - next->pt_state = PT_STATE_RUNNING; - SDPRINTF(("(calling locked_switch %p, %p) spinlock %d, %d\n", - self, next, self->pt_spinlocks, next->pt_spinlocks)); - pthread__locked_switch(self, next, queuelock); - SDPRINTF(("(back from locked_switch %p, %p) spinlock %d, %d\n", - self, next, self->pt_spinlocks, next->pt_spinlocks)); -} - - -/* Get the next thread to switch to. Will never return NULL. */ -pthread_t -pthread__next(pthread_t self) -{ - pthread_t next; - - pthread_spinlock(self, &pthread__runqueue_lock); - next = PTQ_FIRST(&pthread__runqueue); - if (next) { - pthread__assert(next->pt_type == PT_THREAD_NORMAL); - PTQ_REMOVE(&pthread__runqueue, next, pt_runq); - SDPRINTF(("(next %p) returning thread %p\n", self, next)); - if (pthread__maxconcurrency > pthread__concurrency && - PTQ_FIRST(&pthread__runqueue)) - pthread__setconcurrency(1); - } else { - next = PTQ_FIRST(&pthread__idlequeue); - pthread__assert(next != 0); - PTQ_REMOVE(&pthread__idlequeue, next, pt_runq); - pthread__assert(next->pt_type == PT_THREAD_IDLE); - SDPRINTF(("(next %p) returning idle thread %p\n", self, next)); - } - next->pt_vpid = self->pt_vpid; - pthread_spinunlock(self, &pthread__runqueue_lock); - - return next; -} - - -/* Put a thread on the suspended queue */ -void -pthread__suspend(pthread_t self, pthread_t thread) -{ - - SDPRINTF(("(sched %p) suspending %p\n", self, thread)); - thread->pt_state = PT_STATE_SUSPENDED; - pthread__assert(thread->pt_type == PT_THREAD_NORMAL); - pthread__assert(thread->pt_spinlocks == 0); - pthread_spinlock(self, &pthread__runqueue_lock); - PTQ_INSERT_TAIL(&pthread__suspqueue, thread, pt_runq); - pthread_spinunlock(self, &pthread__runqueue_lock); - /* XXX flaglock? */ - thread->pt_flags &= ~PT_FLAG_SUSPENDED; -} - -/* Put a thread back on the run queue */ -void -pthread__sched(pthread_t self, pthread_t thread) -{ - - SDPRINTF(("(sched %p) scheduling %p\n", self, thread)); - thread->pt_state = PT_STATE_RUNNABLE; - pthread__assert(thread->pt_type == PT_THREAD_NORMAL); - pthread__assert(thread->pt_spinlocks == 0); -#ifdef PTHREAD__DEBUG - thread->rescheds++; -#endif - pthread__assert(PTQ_LAST(&pthread__runqueue, pthread_queue_t) != thread); - pthread__assert(PTQ_FIRST(&pthread__runqueue) != thread); - pthread_spinlock(self, &pthread__runqueue_lock); - PTQ_INSERT_TAIL(&pthread__runqueue, thread, pt_runq); - pthread_spinunlock(self, &pthread__runqueue_lock); -} - -/* Put a bunch of sleeping threads on the run queue */ -void -pthread__sched_sleepers(pthread_t self, struct pthread_queue_t *threadq) -{ - pthread_t thread; - - pthread_spinlock(self, &pthread__runqueue_lock); - PTQ_FOREACH(thread, threadq, pt_sleep) { - SDPRINTF(("(sched_sleepers %p) scheduling %p\n", self, thread)); - thread->pt_state = PT_STATE_RUNNABLE; - pthread__assert(thread->pt_type == PT_THREAD_NORMAL); - pthread__assert(thread->pt_spinlocks == 0); -#ifdef PTHREAD__DEBUG - thread->rescheds++; -#endif - PTQ_INSERT_TAIL(&pthread__runqueue, thread, pt_runq); - } - pthread_spinunlock(self, &pthread__runqueue_lock); -} - - -/* Make a thread a candidate idle thread. */ -void -pthread__sched_idle(pthread_t self, pthread_t thread) -{ - - SDPRINTF(("(sched_idle %p) idling %p\n", self, thread)); - thread->pt_state = PT_STATE_RUNNABLE; - - thread->pt_flags &= ~PT_FLAG_IDLED; - thread->pt_trapuc = NULL; - _INITCONTEXT_U(thread->pt_uc); - thread->pt_uc->uc_stack = thread->pt_stack; - thread->pt_uc->uc_link = NULL; - makecontext(thread->pt_uc, pthread__idle, 0); - - pthread_spinlock(self, &pthread__runqueue_lock); - PTQ_INSERT_TAIL(&pthread__idlequeue, thread, pt_runq); - pthread_spinunlock(self, &pthread__runqueue_lock); -} - - -void -pthread__sched_idle2(pthread_t self) -{ - pthread_t idlethread, qhead, next; - - qhead = NULL; - pthread_spinlock(self, &pthread__deadqueue_lock); - idlethread = PTQ_FIRST(&pthread__reidlequeue[self->pt_vpid]); - while (idlethread != NULL) { - SDPRINTF(("(sched_idle2 %p) reidling %p\n", self, idlethread)); - next = PTQ_NEXT(idlethread, pt_runq); - if ((idlethread->pt_next == NULL) && - (idlethread->pt_blockgen == idlethread->pt_unblockgen)) { - PTQ_REMOVE(&pthread__reidlequeue[self->pt_vpid], - idlethread, pt_runq); - idlethread->pt_next = qhead; - qhead = idlethread; - - pthread__concurrency++; - SDPRINTF(("(sched_idle2 %p concurrency) now %d from %p\n", - self, pthread__concurrency, idlethread)); - pthread__assert(pthread__concurrency <= - pthread__maxconcurrency); - - } else { - SDPRINTF(("(sched_idle2 %p) %p is in a preemption loop\n", self, idlethread)); - } - idlethread = next; - } - pthread_spinunlock(self, &pthread__deadqueue_lock); - - if (qhead) - pthread__sched_bulk(self, qhead); -} - -/* - * Put a series of threads, linked by their pt_next fields, onto the - * run queue. - */ -void -pthread__sched_bulk(pthread_t self, pthread_t qh) -{ - pthread_t next; - pthread_t volatile qhead = qh; - - pthread_spinlock(self, &pthread__runqueue_lock); - for ( ; qhead && (qhead != self) ; qhead = next) { - next = qhead->pt_next; - pthread__assert(qhead->pt_spinlocks == 0); - pthread__assert(qhead->pt_type != PT_THREAD_UPCALL); - if (qhead->pt_unblockgen != qhead->pt_blockgen) - qhead->pt_unblockgen++; - if (qhead->pt_type == PT_THREAD_NORMAL) { - qhead->pt_state = PT_STATE_RUNNABLE; - qhead->pt_next = NULL; - qhead->pt_parent = NULL; -#ifdef PTHREAD__DEBUG - qhead->rescheds++; -#endif - SDPRINTF(("(bulk %p) scheduling %p\n", self, qhead)); - pthread__assert(PTQ_LAST(&pthread__runqueue, pthread_queue_t) != qhead); - pthread__assert(PTQ_FIRST(&pthread__runqueue) != qhead); - if (qhead->pt_flags & PT_FLAG_SUSPENDED) { - qhead->pt_state = PT_STATE_SUSPENDED; - PTQ_INSERT_TAIL(&pthread__suspqueue, qhead, pt_runq); - } else - PTQ_INSERT_TAIL(&pthread__runqueue, qhead, pt_runq); - } else if (qhead->pt_type == PT_THREAD_IDLE) { - qhead->pt_state = PT_STATE_RUNNABLE; - qhead->pt_flags &= ~PT_FLAG_IDLED; - qhead->pt_next = NULL; - qhead->pt_parent = NULL; - qhead->pt_trapuc = NULL; - _INITCONTEXT_U(qhead->pt_uc); - qhead->pt_uc->uc_stack = qhead->pt_stack; - qhead->pt_uc->uc_link = NULL; - makecontext(qhead->pt_uc, pthread__idle, 0); - SDPRINTF(("(bulk %p) idling %p\n", self, qhead)); - PTQ_INSERT_TAIL(&pthread__idlequeue, qhead, pt_runq); - } - } - pthread_spinunlock(self, &pthread__runqueue_lock); -} - -#else /* PTHREAD_SA */ - -__strong_alias(__libc_thr_yield,_sys_sched_yield) - -#endif /* PTHREAD_SA */ - -/*ARGSUSED*/ -int -pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param) -{ - if (param == NULL || policy == NULL) - return EINVAL; - param->sched_priority = 0; - *policy = SCHED_RR; - return 0; -} - -/*ARGSUSED*/ -int -pthread_setschedparam(pthread_t thread, int policy, - const struct sched_param *param) -{ - if (param == NULL || policy < SCHED_FIFO || policy > SCHED_RR) - return EINVAL; - if (param->sched_priority > 0 || policy != SCHED_RR) - return ENOTSUP; - return 0; -} diff --git a/lib/libpthread/pthread_rwlock.c b/lib/libpthread/pthread_rwlock.c index 050d40ee8db..f6edf5e838e 100644 --- a/lib/libpthread/pthread_rwlock.c +++ b/lib/libpthread/pthread_rwlock.c @@ -1,7 +1,7 @@ -/* $NetBSD: pthread_rwlock.c,v 1.15 2006/12/24 18:39:46 ad Exp $ */ +/* $NetBSD: pthread_rwlock.c,v 1.16 2007/03/02 18:53:53 ad Exp $ */ /*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. + * Copyright (c) 2002, 2006, 2007 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,17 +37,13 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_rwlock.c,v 1.15 2006/12/24 18:39:46 ad Exp $"); +__RCSID("$NetBSD: pthread_rwlock.c,v 1.16 2007/03/02 18:53:53 ad Exp $"); #include <errno.h> #include "pthread.h" #include "pthread_int.h" -#ifdef PTHREAD_SA -static void pthread_rwlock__callback(void *); -#endif - __strong_alias(__libc_rwlock_init,pthread_rwlock_init) __strong_alias(__libc_rwlock_rdlock,pthread_rwlock_rdlock) __strong_alias(__libc_rwlock_wrlock,pthread_rwlock_wrlock) @@ -118,22 +114,8 @@ pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) */ while ((rwlock->ptr_writer != NULL) || (!PTQ_EMPTY(&rwlock->ptr_wblocked))) { -#ifdef PTHREAD_SA - PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep); - /* Locking a rwlock is not a cancellation point; don't check */ - pthread_spinlock(self, &self->pt_statelock); - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = rwlock; - self->pt_sleepq = &rwlock->ptr_rblocked; - self->pt_sleeplock = &rwlock->ptr_interlock; - pthread_spinunlock(self, &self->pt_statelock); - pthread__block(self, &rwlock->ptr_interlock); - /* interlock is not held when we return */ - pthread_spinlock(self, &rwlock->ptr_interlock); -#else /* PTHREAD_SA */ (void)pthread__park(self, &rwlock->ptr_interlock, rwlock, &rwlock->ptr_rblocked, NULL, 1, 0); -#endif /* PTHREAD_SA */ } rwlock->ptr_nreaders++; @@ -202,22 +184,8 @@ pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) return EDEADLK; } #endif -#ifdef PTHREAD_SA - PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep); - /* Locking a rwlock is not a cancellation point; don't check */ - pthread_spinlock(self, &self->pt_statelock); - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = rwlock; - self->pt_sleepq = &rwlock->ptr_wblocked; - self->pt_sleeplock = &rwlock->ptr_interlock; - pthread_spinunlock(self, &self->pt_statelock); - pthread__block(self, &rwlock->ptr_interlock); - /* interlock is not held when we return */ - pthread_spinlock(self, &rwlock->ptr_interlock); -#else (void)pthread__park(self, &rwlock->ptr_interlock, rwlock, &rwlock->ptr_wblocked, NULL, 1, 0); -#endif } rwlock->ptr_writer = self; @@ -265,10 +233,6 @@ pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abs_timeout) { pthread_t self; -#ifdef PTHREAD_SA - struct pthread_rwlock__waitarg wait; - struct pt_alarm_t alarm; -#endif int retval; #ifdef ERRORCHECK @@ -298,30 +262,8 @@ pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, retval = 0; while ((retval == 0) && ((rwlock->ptr_writer != NULL) || (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) { -#ifdef PTHREAD_SA - wait.ptw_thread = self; - wait.ptw_rwlock = rwlock; - wait.ptw_queue = &rwlock->ptr_rblocked; - pthread__alarm_add(self, &alarm, abs_timeout, - pthread_rwlock__callback, &wait); - PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep); - /* Locking a rwlock is not a cancellation point; don't check */ - pthread_spinlock(self, &self->pt_statelock); - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = rwlock; - self->pt_sleepq = &rwlock->ptr_rblocked; - self->pt_sleeplock = &rwlock->ptr_interlock; - pthread_spinunlock(self, &self->pt_statelock); - pthread__block(self, &rwlock->ptr_interlock); - /* interlock is not held when we return */ - pthread__alarm_del(self, &alarm); - if (pthread__alarm_fired(&alarm)) - retval = ETIMEDOUT; - pthread_spinlock(self, &rwlock->ptr_interlock); -#else retval = pthread__park(self, &rwlock->ptr_interlock, rwlock, &rwlock->ptr_rblocked, abs_timeout, 1, 0); -#endif } /* One last chance to get the lock, in case it was released between @@ -342,10 +284,6 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abs_timeout) { -#ifdef PTHREAD_SA - struct pthread_rwlock__waitarg wait; - struct pt_alarm_t alarm; -#endif pthread_t self; int retval; extern int pthread__started; @@ -382,30 +320,8 @@ pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, return EDEADLK; } #endif -#ifdef PTHREAD_SA - wait.ptw_thread = self; - wait.ptw_rwlock = rwlock; - wait.ptw_queue = &rwlock->ptr_wblocked; - pthread__alarm_add(self, &alarm, abs_timeout, - pthread_rwlock__callback, &wait); - PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep); - /* Locking a rwlock is not a cancellation point; don't check */ - pthread_spinlock(self, &self->pt_statelock); - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = rwlock; - self->pt_sleepq = &rwlock->ptr_wblocked; - self->pt_sleeplock = &rwlock->ptr_interlock; - pthread_spinunlock(self, &self->pt_statelock); - pthread__block(self, &rwlock->ptr_interlock); - /* interlock is not held when we return */ - pthread__alarm_del(self, &alarm); - if (pthread__alarm_fired(&alarm)) - retval = ETIMEDOUT; - pthread_spinlock(self, &rwlock->ptr_interlock); -#else retval = pthread__park(self, &rwlock->ptr_interlock, rwlock, &rwlock->ptr_wblocked, abs_timeout, 1, 0); -#endif } if ((rwlock->ptr_nreaders == 0) && (rwlock->ptr_writer == NULL)) { @@ -418,41 +334,10 @@ pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, } -#ifdef PTHREAD_SA -static void -pthread_rwlock__callback(void *arg) -{ - struct pthread_rwlock__waitarg *a; - pthread_t self; - - a = arg; - self = pthread__self(); - - pthread_spinlock(self, &a->ptw_rwlock->ptr_interlock); - /* - * Don't dequeue and schedule the thread if it's already been - * queued up by a signal or broadcast (but hasn't yet run as far - * as pthread__alarm_del(), or we wouldn't be here, and hence can't - * have become blocked on some *other* queue). - */ - if (a->ptw_thread->pt_state == PT_STATE_BLOCKED_QUEUE) { - PTQ_REMOVE(a->ptw_queue, a->ptw_thread, pt_sleep); - pthread__sched(self, a->ptw_thread); - } - pthread_spinunlock(self, &a->ptw_rwlock->ptr_interlock); - -} -#endif - - int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { pthread_t self, writer; -#ifdef PTHREAD_SA - struct pthread_queue_t blockedq; - PTQ_INIT(&blockedq); -#endif #ifdef ERRORCHECK if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC)) return EINVAL; @@ -473,11 +358,6 @@ pthread_rwlock_unlock(pthread_rwlock_t *rwlock) writer = PTQ_FIRST(&rwlock->ptr_wblocked); if (writer != NULL) { PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep); - } else { -#ifdef PTHREAD_SA - blockedq = rwlock->ptr_rblocked; - PTQ_INIT(&rwlock->ptr_rblocked); -#endif } } else #ifdef ERRORCHECK @@ -499,20 +379,11 @@ pthread_rwlock_unlock(pthread_rwlock_t *rwlock) #endif } -#ifdef PTHREAD_SA - if (writer != NULL) - pthread__sched(self, writer); - else - pthread__sched_sleepers(self, &blockedq); - - pthread_spinunlock(self, &rwlock->ptr_interlock); -#else /* PTHREAD_SA */ if (writer != NULL) pthread__unpark(self, &rwlock->ptr_interlock, rwlock, writer); else pthread__unpark_all(self, &rwlock->ptr_interlock, rwlock, &rwlock->ptr_rblocked); -#endif /* PTHREAD_SA */ return 0; } diff --git a/lib/libpthread/pthread_sa.c b/lib/libpthread/pthread_sa.c deleted file mode 100644 index 7ac5ac8bb42..00000000000 --- a/lib/libpthread/pthread_sa.c +++ /dev/null @@ -1,852 +0,0 @@ -/* $NetBSD: pthread_sa.c,v 1.39 2007/02/06 15:24:37 ad Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_sa.c,v 1.39 2007/02/06 15:24:37 ad Exp $"); - -#include <err.h> -#include <errno.h> -#include <lwp.h> -#ifdef PTHREAD_SA -#include <sa.h> -#endif -#include <signal.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ucontext.h> -#include <unistd.h> -#include <sys/time.h> - -#include "pthread.h" -#include "pthread_int.h" - -#ifdef PTHREAD_SA_DEBUG -#define SDPRINTF(x) DPRINTF(x) -#else -#define SDPRINTF(x) -#endif - -#ifdef PTHREAD_SA - -#define UC(t) ((t)->pt_trapuc ? (t)->pt_trapuc : (t)->pt_uc) - -#define PUC(t) ((t)->pt_trapuc ? 'T':'U') , UC(t) - -extern struct pthread_queue_t pthread__allqueue; -extern int pthread__concurrency, pthread__maxconcurrency; - -#define PTHREAD_RRTIMER_INTERVAL_DEFAULT 100 -static pthread_mutex_t rrtimer_mutex = PTHREAD_MUTEX_INITIALIZER; -static timer_t pthread_rrtimer; -static int pthread_rrtimer_interval = PTHREAD_RRTIMER_INTERVAL_DEFAULT; - -int pthread__maxlwps; - - -#define pthread__sa_id(sap) (pthread__id((sap)->sa_context)) - -void pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, - void *arg); -void pthread__find_interrupted(int type, struct sa_t *sas[], int ev, int intr, - pthread_t *qhead, pthread_t *schedqhead, pthread_t self); -void pthread__resolve_locks(pthread_t self, pthread_t *interrupted); - -extern void pthread__switch_return_point(void); - -typedef void (*fptr_t)(void); - -void -pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg) -{ - pthread_t t, self, next, intqueue, schedqueue; - int flags, i; - siginfo_t *si; - - PTHREADD_ADD(PTHREADD_UPCALLS); - - self = pthread__self(); - self->pt_state = PT_STATE_RUNNING; - - if (sas[0]->sa_id > pthread__maxlwps) - pthread__maxlwps = sas[0]->sa_id; - - self->pt_vpid = sas[0]->sa_cpu; - - SDPRINTF(("(up %p) type %d LWP %d ev %d intr %d\n", self, - type, sas[0]->sa_id, ev, intr)); - - if (type != SA_UPCALL_BLOCKED) { - /* - * Do per-thread work, including saving the context. - * Briefly run any threads that were in a critical section. - * This includes any upcalls that have been interrupted, so - * they can do their own version of this dance. - */ - pthread__find_interrupted(type, sas, ev, intr, - &intqueue, &schedqueue, self); - if (intqueue != self) - pthread__resolve_locks(self, &intqueue); - /* We can take spinlocks now */ - if (intqueue != self) - pthread__sched_bulk(self, intqueue); - if (schedqueue != self) - pthread__sched_bulk(self, schedqueue); - } - - switch (type) { - case SA_UPCALL_BLOCKED: - PTHREADD_ADD(PTHREADD_UP_BLOCK); - t = pthread__sa_id(sas[1]); - SDPRINTF(("(up %p) blocker %d %p(%d)\n", self, - sas[1]->sa_id, t, t->pt_type)); - pthread__assert(t->pt_vpid == sas[1]->sa_cpu); - t->pt_blockedlwp = sas[1]->sa_id; - t->pt_blockgen += 2; - /* pthread__assert(t->pt_blockgen <= t->pt_unblockgen + 2); */ - if (t->pt_cancel) - _lwp_wakeup(t->pt_blockedlwp); -#ifdef PTHREAD__DEBUG - t->blocks++; -#endif - break; - case SA_UPCALL_NEWPROC: - PTHREADD_ADD(PTHREADD_UP_NEW); - break; - case SA_UPCALL_PREEMPTED: - PTHREADD_ADD(PTHREADD_UP_PREEMPT); - break; - case SA_UPCALL_UNBLOCKED: - PTHREADD_ADD(PTHREADD_UP_UNBLOCK); - for (i = 0; i < ev; i++) { - t = pthread__sa_id(sas[1 + i]); - /* - * A signal may have been presented to this - * thread while it was in the kernel. - */ - pthread_spinlock(self, &t->pt_flaglock); - flags = t->pt_flags; - pthread_spinunlock(self, &t->pt_flaglock); - if (t->pt_type == PT_THREAD_IDLE && - (flags & PT_FLAG_IDLED)) - t->pt_unblockgen++; - if (flags & PT_FLAG_SIGDEFERRED) - pthread__signal_deferred(self, t); - } - break; - case SA_UPCALL_SIGNAL: - PTHREADD_ADD(PTHREADD_UP_SIGNAL); - /* - * Note that we handle signals after handling - * spinlock preemption. This is because spinlocks are only - * used internally to the thread library and we don't want to - * expose the middle of them to a signal. While this means - * that synchronous instruction traps that occur inside - * critical sections in this library (SIGFPE, SIGILL, SIGBUS, - * SIGSEGV) won't be handled at the precise location where - * they occurred, that's okay, because (1) we don't use any FP - * and (2) SIGILL/SIGBUS/SIGSEGV should really just core dump. - * - * This also means that a thread that was interrupted to take - * a signal will be on a run queue, and not in upcall limbo. - */ - si = arg; - SDPRINTF(("(up %p) signal %d %p\n", self, - ev ? sas[1]->sa_id : -1, si)); - if (ev) - pthread__signal(self, pthread__sa_id(sas[1]), si); - else - pthread__signal(self, NULL, si); - break; - case SA_UPCALL_SIGEV: - PTHREADD_ADD(PTHREADD_UP_SIGEV); - si = arg; - SDPRINTF(("(up %p) sigev val %x\n", self, - si->si_sigval.sival_int)); - if (si->si_sigval.sival_int == PT_ALARMTIMER_MAGIC) - pthread__alarm_process(self, arg); - /* - * PT_RRTIMER_MAGIC doesn't need explicit handling; - * the per-thread work above will put the interrupted - * thread on the back of the run queue, and - * pthread_next() will get one from the front. - */ - break; - case SA_UPCALL_USER: - /* We don't send ourselves one of these. */ - default: - pthread__abort(); - } - - if (type != SA_UPCALL_BLOCKED) - pthread__sched_idle2(self); - - /* - * At this point everything on our list should be scheduled - * (or was an upcall). - */ - pthread__assert(self->pt_spinlocks == 0); - if (self->pt_next) { - SDPRINTF(("(up %p) chain switching to %p (uc: %c %p pc: %lx)\n", - self, self->pt_next, PUC(self->pt_next), - pthread__uc_pc(UC(self->pt_next)))); - self->pt_switchtouc = UC(self); - self->pt_switchto = self; - pthread__assert(self->pt_blockgen == self->pt_unblockgen); - pthread__switch(self, self->pt_next); - /*NOTREACHED*/ - pthread__abort(); - } - next = pthread__next(self); - next->pt_state = PT_STATE_RUNNING; - SDPRINTF(("(up %p) switching to %p (uc: %c %p pc: %lx)\n", - self, next, PUC(next), pthread__uc_pc(UC(next)))); - pthread__upcall_switch(self, next); - /*NOTREACHED*/ - pthread__abort(); -} - -/* - * Build a chain of the threads that were interrupted by the upcall. - * Determine if any of them were upcalls or lock-holders that - * need to be continued early. - */ -void -pthread__find_interrupted(int type, struct sa_t *sas[], int ev, int intr, - pthread_t *intqhead, pthread_t *schedqhead, pthread_t self) -{ - int i, resume; - pthread_t victim, nextint, nextsched; - - nextint = nextsched = self; - - for (i = 0; i < ev + intr; i++) { - resume = 0; - victim = pthread__sa_id(sas[1 + i]); -#ifdef PTHREAD__DEBUG - victim->preempts++; -#endif - victim->pt_trapuc = sas[1 + i]->sa_context; - victim->pt_trapuc->uc_flags &= ~_UC_SIGMASK; - SDPRINTF(("(fi %p) victim %d %p(%d)", self, sas[1 + i]->sa_id, - victim, victim->pt_type)); - if (type == SA_UPCALL_UNBLOCKED && i < ev) { - victim->pt_unblockgen++; -#ifdef PTHREAD__DEBUG - if (victim->pt_blockgen != victim->pt_unblockgen + 1) { - SDPRINTF((" unblock before block")); - } else if (victim->pt_type == PT_THREAD_UPCALL || - victim->pt_spinlocks > 0 || victim->pt_next) { - SDPRINTF((" critical")); - } else { - SDPRINTF((" event")); - } -#endif - } - if (victim->pt_type == PT_THREAD_UPCALL) { - /* Case 1: Upcall. Must be resumed. */ - SDPRINTF((" upcall")); - if (victim->pt_spinlocks > 0) { - SDPRINTF((" lockholder %d", - victim->pt_spinlocks)); - } else { - SDPRINTF((" nonlockholder")); - } - resume = 1; - if (victim->pt_next) { - /* - * Case 1A: Upcall in a chain. - * - * Already part of a chain. We want to - * splice this chain into our chain, so - * we have to find the root. - */ - SDPRINTF((" chain")); - for ( ; victim->pt_parent != NULL; - victim = victim->pt_parent) { - SDPRINTF((" parent %p", victim->pt_parent)); - pthread__assert(victim->pt_parent != victim); - } - } - } else { - /* Case 2: Normal or idle thread. */ - if (victim->pt_spinlocks > 0) { - /* Case 2A: Lockholder. Must be resumed. */ - SDPRINTF((" lockholder %d", - victim->pt_spinlocks)); - resume = 1; - if (victim->pt_next) { - /* - * Case 2A1: Lockholder on a chain. - * Same deal as 1A. - */ - SDPRINTF((" chain")); - for ( ; victim->pt_parent != NULL; - victim = victim->pt_parent) { - SDPRINTF((" parent %p", victim->pt_parent)); - pthread__assert(victim->pt_parent != victim); - } - - - } - } else { - /* Case 2B: Non-lockholder. */ - SDPRINTF((" nonlockholder")); - if (victim->pt_next) { - /* - * Case 2B1: Non-lockholder on a chain - * (must have just released a lock). - */ - SDPRINTF((" chain")); - resume = 1; - for ( ; victim->pt_parent != NULL; - victim = victim->pt_parent) { - SDPRINTF((" parent %p", victim->pt_parent)); - pthread__assert(victim->pt_parent != victim); - } - } else if (victim->pt_flags & PT_FLAG_IDLED) { - /* - * Idle threads that have already - * idled must be skipped so - * that we don't (a) idle-queue them - * twice and (b) get the pt_next - * queue of threads to put on the run - * queue mangled by - * pthread__sched_idle2() - */ - SDPRINTF((" idled\n")); - continue; - } - - } - } - pthread__assert(victim != self); - if (resume) { - pthread__assert(victim->pt_parent == NULL); - victim->pt_parent = self; - pthread__assert(victim->pt_next == NULL); - victim->pt_next = nextint; - nextint = victim; -#ifdef PTHREAD__DEBUG - for (; victim; victim = victim->pt_next) - pthread__assert(victim->pt_next != nextint); -#endif - } else { - pthread__assert(victim->pt_parent == NULL); - pthread__assert(victim->pt_next == NULL); - victim->pt_next = nextsched; - nextsched = victim; -#ifdef PTHREAD__DEBUG - for (; victim; victim = victim->pt_next) - pthread__assert(victim->pt_next != nextsched); -#endif - } - SDPRINTF(("\n")); - } - - *intqhead = nextint; - *schedqhead = nextsched; -} - -void -pthread__resolve_locks(pthread_t self, pthread_t *intqueuep) -{ - pthread_t victim, prev, next, switchto, runq, intqueue; - pthread_t tmp; - pthread_spin_t *lock; - - PTHREADD_ADD(PTHREADD_RESOLVELOCKS); - - runq = self; - intqueue = *intqueuep; - switchto = NULL; - victim = intqueue; - - SDPRINTF(("(rl %p) entered\n", self)); - - while (intqueue != self) { - /* - * Make a pass over the interrupted queue, cleaning out - * any threads that have dropped all their locks and any - * upcalls that have finished. - */ - SDPRINTF(("(rl %p) intqueue %p\n", self, intqueue)); - prev = NULL; - for (victim = intqueue; victim != self; victim = next) { - next = victim->pt_next; - SDPRINTF(("(rl %p) victim %p (uc %c %p)", self, - victim, PUC(victim))); - - if (victim->pt_type == PT_THREAD_NORMAL) { - fptr_t psrp, pc; - - SDPRINTF((" normal")); - psrp = pthread__switch_return_point; - pc = (fptr_t)((intptr_t) - pthread__uc_pc(victim->pt_uc)); - if ((victim->pt_spinlocks == 0) && - ((victim->pt_switchto != NULL) || - (pc == psrp))) { - - /* - * We can remove this thread - * from the interrupted queue. - */ - if (prev) - prev->pt_next = next; - else - intqueue = next; - /* - * Clear trap context, which is - * no longer useful. - */ - victim->pt_trapuc = NULL; - /* - * Check whether the victim was - * making a locked switch. - */ - if (victim->pt_heldlock) { - /* - * Yes. Therefore, it's on - * some sleep queue and - * all we have to do is - * release the lock. - */ - lock = victim->pt_heldlock; - victim->pt_heldlock = NULL; - pthread__simple_unlock(lock); - victim->pt_next = NULL; - victim->pt_parent = NULL; - SDPRINTF((" heldlock: %p",lock)); - } else { - /* - * No. Queue it for the - * run queue. - */ - victim->pt_next = runq; - runq = victim; - } - } else { - SDPRINTF((" spinlocks: %d", - victim->pt_spinlocks)); - /* - * Still holding locks. - * Leave it in the interrupted queue. - */ - prev = victim; - } - } else if (victim->pt_type == PT_THREAD_UPCALL) { - SDPRINTF((" upcall")); - /* Okay, an upcall. */ - if (victim->pt_switchto) { - /* We're done with you. */ - SDPRINTF((" recyclable")); - pthread__assert(victim != prev); - pthread__assert(!prev || prev->pt_next); - /* - * Clear trap context, which is - * no longer useful. - */ - victim->pt_trapuc = NULL; - if (prev) - prev->pt_next = next; - else - intqueue = next; - if (victim->pt_switchto == victim) { - victim->pt_switchto = NULL; - victim->pt_switchtouc = NULL; - SDPRINTF((" switchto self")); - } - pthread__sa_recycle(victim, self); - } else { - /* - * Not finished yet. - * Leave it in the interrupted queue. - */ - prev = victim; - } - } else { - SDPRINTF((" idle")); - /* - * Idle threads should be given an opportunity - * to put themselves on the reidle queue. - * We know that they're done when they have no - * locks and PT_FLAG_IDLED is set. - */ - if (victim->pt_spinlocks != 0) { - /* Still holding locks. */ - SDPRINTF((" spinlocks: %d", - victim->pt_spinlocks)); - prev = victim; - } else if (!(victim->pt_flags & PT_FLAG_IDLED)) { - /* - * Hasn't yet put itself on the - * reidle queue. - */ - SDPRINTF((" not done")); - prev = victim; - } else { - /* Done! */ - if (prev) - prev->pt_next = next; - else - intqueue = next; - /* Permit moving off the reidlequeue */ - victim->pt_next = NULL; - } - } - - if (victim->pt_switchto) { - PTHREADD_ADD(PTHREADD_SWITCHTO); - switchto = victim->pt_switchto; - switchto->pt_uc = victim->pt_switchtouc; - switchto->pt_trapuc = NULL; - victim->pt_switchto = NULL; - victim->pt_switchtouc = NULL; - SDPRINTF((" switchto: %p (uc %p pc %lx)", - switchto, switchto->pt_uc, - pthread__uc_pc(switchto->pt_uc))); - - /* - * Threads can have switchto set to themselves - * if they hit new_preempt. Don't put them - * on the run queue twice. - */ - if (switchto != victim) { - if ((switchto->pt_next) || - (switchto->pt_spinlocks != 0) || - (switchto->pt_type == PT_THREAD_UPCALL)) { - /* - * The thread being switched - * to was preempted and - * continued. Find the - * preempter and put it on - * our continuation chain. - */ - SDPRINTF((" switchto chained")); - for ( tmp = switchto; - tmp->pt_parent != NULL; - tmp = tmp->pt_parent) - SDPRINTF((" parent: %p", tmp->pt_parent)); - pthread__assert(tmp->pt_parent == NULL); - tmp->pt_parent = self; - pthread__assert(tmp->pt_next == NULL); - tmp->pt_next = intqueue; - intqueue = tmp; - if (switchto->pt_type == PT_THREAD_NORMAL && - switchto->pt_spinlocks == 0) { - /* - * We set switchto to - * ourselves so that we - * get off the intqueue - */ - switchto->pt_switchto = switchto; - switchto->pt_switchtouc = switchto->pt_uc; - } - } else if (switchto->pt_type == - PT_THREAD_IDLE && - switchto->pt_flags & PT_FLAG_IDLED) { - SDPRINTF((" idle done")); - } else { - switchto->pt_next = runq; - runq = switchto; - } - } - switchto = NULL; - } - SDPRINTF(("\n")); - } - - if (intqueue != self) { - /* - * There is a chain. Run through the elements - * of the chain. If one of them is preempted again, - * the upcall that handles it will have us on its - * chain, and we will continue here, having - * returned from the switch. - */ - SDPRINTF(("(rl %p) starting chain %p (uc %c %p pc %lx sp %lx)\n", - self, intqueue, PUC(intqueue), - pthread__uc_pc(UC(intqueue)), - pthread__uc_sp(UC(intqueue)))); - pthread__assert(self->pt_blockgen == self->pt_unblockgen); - pthread__switch(self, intqueue); - SDPRINTF(("(rl %p) returned from chain\n", - self)); - } - - if (self->pt_next) { - /* - * We're on a chain ourselves. Let the other - * threads in the chain run; our parent upcall - * will resume us here after a pass around its - * interrupted queue. - */ - SDPRINTF(("(rl %p) upcall chain switch to %p (uc %c %p pc %lx sp %lx)\n", - self, self->pt_next, - PUC(self->pt_next), - pthread__uc_pc(UC(self->pt_next)), - pthread__uc_sp(UC(self->pt_next)))); - pthread__assert(self->pt_blockgen == self->pt_unblockgen); - pthread__switch(self, self->pt_next); - } - - } - - SDPRINTF(("(rl %p) exiting\n", self)); - *intqueuep = runq; -} - -/* - * Stash away an upcall and its stack, possibly recycling it to the kernel. - * Must be running in the context of "new". - */ -void -pthread__sa_recycle(pthread_t old, pthread_t new) -{ - - old->pt_next = NULL; - old->pt_parent = NULL; - old->pt_state = PT_STATE_RUNNABLE; - -#ifdef PTHREAD__DEBUG - if (pthread__debuglog_newline()) - SDPRINTF(("(recycle %p) recycling %p\n", new, old)); - else - SDPRINTF((" (recycling %p)", old)); -#endif - old->pt_stackinfo.sasi_stackgen++; -} - -/* - * Set the round-robin timeslice timer. - */ -static int -pthread__setrrtimer(int msec, int startit) -{ - static int rrtimer_created; - struct itimerspec it; - - /* - * This check is safe -- we will either be called before there - * are any threads, or with the rrtimer_mutex held. - */ - if (rrtimer_created == 0) { - struct sigevent ev; - - ev.sigev_notify = SIGEV_SA; - ev.sigev_signo = 0; - ev.sigev_value.sival_int = (int) PT_RRTIMER_MAGIC; - if (timer_create(CLOCK_VIRTUAL, &ev, &pthread_rrtimer) == -1) - return (errno); - - rrtimer_created = 1; - } - - if (startit) { - it.it_interval.tv_sec = 0; - it.it_interval.tv_nsec = (long)msec * 1000000; - it.it_value = it.it_interval; - if (timer_settime(pthread_rrtimer, TIMER_RELTIME, &it, NULL) == - -1) - return (errno); - } - - pthread_rrtimer_interval = msec; - - return (0); -} - -/* Get things rolling. */ -void -pthread__sa_start(void) -{ - pthread_t self, t; - stack_t upcall_stacks[PT_UPCALLSTACKS]; - int ret, i, errnosave, flags, rr; - char *value; - - flags = 0; - value = getenv("PTHREAD_PREEMPT"); - if (value && strcmp(value, "yes") == 0) - flags |= SA_FLAG_PREEMPT; - - /* - * It's possible the user's program has set the round-robin - * interval before starting any threads. - * - * Allow the environment variable to override the default. - * - * XXX Should we just nuke the environment variable? - */ - rr = pthread_rrtimer_interval; - value = getenv("PTHREAD_RRTIME"); - if (value) - rr = atoi(value); - - flags |= SA_FLAG_STACKINFO; - ret = sa_register(pthread__upcall, NULL, flags, - pthread__stackinfo_offset()); - if (ret) { - if (errno == ENOSYS) - errx(1, - "libpthread: SA system calls are not available.\n" - ); - err(1, "libpthread: sa_register failed\n"); - } - - self = pthread__self(); - for (i = 0; i < PT_UPCALLSTACKS; i++) { - if (0 != (ret = pthread__stackalloc(&t))) - abort(); - upcall_stacks[i] = t->pt_stack; - pthread__initthread(self, t); - t->pt_type = PT_THREAD_UPCALL; - t->pt_flags = PT_FLAG_DETACHED; - sigfillset(&t->pt_sigmask); /* XXX hmmmmmm */ - /* No locking needed, there are no threads yet. */ - PTQ_INSERT_HEAD(&pthread__allqueue, t, pt_allq); - } - - ret = sa_stacks(i, upcall_stacks); - if (ret == -1) - abort(); - - /* XXX - * Calling sa_enable() can mess with errno in bizzare ways, - * because the kernel doesn't really return from it as a - * normal system call. The kernel will launch an upcall - * handler which will jump back to the inside of sa_enable() - * and permit us to continue here. However, since the kernel - * doesn't get a chance to set up the return-state properly, - * the syscall stub may interpret the unmodified register - * state as an error return and stuff an inappropriate value - * into errno. - * - * Therefore, we need to keep errno from being changed by this - * slightly weird control flow. - */ - errnosave = errno; - sa_enable(); - errno = errnosave; - - /* Start the round-robin timer. */ - if (rr != 0 && pthread__setrrtimer(rr, 1) != 0) - abort(); - - pthread__concurrency = 1; - if (pthread__maxconcurrency > pthread__concurrency) { - pthread__concurrency += sa_setconcurrency(pthread__maxconcurrency); - } - -} - -/* - * Interface routines to get/set the round-robin timer interval. - * - * XXX Sanity check the behavior for MP systems. - */ - -int -pthread_getrrtimer_np(void) -{ - - return (pthread_rrtimer_interval); -} - -int -pthread_setrrtimer_np(int msec) -{ - extern int pthread__started; - int ret = 0; - - if (msec < 0) - return (EINVAL); - - pthread_mutex_lock(&rrtimer_mutex); - - ret = pthread__setrrtimer(msec, pthread__started); - - pthread_mutex_unlock(&rrtimer_mutex); - - return (ret); -} - -void -pthread__setconcurrency(int concurrency) -{ - pthread_t self; - int ret; - - self = pthread__self(); - SDPRINTF(("(setconcurrency %p) requested delta %d, current %d\n", - self, concurrency, pthread__concurrency)); - - concurrency += pthread__concurrency; - if (concurrency > pthread__maxconcurrency) - concurrency = pthread__maxconcurrency; - - if (concurrency > pthread__concurrency) { - ret = sa_setconcurrency(concurrency); - /* pthread__concurrency += ret; */ - - SDPRINTF(("(setconcurrency %p) requested %d, now %d, ret %d\n", - self, concurrency, pthread__concurrency, ret)); - } - SDPRINTF(("(set %p concurrency) now %d\n", - self, pthread__concurrency)); -} - - -#else /* PTHREAD_SA */ - -int -pthread_getrrtimer_np(void) -{ - - return (100); -} - -int -pthread_setrrtimer_np(int msec) -{ - - return (EOPNOTSUPP); -} - -#endif /* PTHREAD_SA */ diff --git a/lib/libpthread/pthread_sig.c b/lib/libpthread/pthread_sig.c deleted file mode 100644 index 6805e826c68..00000000000 --- a/lib/libpthread/pthread_sig.c +++ /dev/null @@ -1,1130 +0,0 @@ -/* $NetBSD: pthread_sig.c,v 1.49 2007/01/22 15:06:31 christos Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_sig.c,v 1.49 2007/01/22 15:06:31 christos Exp $"); - -/* We're interposing a specific version of the signal interface. */ -#define __LIBC12_SOURCE__ - -#define __PTHREAD_SIGNAL_PRIVATE - -#define __EXPOSE_STACK 1 -#include <sys/param.h> -#include <errno.h> -#include <lwp.h> -#include <stdint.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> /* for memcpy() */ -#include <ucontext.h> -#include <unistd.h> -#include <compat/include/signal.h> -#include <sys/syscall.h> - -#include <sched.h> -#include "pthread.h" -#include "pthread_int.h" - -#ifdef PTHREAD_SIG_DEBUG -#define SDPRINTF(x) DPRINTF(x) -#else -#define SDPRINTF(x) -#endif - -int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); - -__strong_alias(__libc_thr_sigsetmask,pthread_sigmask) -__strong_alias(__sigprocmask14,pthread_sigmask) - -#ifdef PTHREAD_SA - -extern int pthread__started; - -extern pthread_spin_t pthread__runqueue_lock; -extern struct pthread_queue_t pthread__runqueue; - -extern pthread_spin_t pthread__allqueue_lock; -extern struct pthread_queue_t pthread__allqueue; - -extern pthread_spin_t pthread__suspqueue_lock; -extern struct pthread_queue_t pthread__suspqueue; - -static pthread_spin_t pt_sigacts_lock = __SIMPLELOCK_UNLOCKED; -static struct sigaction pt_sigacts[_NSIG]; - -static pthread_spin_t pt_process_siglock = __SIMPLELOCK_UNLOCKED; -static sigset_t pt_process_sigmask; -static sigset_t pt_process_siglist; - -/* Queue of threads that are waiting in sigsuspend(). */ -static struct pthread_queue_t pt_sigsuspended; -static pthread_spin_t pt_sigsuspended_lock = __SIMPLELOCK_UNLOCKED; - -/* - * Nothing actually signals or waits on this lock, but the sleepobj - * needs to point to something. - */ -static pthread_cond_t pt_sigsuspended_cond = PTHREAD_COND_INITIALIZER; - -/* Queue of threads that are waiting in sigtimedwait(). */ -static struct pthread_queue_t pt_sigwaiting; -static pthread_spin_t pt_sigwaiting_lock = __SIMPLELOCK_UNLOCKED; -static pthread_t pt_sigwmaster; -static pthread_cond_t pt_sigwaiting_cond = PTHREAD_COND_INITIALIZER; - -static void pthread__make_siginfo(siginfo_t *, int); -static void pthread__kill(pthread_t, pthread_t, siginfo_t *); -static void pthread__kill_self(pthread_t, siginfo_t *); - -static void -pthread__signal_tramp(void (*)(int, siginfo_t *, void *), - siginfo_t *, ucontext_t *); - -static int firstsig(const sigset_t *); - -int _sys_execve(const char *, char *const [], char *const []); - -__strong_alias(__exeve,execve) - -void -pthread__signal_init(void) -{ - SDPRINTF(("(signal_init) setting process sigmask\n")); - _sys___sigprocmask14(0, NULL, &pt_process_sigmask); - - PTQ_INIT(&pt_sigsuspended); - PTQ_INIT(&pt_sigwaiting); -} - -void -pthread__signal_start(void) -{ - int i; - struct sigaction act; - - /* Clear all additional signal masks; we'll handle them ourselves */ - for (i = 1 ; i < NSIG ; i++) { - __libc_sigaction14(i, NULL, &act); - __sigemptyset14(&act.sa_mask); - __libc_sigaction14(i, &act, NULL); - } -} - -static void -pthread__make_siginfo(siginfo_t *si, int sig) -{ - (void)memset(si, 0, sizeof(*si)); - si->si_signo = sig; - si->si_code = SI_USER; - /* - * XXX: these could be cached, but beware of setuid(). - */ - si->si_uid = getuid(); - si->si_pid = getpid(); -} - -int -pthread_kill(pthread_t thread, int sig) -{ - pthread_t self; - void (*handler)(int); - - self = pthread__self(); - - SDPRINTF(("(pthread_kill %p) kill %p sig %d\n", self, thread, sig)); - - if ((sig < 0) || (sig >= _NSIG)) - return EINVAL; - if (pthread__find(self, thread) != 0) - return ESRCH; - - /* - * We only let the thread handle this signal if the action for - * the signal is an explicit handler. Otherwise we feed it to - * the kernel so that it can affect the whole process. - */ - pthread_spinlock(self, &pt_sigacts_lock); - handler = pt_sigacts[sig].sa_handler; - pthread_spinunlock(self, &pt_sigacts_lock); - - if (handler == SIG_IGN) { - SDPRINTF(("(pthread_kill %p) do nothing\n", self, thread, sig)); - /* Do nothing */ - } else if ((sig == SIGKILL) || (sig == SIGSTOP) || - (handler == SIG_DFL)) { - /* Let the kernel do the work */ - SDPRINTF(("(pthread_kill %p) kernel kill\n", self, thread, sig)); - kill(getpid(), sig); - } else { - siginfo_t si; - pthread__make_siginfo(&si, sig); - pthread_spinlock(self, &thread->pt_siglock); - pthread__kill(self, thread, &si); - pthread_spinunlock(self, &thread->pt_siglock); - } - - return 0; -} - - -/* - * Interpositioning is our friend. We need to intercept sigaction(), - * sigsuspend() and sigtimedwait(). - */ - -int -__sigaction14(int sig, const struct sigaction *act, struct sigaction *oact) -{ - struct sigaction realact; - sigset_t oldmask; - pthread_t self; - int retval; - - if ((sig <= 0) || (sig >= _NSIG)) - return EINVAL; - - self = pthread__self(); - pthread_spinlock(self, &pt_sigacts_lock); - oldmask = pt_sigacts[sig].sa_mask; - if (act != NULL) { - /* Save the information for our internal dispatch. */ - pt_sigacts[sig] = *act; - pthread_spinunlock(self, &pt_sigacts_lock); - /* - * We want to handle all signals ourself, and not have - * the kernel mask them. Therefore, we clear the - * sa_mask field before passing this to the kernel. We - * do not set SA_NODEFER, which seems like it might be - * appropriate, because that would permit a continuous - * stream of signals to exhaust the supply of upcalls. - */ - if (pthread__started) { - realact = *act; - __sigemptyset14(&realact.sa_mask); - act = &realact; - } - } else - pthread_spinunlock(self, &pt_sigacts_lock); - - retval = __libc_sigaction14(sig, act, oact); - if (oact && (retval == 0)) - oact->sa_mask = oldmask; - - return retval; -} - -int _sys___sigsuspend14(const sigset_t *); - -int -__sigsuspend14(const sigset_t *sigmask) -{ - pthread_t self; - sigset_t oldmask; - - /* if threading not started yet, just do the syscall */ - if (__predict_false(pthread__started == 0)) - return (_sys___sigsuspend14(sigmask)); - - self = pthread__self(); - - pthread_spinlock(self, &pt_sigsuspended_lock); - pthread_spinlock(self, &self->pt_statelock); - if (self->pt_cancel) { - pthread_spinunlock(self, &self->pt_statelock); - pthread_spinunlock(self, &pt_sigsuspended_lock); - pthread_exit(PTHREAD_CANCELED); - } - pthread_sigmask(SIG_SETMASK, sigmask, &oldmask); - - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = &pt_sigsuspended_cond; - self->pt_sleepq = &pt_sigsuspended; - self->pt_sleeplock = &pt_sigsuspended_lock; - pthread_spinunlock(self, &self->pt_statelock); - - PTQ_INSERT_TAIL(&pt_sigsuspended, self, pt_sleep); - pthread__block(self, &pt_sigsuspended_lock); - - pthread__testcancel(self); - - pthread_sigmask(SIG_SETMASK, &oldmask, NULL); - - errno = EINTR; - return -1; -} - -/* - * Interpositioned sigtimedwait(2), need to multiplex all - * eventual callers to a single kernel lwp. - */ -int _sigtimedwait(const sigset_t * __restrict, siginfo_t * __restrict, - const struct timespec * __restrict); - -static void -pthread_sigtimedwait__callback(void *arg) -{ - pthread__sched(pthread__self(), (pthread_t) arg); -} - -int -sigtimedwait(const sigset_t * __restrict set, siginfo_t * __restrict info, - const struct timespec * __restrict timeout) -{ - pthread_t self, target; - sigset_t wset; - struct timespec timo; - int sig, error = 0; - - /* if threading not started yet, just do the syscall */ - if (__predict_false(pthread__started == 0)) - return (_sigtimedwait(set, info, timeout)); - - self = pthread__self(); - pthread__testcancel(self); - - pthread_spinlock(self, &self->pt_siglock); - - /* - * Check if one of the signals that we will be waiting for - * is already pending. If so, return it immediately. - * XXX the MP locking of this isn't right. - */ - wset = *set; - __sigandset(&self->pt_siglist, &wset); - sig = firstsig(&wset); - if (sig) { - info->si_signo = sig; - __sigdelset14(&self->pt_siglist, sig); /* clear it */ - pthread_spinunlock(self, &self->pt_siglock); - pthread__testcancel(self); - return 0; - } - - /* also call syscall if timeout is zero (i.e. polling) */ - if (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0) { - pthread_spinunlock(self, &self->pt_siglock); - error = _sigtimedwait(set, info, timeout); - pthread__testcancel(self); - return (error); - } - if (timeout) { - if ((u_int) timeout->tv_nsec >= 1000000000) { - pthread_spinunlock(self, &self->pt_siglock); - errno = EINVAL; - return (-1); - } - - timo = *timeout; - } - - pthread_spinunlock(self, &self->pt_siglock); - pthread_spinlock(self, &pt_sigwaiting_lock); - - /* - * If there is already a master thread running, arrange things - * to accommodate for eventual extra signals to wait for - * and join the sigwaiting list. - */ - if (pt_sigwmaster) { - struct pt_alarm_t timoalarm; - struct timespec etimo; - - SDPRINTF(("(stw %p) not master\n", self)); - - /* - * Get current time. We need it if we would become master. - */ - if (timeout) { - clock_gettime(CLOCK_MONOTONIC, &etimo); - timespecadd(&etimo, timeout, &etimo); - } - - /* - * Check if this thread's wait set is different to master set. - */ - wset = *set; - __sigminusset(pt_sigwmaster->pt_sigwait, &wset); - if (firstsig(&wset)) { - /* - * Some new signal in set, wakeup master. It will - * rebuild its wait set. - */ - _lwp_wakeup(pt_sigwmaster->pt_blockedlwp); - } - - /* Save our wait set and info pointer */ - wset = *set; - self->pt_sigwait = &wset; - self->pt_wsig = info; - - /* zero to recognize when we get passed the signal from master */ - info->si_signo = 0; - - if (timeout) { - pthread__alarm_add(self, &timoalarm, &etimo, - pthread_sigtimedwait__callback, self); - } - - block: - pthread_spinlock(self, &self->pt_statelock); - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = &pt_sigwaiting_cond; - self->pt_sleepq = &pt_sigwaiting; - self->pt_sleeplock = &pt_sigwaiting_lock; - pthread_spinunlock(self, &self->pt_statelock); - - PTQ_INSERT_TAIL(&pt_sigwaiting, self, pt_sleep); - - SDPRINTF(("(stw %p) not master blocking\n", self)); - pthread__block(self, &pt_sigwaiting_lock); - SDPRINTF(("(stw %p) not master unblocked\n", self)); - - /* check if we got a signal we waited for */ - if (info->si_signo) { - /* got the signal from master */ - pthread__testcancel(self); - return (0); - } - - /* need the lock from now on */ - pthread_spinlock(self, &pt_sigwaiting_lock); - - /* - * If alarm fired, remove us from queue, adjust master - * wait set and return with EAGAIN. - */ - if (timeout) { - if (pthread__alarm_fired(&timoalarm)) { - PTQ_REMOVE(&pt_sigwaiting, self, pt_sleep); - - /* - * Signal master. It will rebuild its wait set. - */ - _lwp_wakeup(pt_sigwmaster->pt_blockedlwp); - - pthread_spinunlock(self, &pt_sigwaiting_lock); - errno = EAGAIN; - return (-1); - } - pthread__alarm_del(self, &timoalarm); - } - - /* - * May have been woken up to deliver signal - check if we are - * the master and reblock if appropriate. - */ - if (pt_sigwmaster != self) - goto block; - - /* not signal nor alarm, must have been upgraded to master */ - pthread__assert(pt_sigwmaster == self); - - /* update timeout before upgrading to master */ - if (timeout) { - struct timespec tnow; - - clock_gettime(CLOCK_MONOTONIC, &tnow); - /* compute difference to end time */ - timespecsub(&tnow, &etimo, &tnow); - /* substract the difference from timeout */ - timespecsub(&timo, &tnow, &timo); - } - } - - /* MASTER */ - self->pt_sigwait = &wset; - self->pt_wsig = NULL; - - /* Master thread loop */ - pt_sigwmaster = self; - SDPRINTF(("(stw %p) i am the master\n", self)); - for(;;) { - /* Build our wait set */ - wset = *set; - if (!PTQ_EMPTY(&pt_sigwaiting)) { - PTQ_FOREACH(target, &pt_sigwaiting, pt_sleep) - __sigplusset(target->pt_sigwait, &wset); - } - - pthread_spinunlock(self, &pt_sigwaiting_lock); - - /* - * We are either the only one, or wait set was setup already. - * Just do the syscall now. - */ - SDPRINTF(("(stw %p) master blocking\n", self)); - error = __sigtimedwait(&wset, info, (timeout) ? &timo : NULL); - SDPRINTF(("(stw %p) master unblocking\n", self)); - - pthread_spinlock(self, &pt_sigwaiting_lock); - if ((error && (errno != ECANCELED || self->pt_cancel)) - || (!error && __sigismember14(set, info->si_signo)) ) { - - /* - * Normal function return. Clear pt_sigwmaster, - * and if wait queue is nonempty, make first waiter - * new master. - */ - SDPRINTF(("(stw %p) master normal self %d\n", - self, info->si_signo)); - pt_sigwmaster = NULL; - if (!PTQ_EMPTY(&pt_sigwaiting)) { - pt_sigwmaster = PTQ_FIRST(&pt_sigwaiting); - SDPRINTF(("(stw %p) new master %p\n", self, - pt_sigwmaster)); - PTQ_REMOVE(&pt_sigwaiting, pt_sigwmaster, - pt_sleep); - pthread__sched(self, pt_sigwmaster); - } - - pthread_spinunlock(self, &pt_sigwaiting_lock); - pthread__testcancel(self); - return (error); - } - - if (!error) { - - /* - * Got a signal, but not from _our_ wait set. - * Scan the queue of sigwaiters and wakeup - * the first thread waiting for this signal. - */ - PTQ_FOREACH(target, &pt_sigwaiting, pt_sleep) { - if (__sigismember14(target->pt_sigwait, - info->si_signo)) { - pthread__assert(target->pt_state == - PT_STATE_BLOCKED_QUEUE); - SDPRINTF(("(stw %p) master target %p\n", - self, target)); - - /* copy to waiter siginfo */ - memcpy(target->pt_wsig, info, sizeof(*info)); - PTQ_REMOVE(&pt_sigwaiting, target, pt_sleep); - pthread__sched(self, target); - break; - } - } - - if (!target) { - - /* - * Didn't find anyone waiting on this signal. - * Deliver signal normally. This might - * happen if a thread times out, but - * 'their' signal arrives before the master - * thread would be scheduled after _lwp_wakeup(). - */ - SDPRINTF(("(stw %p) master orphaned\n", self)); - pthread__signal(self, NULL, info); - } else { - - /* - * Signal waiter removed, adjust our wait set. - */ - SDPRINTF(("(stw %p) master raced\n", self)); - wset = *set; - PTQ_FOREACH(target, &pt_sigwaiting, pt_sleep) - __sigplusset(target->pt_sigwait, &wset); - } - } else { - /* - * ECANCELED - new sigwaiter arrived and added to master - * wait set, or some sigwaiter exited due to timeout - * and removed from master wait set. All the work - * was done already, so just update our timeout - * and go back to syscall. - */ - } - - /* Timeout was adjusted by the syscall, just call again. */ - } - - /* NOTREACHED */ - return (0); -} - -/* - * firstsig is stolen from kern_sig.c - * XXX this is an abstraction violation; except for this, all of - * the knowledge about the composition of sigset_t's was encapsulated - * in signal.h. - * Putting this function in signal.h caused problems with other parts of the - * kernel that #included <signal.h> but didn't have a prototype for ffs. - */ - -static int -firstsig(const sigset_t *ss) -{ - int sig; - - sig = ffs((int)ss->__bits[0]); - if (sig != 0) - return (sig); -#if _NSIG > 33 - sig = ffs((int)ss->__bits[1]); - if (sig != 0) - return (sig + 32); -#endif -#if _NSIG > 65 - sig = ffs((int)ss->__bits[2]); - if (sig != 0) - return (sig + 64); -#endif -#if _NSIG > 97 - sig = ffs((int)ss->__bits[3]); - if (sig != 0) - return (sig + 96); -#endif - return (0); -} - -int -pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) -{ - sigset_t tmp, takelist; - pthread_t self; - int i; - siginfo_t si; - - self = pthread__self(); - /* - * While other threads may read a process's sigmask, - * they won't write it, so we don't need to lock our reads of it. - */ - if (oset != NULL) - *oset = self->pt_sigmask; - - if (set == NULL) - return 0; - - pthread_spinlock(self, &self->pt_siglock); - if (how == SIG_BLOCK) { - __sigplusset(set, &self->pt_sigmask); - /* - * Blocking of signals that are now - * blocked by all threads will be done - * lazily, at signal delivery time. - */ - if (__predict_true(pthread__started)) { - pthread_spinunlock(self, &self->pt_siglock); - return 0; - } - } else if (how == SIG_UNBLOCK) - __sigminusset(set, &self->pt_sigmask); - else if (how == SIG_SETMASK) - self->pt_sigmask = *set; - else { - pthread_spinunlock(self, &self->pt_siglock); - return EINVAL; - } - - if (__predict_false(pthread__started == 0)) { - pt_process_sigmask = self->pt_sigmask; - _sys___sigprocmask14(SIG_SETMASK, &pt_process_sigmask, NULL); - pthread_spinunlock(self, &self->pt_siglock); - return 0; - } - - /* See if there are any signals to take */ - __sigemptyset14(&takelist); - tmp = self->pt_siglist; - while ((i = firstsig(&tmp)) != 0) { - if (!__sigismember14(&self->pt_sigmask, i)) { - __sigaddset14(&takelist, i); - __sigdelset14(&self->pt_siglist, i); - } - __sigdelset14(&tmp, i); - } - pthread_spinlock(self, &pt_process_siglock); - tmp = pt_process_siglist; - while ((i = firstsig(&tmp)) != 0) { - if (!__sigismember14(&self->pt_sigmask, i)) { - __sigaddset14(&takelist, i); - __sigdelset14(&pt_process_siglist, i); - } - __sigdelset14(&tmp, i); - } - /* Unblock any signals that were blocked process-wide before this. */ - tmp = pt_process_sigmask; - __sigandset(&self->pt_sigmask, &tmp); - if (!__sigsetequal(&tmp, &pt_process_sigmask)) { - pt_process_sigmask = tmp; - _sys___sigprocmask14(SIG_SETMASK, &pt_process_sigmask, NULL); - } - pthread_spinunlock(self, &pt_process_siglock); - - pthread__make_siginfo(&si, 0); - while ((i = firstsig(&takelist)) != 0) { - /* Take the signal */ - SDPRINTF(("(pt_sigmask %p) taking unblocked signal %d\n", - self, i)); - si.si_signo = i; - pthread__kill_self(self, &si); - __sigdelset14(&takelist, i); - } - - pthread_spinunlock(self, &self->pt_siglock); - - return 0; -} - - -/* - * Dispatch a signal to thread t, if it is non-null, and to any - * willing thread, if t is null. - */ -void -pthread__signal(pthread_t self, pthread_t t, siginfo_t *si) -{ - pthread_t target, good, okay; - - if (t) { - target = t; - pthread_spinlock(self, &target->pt_siglock); - } else { - /* - * Pick a thread that doesn't have the signal blocked - * and can be reasonably forced to run. - */ - okay = good = NULL; - pthread_spinlock(self, &pthread__allqueue_lock); - PTQ_FOREACH(target, &pthread__allqueue, pt_allq) { - /* - * Changing to PT_STATE_ZOMBIE is protected by - * the pthread__allqueue lock, so we can just - * test for it here. - */ - if ((target->pt_state == PT_STATE_ZOMBIE) || - (target->pt_type != PT_THREAD_NORMAL)) - continue; - pthread_spinlock(self, &target->pt_siglock); - SDPRINTF(( - "(pt_signal %p) target %p: state %d, mask %08x\n", - self, target, target->pt_state, target->pt_sigmask.__bits[0])); - if (!__sigismember14(&target->pt_sigmask, - si->si_signo)) { - if (target->pt_blockgen == target->pt_unblockgen) { - good = target; - /* Leave target locked */ - break; - } else if (okay == NULL) { - okay = target; - /* Leave target locked */ - continue; - } - } - pthread_spinunlock(self, &target->pt_siglock); - } - pthread_spinunlock(self, &pthread__allqueue_lock); - if (good) { - target = good; - if (okay) - pthread_spinunlock(self, &okay->pt_siglock); - } else { - target = okay; - } - - if (target == NULL) { - /* - * They all have it blocked. Note that in our - * process-wide signal mask, and stash the signal - * for later unblocking. - */ - pthread_spinlock(self, &pt_process_siglock); - __sigaddset14(&pt_process_sigmask, si->si_signo); - SDPRINTF(("(pt_signal %p) lazily setting proc sigmask to " - "%08x\n", self, pt_process_sigmask.__bits[0])); - _sys___sigprocmask14(SIG_SETMASK, &pt_process_sigmask, NULL); - __sigaddset14(&pt_process_siglist, si->si_signo); - pthread_spinunlock(self, &pt_process_siglock); - return; - } - } - - /* - * We now have a signal and a victim. - * The victim's pt_siglock is locked. - */ - - /* - * Reset the process signal mask so we can take another - * signal. We will not exhaust our supply of upcalls; if - * another signal is delivered after this, the resolve_locks - * dance will permit us to finish and recycle before the next - * upcall reaches this point. - */ - pthread_spinlock(self, &pt_process_siglock); - SDPRINTF(("(pt_signal %p) setting proc sigmask to " - "%08x\n", self, pt_process_sigmask.__bits[0])); - _sys___sigprocmask14(SIG_SETMASK, &pt_process_sigmask, NULL); - pthread_spinunlock(self, &pt_process_siglock); - - pthread__kill(self, target, si); - pthread_spinunlock(self, &target->pt_siglock); -} - -/* - * Call the signal handler in the context of this thread. Not quite as - * suicidal as it sounds. - * Must be called with target's siglock held. - */ -static void -pthread__kill_self(pthread_t self, siginfo_t *si) -{ - sigset_t oldmask; - struct sigaction act; - ucontext_t uc; /* XXX: we don't pass the right context here */ - - pthread_spinlock(self, &pt_sigacts_lock); - act = pt_sigacts[si->si_signo]; - pthread_spinunlock(self, &pt_sigacts_lock); - - SDPRINTF(("(pthread__kill_self %p) sig %d\n", self, si->si_signo)); - - oldmask = self->pt_sigmask; - __sigplusset(&act.sa_mask, &self->pt_sigmask); - if ((act.sa_flags & SA_NODEFER) == 0) - __sigaddset14(&self->pt_sigmask, si->si_signo); - - pthread_spinunlock(self, &self->pt_siglock); - (*act.sa_sigaction)(si->si_signo, si, &uc); - pthread_spinlock(self, &self->pt_siglock); - - self->pt_sigmask = oldmask; -} - -/* Must be called with target's siglock held */ -static void -pthread__kill(pthread_t self, pthread_t target, siginfo_t *si) -{ - int deliver; - - SDPRINTF(("(pthread__kill %p) target %p sig %d code %d\n", self, target, - si->si_signo, si->si_code)); - - if (__sigismember14(&target->pt_sigmask, si->si_signo)) { - SDPRINTF(("(pthread__kill %p) target masked\n", target)); - - /* - * If the target is waiting for this signal in sigtimedwait(), - * make the target runnable but do not deliver the signal. - * Otherwise record the signal for later delivery. - * XXX not MPsafe. - */ - pthread_spinlock(self, &self->pt_statelock); - if (target->pt_state == PT_STATE_BLOCKED_QUEUE && - target->pt_sleepq == &pt_sigwaiting && - __sigismember14(target->pt_sigwait, si->si_signo)) { - SDPRINTF(("(pthread__kill %p) stw\n", target)); - target->pt_wsig->si_signo = si->si_signo; - pthread_spinunlock(self, &self->pt_statelock); - deliver = 0; - } else { - SDPRINTF(("(pthread__kill %p) deferring\n", target)); - pthread_spinunlock(self, &self->pt_statelock); - __sigaddset14(&target->pt_siglist, si->si_signo); - return; - } - } else { - SDPRINTF(("(pthread__kill %p) target %p delivering\n", - self, target)); - deliver = 1; - } - - if (self == target) { - pthread__kill_self(self, si); - return; - } - - /* - * Ensure the victim is not running. - * In a MP world, it could be on another processor somewhere. - * - * XXX As long as this is uniprocessor, encountering a running - * target process is a bug. - */ - pthread__assert(target->pt_state != PT_STATE_RUNNING || - target->pt_blockgen != target->pt_unblockgen); - - /* - * Holding the state lock blocks out cancellation and any other - * attempts to set this thread up to take a signal. - */ - pthread_spinlock(self, &target->pt_statelock); - if (target->pt_blockgen != target->pt_unblockgen) { - SDPRINTF(("(pthread__kill %p) target blocked\n", target)); - - /* - * The target is not on a queue at all, and - * won't run again for a while. Try to wake it - * from its torpor, then mark the signal for - * later processing. - */ - __sigaddset14(&target->pt_sigblocked, si->si_signo); - __sigaddset14(&target->pt_sigmask, si->si_signo); - pthread_spinlock(self, &target->pt_flaglock); - target->pt_flags |= PT_FLAG_SIGDEFERRED; - pthread_spinunlock(self, &target->pt_flaglock); - pthread_spinunlock(self, &target->pt_statelock); - _lwp_wakeup(target->pt_blockedlwp); - return; - } - SDPRINTF(("(pthread__kill %p) target state %d\n", target, - target->pt_state)); - switch (target->pt_state) { - case PT_STATE_SUSPENDED: - pthread_spinlock(self, &pthread__runqueue_lock); - PTQ_REMOVE(&pthread__suspqueue, target, pt_runq); - pthread_spinunlock(self, &pthread__runqueue_lock); - break; - case PT_STATE_RUNNABLE: - pthread_spinlock(self, &pthread__runqueue_lock); - PTQ_REMOVE(&pthread__runqueue, target, pt_runq); - pthread_spinunlock(self, &pthread__runqueue_lock); - break; - case PT_STATE_BLOCKED_QUEUE: - pthread_spinlock(self, target->pt_sleeplock); - PTQ_REMOVE(target->pt_sleepq, target, pt_sleep); - pthread_spinunlock(self, target->pt_sleeplock); - break; - case PT_STATE_ZOMBIE: - pthread_spinunlock(self, &target->pt_statelock); - return; - default: - ; - } - - if (deliver) - pthread__deliver_signal(self, target, si); - pthread__sched(self, target); - pthread_spinunlock(self, &target->pt_statelock); -} - -/* Must be called with target's siglock held */ -void -pthread__deliver_signal(pthread_t self, pthread_t target, siginfo_t *si) -{ - ucontext_t *uc, * volatile olduc; - struct sigaction act; - siginfo_t *siginfop; - caddr_t sp; - size_t ucsize; - - pthread_spinlock(self, &pt_sigacts_lock); - act = pt_sigacts[si->si_signo]; - pthread_spinunlock(self, &pt_sigacts_lock); - - if (target->pt_trapuc) { - olduc = target->pt_trapuc; - target->pt_trapuc = NULL; - } else - olduc = target->pt_uc; - - /* - * Get the current signal mask, but unblock the current signal, - * because we might have been sigdeferred and the signal would - * have been blocked because of that. Since we are delivering - * the signal now, we cannot have this signal blocked anyway. - * XXX: Is it better to check for SIGDEFERRED here? - */ - olduc->uc_sigmask = target->pt_sigmask; - __sigdelset14(&olduc->uc_sigmask, si->si_signo); - /* - * Prevent anyone else from considering this thread for handling - * more instances of this signal. - */ - __sigplusset(&act.sa_mask, &target->pt_sigmask); - if ((act.sa_flags & SA_NODEFER) == 0) - __sigaddset14(&target->pt_sigmask, si->si_signo); - - /* - * We'd like to just pass oldmask and si to the - * pthread__signal_tramp(), but makecontext() can't reasonably - * pass structures, just word-size things or smaller. We also - * don't want to involve malloc() here, inside the upcall - * handler. So we borrow a bit of space from the target's - * stack, which we were adjusting anyway. - */ - - sp = STACK_MAX(olduc, sizeof(ucontext_t)); - sp = STACK_GROW(sp, STACKSPACE); - siginfop = (void *)STACK_ALLOC(sp, sizeof(siginfo_t)); - sp = STACK_GROW(sp, sizeof(siginfo_t)); - *siginfop = *si; - - /* - * XXX We are blatantly ignoring SIGALTSTACK. It would screw - * with our notion of stack->thread mappings. - */ - - sp = STACK_ALIGN(sp, ~_UC_UCONTEXT_ALIGN); - ucsize = roundup(sizeof(ucontext_t), (~_UC_UCONTEXT_ALIGN) + 1); - uc = (void *)STACK_ALLOC(sp, ucsize); - sp = STACK_GROW(sp, ucsize); - - _INITCONTEXT_U(uc); - - uc->uc_stack.ss_sp = sp; - uc->uc_stack.ss_size = 0; - uc->uc_link = NULL; - - SDPRINTF(("(makecontext %p): target %p: sig: %d uc: %p oldmask: %08x\n", - self, target, si->si_signo, olduc, olduc->uc_sigmask.__bits[0])); - makecontext(uc, pthread__signal_tramp, 3, act.sa_handler, siginfop, - olduc); - target->pt_uc = uc; -} - -void -pthread__signal_deferred(pthread_t self, pthread_t t) -{ - int i; - siginfo_t si; - - pthread_spinlock(self, &t->pt_siglock); - - pthread__make_siginfo(&si, 0); - while ((i = firstsig(&t->pt_sigblocked)) != 0) { - __sigdelset14(&t->pt_sigblocked, i); - si.si_signo = i; - pthread__deliver_signal(self, t, &si); - } - t->pt_flags &= ~PT_FLAG_SIGDEFERRED; - - pthread_spinunlock(self, &t->pt_siglock); -} - -static void -pthread__signal_tramp(void (*handler)(int, siginfo_t *, void *), - siginfo_t *info, ucontext_t *uc) -{ - SDPRINTF(("(tramp %p) sig %d code %d uc %p oldmask %08x\n", - pthread__self(), info->si_signo, info->si_code, uc, - uc->uc_sigmask.__bits[0])); - - (*handler)(info->si_signo, info, uc); - - pthread__self()->pt_flags |= PT_FLAG_SIGNALED; - - /* - * We've finished the handler, so this thread can restore the - * original signal mask. Note that traditional BSD behavior - * allows for the handler to change the signal mask; we handle - * that here. - */ - pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, NULL); - - /* - * Jump back to what we were doing before we were interrupted - * by a signal. - */ - _setcontext_u(uc); - /*NOTREACHED*/ - pthread__abort(); -} - -/* - * The execve() system call and the libc exec*() calls that use it are - * specified to propagate the signal mask of the current thread to the - * initial thread of the new process image. Since thread signal masks - * are maintained in userlevel, this wrapper is necessary to give the - * kernel the correct value. - */ -int -execve(const char *path, char *const argv[], char *const envp[]) -{ - pthread_t self; - int ret; - - self = pthread__self(); - - /* - * Don't acquire pt_process_siglock, even though it seems like - * the right thing to do. The most common reason to be here is - * that we're on the child side of a fork() or vfork() - * call. In either case, another thread could have held - * pt_process_siglock at the moment of forking, and acquiring - * it here would cause us to deadlock. Additionally, in the - * case of vfork(), acquiring the lock here would cause it to - * be locked in the parent's address space and cause a - * deadlock there the next time a signal routine is called. - * - * The remaining case is where a live multithreaded program - * calls exec*() from one of several threads with no explicit - * synchronization. It may get the wrong process sigmask in - * the new process image if another thread executes a signal - * routine between the sigprocmask and the _sys_execve() - * call. I don't have much sympathy for such a program. - */ - _sys___sigprocmask14(SIG_SETMASK, &self->pt_sigmask, NULL); - ret = _sys_execve(path, argv, envp); - - /* Normally, we shouldn't get here; this is an error condition. */ - _sys___sigprocmask14(SIG_SETMASK, &pt_process_sigmask, NULL); - - return ret; -} - -#else /* PTHREAD_SA */ - -int -pthread_kill(pthread_t thread, int sig) -{ - pthread_t self; - - self = pthread__self(); - - SDPRINTF(("(pthread_kill %p) kill %p sig %d\n", self, thread, sig)); - - if ((sig < 0) || (sig >= _NSIG)) - return EINVAL; - if (pthread__find(self, thread) != 0) - return ESRCH; - - return _lwp_kill(thread->pt_lid, sig); -} - -int -pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) -{ - - return _sys___sigprocmask14(how, set, oset); -} - -#endif /* PTHREAD_SA */ diff --git a/lib/libpthread/pthread_sleep.c b/lib/libpthread/pthread_sleep.c deleted file mode 100644 index 676d8602ab1..00000000000 --- a/lib/libpthread/pthread_sleep.c +++ /dev/null @@ -1,191 +0,0 @@ -/* $NetBSD: pthread_sleep.c,v 1.8 2006/12/23 05:14:47 ad Exp $ */ - -/*- - * Copyright (c) 2003 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nathan J. Williams. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_sleep.c,v 1.8 2006/12/23 05:14:47 ad Exp $"); - -#include <errno.h> -#include <limits.h> -#include <sys/time.h> - -#include "pthread.h" -#include "pthread_int.h" - -int _sys_nanosleep(const struct timespec *, struct timespec *); - -#ifdef PTHREAD_SA - -extern int pthread__started; - -/* - * The point of this exercise is to avoid sleeping in the kernel for - * each and every thread that wants to sleep. A surprising number of - * applications create many threads that spend a lot of time sleeping. - * - * "Save a LWP, shoot a preppie." - */ - -/* Queue of threads in nanosleep() */ -struct pthread_queue_t pthread__nanosleeping; -static pthread_spin_t pt_nanosleep_lock = __SIMPLELOCK_UNLOCKED; -/* - * Nothing actually signals or waits on this lock, but the sleepobj - * needs to point to something. - */ -static pthread_cond_t pt_nanosleep_cond = PTHREAD_COND_INITIALIZER; - -static void pthread__nanosleep_callback(void *); - - -int -nanosleep(const struct timespec *rqtp, struct timespec *rmtp) -{ - int retval; - pthread_t self; - struct timespec sleeptime; - struct pt_alarm_t alarm; - - if ((rqtp->tv_sec) < 0 || - (rqtp->tv_nsec < 0) || (rqtp->tv_nsec > 1000000000L)) - return EINVAL; - - retval = 0; - - self = pthread__self(); - - if (pthread__started == 0) { - pthread__testcancel(self); - retval = _sys_nanosleep(rqtp, rmtp); - pthread__testcancel(self); - return retval; - } - - /* - * Figure out the absolute time to sleep until. If the thread - * got suspended before this then the sleep will be longer - * than intended, but the same thing could happen just before - * the thread called sleep too, so it's not our problem. - */ - clock_gettime(CLOCK_REALTIME, &sleeptime); - timespecadd(&sleeptime, rqtp, &sleeptime); - /* - * Adding a caller-supplied value to the current time can wrap - * the time_t, which will be rejected by the kernel. Cap the - * value if that happens. - */ - if (sleeptime.tv_sec < 0) - sleeptime.tv_sec = INT_MAX; - - do { - pthread_spinlock(self, &pt_nanosleep_lock); - pthread_spinlock(self, &self->pt_statelock); - if (self->pt_cancel) { - pthread_spinunlock(self, &self->pt_statelock); - pthread_spinunlock(self, &pt_nanosleep_lock); - pthread_exit(PTHREAD_CANCELED); - } - pthread__alarm_add(self, &alarm, &sleeptime, - pthread__nanosleep_callback, self); - - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepobj = &pt_nanosleep_cond; - self->pt_sleepq = &pthread__nanosleeping; - self->pt_sleeplock = &pt_nanosleep_lock; - self->pt_flags &= ~PT_FLAG_SIGNALED; - pthread_spinunlock(self, &self->pt_statelock); - - PTQ_INSERT_TAIL(&pthread__nanosleeping, self, pt_sleep); - pthread__block(self, &pt_nanosleep_lock); - /* Spinlock is unlocked on return */ - pthread__alarm_del(self, &alarm); - - pthread__testcancel(self); - - if (self->pt_flags & PT_FLAG_SIGNALED) { - retval = -1; - errno = EINTR; - if (rmtp) { - clock_gettime(CLOCK_REALTIME, rmtp); - timespecsub(&sleeptime, rmtp, rmtp); - } - } else if (rmtp) - timespecclear(rmtp); - } while (!(pthread__alarm_fired(&alarm) || - (self->pt_flags & PT_FLAG_SIGNALED))); - - return retval; -} - -static void -pthread__nanosleep_callback(void *arg) -{ - pthread_t self, thread; - - thread = arg; - self = pthread__self(); - /* - * Don't dequeue and schedule the thread if it's already been - * queued up by a signal or broadcast (but hasn't yet run as far - * as pthread__alarm_del(), or we wouldn't be here, and hence can't - * have become blocked on some *other* queue). - */ - pthread_spinlock(self, &pt_nanosleep_lock); - if (thread->pt_state == PT_STATE_BLOCKED_QUEUE) { - PTQ_REMOVE(&pthread__nanosleeping, thread, pt_sleep); - pthread__sched(self, thread); - } - pthread_spinunlock(self, &pt_nanosleep_lock); -} - -#else /* PTHREAD_SA */ - -int -nanosleep(const struct timespec *rqtp, struct timespec *rmtp) -{ - - /* - * XXXLWP For now, just nanosleep. In the future, maybe pass - * a ucontext_t to _lwp_nanosleep() and allow it to recycle our - * kernel stack. - */ - return _sys_nanosleep(rqtp, rmtp); -} - -#endif /* PTHREAD_SA */ - -__strong_alias(_nanosleep, nanosleep) diff --git a/lib/libpthread/pthread_stack.c b/lib/libpthread/pthread_stack.c index 2846c7d9dd8..fa3c8332284 100644 --- a/lib/libpthread/pthread_stack.c +++ b/lib/libpthread/pthread_stack.c @@ -1,7 +1,7 @@ -/* $NetBSD: pthread_stack.c,v 1.19 2007/01/20 18:58:11 christos Exp $ */ +/* $NetBSD: pthread_stack.c,v 1.20 2007/03/02 18:53:54 ad Exp $ */ /*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. + * Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_stack.c,v 1.19 2007/01/20 18:58:11 christos Exp $"); +__RCSID("$NetBSD: pthread_stack.c,v 1.20 2007/03/02 18:53:54 ad Exp $"); #define __EXPOSE_STACK 1 #include <sys/param.h> @@ -207,29 +207,6 @@ pthread__stackid_setup(void *base, size_t size, pthread_t *tp) if (ret == -1) { return errno; } -#ifdef PTHREAD_MLOCK_KLUDGE - ret = mlock(t, sizeof(struct __pthread_st)); - if (ret < 0) { - return errno; - } -#endif *tp = t; return 0; } - - -#ifdef PTHREAD_SA -ssize_t -pthread__stackinfo_offset() -{ - size_t pagesize; - - pagesize = (size_t)sysconf(_SC_PAGESIZE); - -#ifdef __MACHINE_STACK_GROWS_UP - return (-pagesize + offsetof(struct __pthread_st, pt_stackinfo)); -#else - return (-(2 * pagesize) + offsetof(struct __pthread_st, pt_stackinfo)); -#endif -} -#endif diff --git a/lib/libpthread/sem.c b/lib/libpthread/sem.c index f67d14e6bb4..1799df8c614 100644 --- a/lib/libpthread/sem.c +++ b/lib/libpthread/sem.c @@ -1,4 +1,4 @@ -/* $NetBSD: sem.c,v 1.11 2006/12/24 18:39:46 ad Exp $ */ +/* $NetBSD: sem.c,v 1.12 2007/03/02 18:53:54 ad Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: sem.c,v 1.11 2006/12/24 18:39:46 ad Exp $"); +__RCSID("$NetBSD: sem.c,v 1.12 2007/03/02 18:53:54 ad Exp $"); #include <sys/types.h> #include <sys/ksem.h> @@ -332,19 +332,6 @@ sem_wait(sem_t *sem) break; } -#ifdef PTHREAD_SA - PTQ_INSERT_TAIL(&(*sem)->usem_waiters, self, pt_sleep); - self->pt_sleepobj = *sem; - self->pt_state = PT_STATE_BLOCKED_QUEUE; - self->pt_sleepq = &(*sem)->usem_waiters; - self->pt_sleeplock = &(*sem)->usem_interlock; - pthread_spinunlock(self, &self->pt_statelock); - - /* XXX What about signals? */ - - pthread__block(self, &(*sem)->usem_interlock); - /* interlock is not held when we return */ -#else /* * Should be no race against self->pt_cancel here, as the * kernel needs to preserve L_CANCELLED. @@ -355,7 +342,6 @@ sem_wait(sem_t *sem) (void)pthread__park(self, &(*sem)->usem_interlock, *sem, &(*sem)->usem_waiters, NULL, 1, 1); pthread_spinunlock(self, &(*sem)->usem_interlock); -#endif } (*sem)->usem_count--; @@ -437,13 +423,8 @@ sem_post(sem_t *sem) if (blocked) { PTQ_REMOVE(&(*sem)->usem_waiters, blocked, pt_sleep); /* Give the head of the blocked queue another try. */ -#ifdef PTHREAD_SA - pthread__sched(self, blocked); - pthread_spinunlock(self, &(*sem)->usem_interlock); -#else pthread__unpark(self, &(*sem)->usem_interlock, *sem, blocked); -#endif } else pthread_spinunlock(self, &(*sem)->usem_interlock); |
