diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2007-11-26 23:50:04 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2007-11-26 23:50:04 +0000 |
commit | 7aae05c899a68701e362cdd21b91e57c19c8ae68 (patch) | |
tree | 8b233db938479691732242134da8f340854883d4 /sys | |
parent | b3bc6786e9757d50fa5b9a9365624fcba70f3ae6 (diff) |
Like i386 - make the __mp_lock not spin at splhigh.
deraadt@ ok
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/lock_machdep.c | 167 | ||||
-rw-r--r-- | sys/arch/amd64/conf/files.amd64 | 3 | ||||
-rw-r--r-- | sys/arch/amd64/include/mplock.h | 166 |
3 files changed, 180 insertions, 156 deletions
diff --git a/sys/arch/amd64/amd64/lock_machdep.c b/sys/arch/amd64/amd64/lock_machdep.c new file mode 100644 index 00000000000..c9c76015956 --- /dev/null +++ b/sys/arch/amd64/amd64/lock_machdep.c @@ -0,0 +1,167 @@ +/* $OpenBSD: lock_machdep.c,v 1.1 2007/11/26 23:50:03 art Exp $ */ + +/* + * Copyright (c) 2007 Artur Grabowski <art@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#include <sys/param.h> +#include <sys/lock.h> +#include <sys/systm.h> + +#include <machine/atomic.h> +#include <machine/lock.h> +#include <machine/cpufunc.h> + +#include <ddb/db_output.h> + +void +__mp_lock_init(struct __mp_lock *lock) +{ + lock->mpl_cpu = NULL; + lock->mpl_count = 0; +} + +#if defined(MP_LOCKDEBUG) +#ifndef DDB +#error "MP_LOCKDEBUG requires DDB" +#endif + +/* CPU-dependent timing, needs this to be settable from ddb. */ +extern int __mp_lock_spinout; +#endif + +#define SPINLOCK_SPIN_HOOK __asm __volatile("pause": : :"memory") + +static __inline void +__mp_lock_spin(struct __mp_lock *mpl) +{ +#ifndef MP_LOCKDEBUG + while (mpl->mpl_count != 0) + SPINLOCK_SPIN_HOOK; +#else + int ticks = __mp_lock_spinout; + + while (mpl->mpl_count != 0 && ticks-- > 0) + SPINLOCK_SPIN_HOOK; + + if (ticks == 0) { + db_printf("__mp_lock(0x%x): lock spun out", mpl); + Debugger(); + } +#endif +} + +void +__mp_lock(struct __mp_lock *mpl) +{ + /* + * Please notice that mpl_count gets incremented twice for the + * first lock. This is on purpose. The way we release the lock + * in mp_unlock is to decrement the mpl_count and then check if + * the lock should be released. Since mpl_count is what we're + * spinning on, decrementing it in mpl_unlock to 0 means that + * we can't clear mpl_cpu, because we're no longer holding the + * lock. In theory mpl_cpu doesn't need to be cleared, but it's + * safer to clear it and besides, setting mpl_count to 2 on the + * first lock makes most of this code much simpler. + */ + + while (1) { + long rf = read_rflags(); + + disable_intr(); + if (x86_atomic_cas_ul(&mpl->mpl_count, 0, 1) == 0) { + mpl->mpl_cpu = curcpu(); + } + + if (mpl->mpl_cpu == curcpu()) { + mpl->mpl_count++; + write_rflags(rf); + break; + } + write_rflags(rf); + + __mp_lock_spin(mpl); + } +} + +void +__mp_unlock(struct __mp_lock *mpl) +{ + long rf = read_rflags(); + +#ifdef MP_LOCKDEBUG + if (mpl->mpl_cpu != curcpu()) { + db_printf("__mp_unlock(%p): not held lock\n", mpl); + Debugger(); + } +#endif + + disable_intr(); + if (--mpl->mpl_count == 1) { + mpl->mpl_cpu = NULL; + mpl->mpl_count = 0; + } + write_rflags(rf); +} + +int +__mp_release_all(struct __mp_lock *mpl) { + int rv = mpl->mpl_count - 1; + long rf = read_rflags(); + +#ifdef MP_LOCKDEBUG + if (mpl->mpl_cpu != curcpu()) { + db_printf("__mp_release_all(%p): not held lock\n", mpl); + Debugger(); + } +#endif + + disable_intr(); + mpl->mpl_cpu = NULL; + mpl->mpl_count = 0; + write_rflags(rf); + + return (rv); +} + +int +__mp_release_all_but_one(struct __mp_lock *mpl) { + int rv = mpl->mpl_count - 2; + +#ifdef MP_LOCKDEBUG + if (mpl->mpl_cpu != curcpu()) { + db_printf("__mp_release_all_but_one(%p): not held lock\n", mpl); + Debugger(); + } +#endif + + mpl->mpl_count = 2; + + return (rv); +} + +void +__mp_acquire_count(struct __mp_lock *mpl, int count) { + while (count--) + __mp_lock(mpl); +} + +int +__mp_lock_held(struct __mp_lock *mpl) { + return mpl->mpl_cpu == curcpu(); +} + diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 index 5ab5f20a899..12f7f9daf8b 100644 --- a/sys/arch/amd64/conf/files.amd64 +++ b/sys/arch/amd64/conf/files.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.amd64,v 1.37 2007/11/25 17:11:12 oga Exp $ +# $OpenBSD: files.amd64,v 1.38 2007/11/26 23:50:03 art Exp $ maxpartitions 16 maxusers 2 16 128 @@ -22,6 +22,7 @@ file arch/amd64/amd64/softintr.c file arch/amd64/amd64/i8259.c file arch/amd64/amd64/cacheinfo.c file arch/amd64/amd64/mutex.S +file arch/amd64/amd64/lock_machdep.c multiprocessor file arch/amd64/amd64/intr.c file arch/amd64/amd64/bus_space.c diff --git a/sys/arch/amd64/include/mplock.h b/sys/arch/amd64/include/mplock.h index 8f87c895aae..82b0d3212f9 100644 --- a/sys/arch/amd64/include/mplock.h +++ b/sys/arch/amd64/include/mplock.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mplock.h,v 1.1 2007/11/26 17:15:29 art Exp $ */ +/* $OpenBSD: mplock.h,v 1.2 2007/11/26 23:50:03 art Exp $ */ /* * Copyright (c) 2004 Niklas Hallqvist. All rights reserved. @@ -27,165 +27,21 @@ #ifndef _MACHINE_MPLOCK_H_ #define _MACHINE_MPLOCK_H_ -/* - * Really simple spinlock implementation with recursive capabilities. - * Correctness is paramount, no fancyness allowed. - */ - struct __mp_lock { - __cpu_simple_lock_t mpl_lock; - cpuid_t mpl_cpu; - int mpl_count; + volatile struct cpu_info *mpl_cpu; + volatile long mpl_count; }; -static __inline void -__mp_lock_init(struct __mp_lock *lock) -{ - __cpu_simple_lock_init(&lock->mpl_lock); - lock->mpl_cpu = LK_NOCPU; - lock->mpl_count = 0; -} - -#if defined(MP_LOCKDEBUG) -#ifndef DDB -#error "MP_LOCKDEBUG requires DDB" -#endif - -extern void Debugger(void); -extern int db_printf(const char *, ...) - __attribute__((__format__(__kprintf__,1,2))); - -/* CPU-dependent timing, needs this to be settable from ddb. */ -extern int __mp_lock_spinout; -#endif - -static __inline void -__mp_lock(struct __mp_lock *lock) -{ - int s = spllock(); - - if (lock->mpl_cpu != cpu_number()) { -#ifndef MP_LOCKDEBUG - __cpu_simple_lock(&lock->mpl_lock); -#else - { - int got_it; - do { - int ticks = __mp_lock_spinout; - - do { - got_it = __cpu_simple_lock_try( - &lock->mpl_lock); - } while (!got_it && ticks-- > 0); - if (!got_it) { - db_printf( - "__mp_lock(0x%x): lock spun out", - lock); - Debugger(); - } - } while (!got_it); - } -#endif - lock->mpl_cpu = cpu_number(); - } - lock->mpl_count++; - splx(s); -} - -/* - * Try to acquire the lock, if another cpu has it, fill it in the - * call-by-reference cpu parameter. Return true if acquired. - */ -static __inline int -__mp_lock_try(struct __mp_lock *lock, cpuid_t *cpu) -{ - int s = spllock(); - - if (lock->mpl_cpu != cpu_number()) { - if (!__cpu_simple_lock_try(&lock->mpl_lock)) { - *cpu = lock->mpl_cpu; - splx(s); - return 0; - } - lock->mpl_cpu = cpu_number(); - } - lock->mpl_count++; - splx(s); - return 1; -} - -static __inline void -__mp_unlock(struct __mp_lock *lock) -{ - int s = spllock(); - -#ifdef MP_LOCKDEBUG - if (lock->mpl_count == 0 || lock->mpl_cpu == LK_NOCPU) { - db_printf("__mp_unlock(0x%x): releasing not locked lock\n", - lock); - Debugger(); - } -#endif - - if (--lock->mpl_count == 0) { - lock->mpl_cpu = LK_NOCPU; - __cpu_simple_unlock(&lock->mpl_lock); - } - splx(s); -} - -static __inline int -__mp_release_all(struct __mp_lock *lock) { - int s = spllock(); - int rv = lock->mpl_count; +#ifndef _LOCORE -#ifdef MP_LOCKDEBUG - if (lock->mpl_count == 0 || lock->mpl_cpu == LK_NOCPU) { - db_printf( - "__mp_release_all(0x%x): releasing not locked lock\n", - lock); - Debugger(); - } -#endif - - lock->mpl_cpu = LK_NOCPU; - lock->mpl_count = 0; - __cpu_simple_unlock(&lock->mpl_lock); - splx(s); - return (rv); -} +void __mp_lock_init(struct __mp_lock *); +void __mp_lock(struct __mp_lock *); +void __mp_unlock(struct __mp_lock *); +int __mp_release_all(struct __mp_lock *); +int __mp_release_all_but_one(struct __mp_lock *); +void __mp_acquire_count(struct __mp_lock *, int); +int __mp_lock_held(struct __mp_lock *); -static __inline int -__mp_release_all_but_one(struct __mp_lock *lock) { - int s = spllock(); - int rv = lock->mpl_count - 1; - -#ifdef MP_LOCKDEBUG - if (lock->mpl_count == 0 || lock->mpl_cpu == LK_NOCPU) { - db_printf( - "__mp_release_all_but_one(0x%x): releasing not locked lock\n", - lock); - Debugger(); - } #endif - lock->mpl_count = 1; - splx(s); - return (rv); -} - -static __inline void -__mp_acquire_count(struct __mp_lock *lock, int count) { - int s = spllock(); - - while (count--) - __mp_lock(lock); - splx(s); -} - -static __inline int -__mp_lock_held(struct __mp_lock *lock) { - return lock->mpl_count && lock->mpl_cpu == cpu_number(); -} - #endif /* !_MACHINE_MPLOCK_H */ |