2000-09-07 01:33:02 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1997 Berkeley Software Design, 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. Berkeley Software Design Inc's name may not be used to endorse or
|
|
|
|
* promote products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN 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 BERKELEY SOFTWARE DESIGN 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.
|
|
|
|
*
|
|
|
|
* from BSDI $Id: mutex.h,v 2.7.2.35 2000/04/27 03:10:26 cp Exp $
|
|
|
|
* $FreeBSD$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _MACHINE_MUTEX_H_
|
|
|
|
#define _MACHINE_MUTEX_H_
|
|
|
|
|
|
|
|
#ifndef LOCORE
|
|
|
|
|
2000-10-04 01:21:58 +00:00
|
|
|
#ifdef _KERNEL
|
- Make the mutex code almost completely machine independent. This greatly
reducues the maintenance load for the mutex code. The only MD portions
of the mutex code are in machine/mutex.h now, which include the assembly
macros for handling mutexes as well as optionally overriding the mutex
micro-operations. For example, we use optimized micro-ops on the x86
platform #ifndef I386_CPU.
- Change the behavior of the SMP_DEBUG kernel option. In the new code,
mtx_assert() only depends on INVARIANTS, allowing other kernel developers
to have working mutex assertiions without having to include all of the
mutex debugging code. The SMP_DEBUG kernel option has been renamed to
MUTEX_DEBUG and now just controls extra mutex debugging code.
- Abolish the ugly mtx_f hack. Instead, we dynamically allocate
seperate mtx_debug structures on the fly in mtx_init, except for mutexes
that are initiated very early in the boot process. These mutexes
are declared using a special MUTEX_DECLARE() macro, and use a new
flag MTX_COLD when calling mtx_init. This is still somewhat hackish,
but it is less evil than the mtx_f filler struct, and the mtx struct is
now the same size with and without mutex debugging code.
- Add some micro-micro-operation macros for doing the actual atomic
operations on the mutex mtx_lock field to make it easier for other archs
to override/optimize mutex ops if needed. These new tiny ops also clean
up the code in some places by replacing long atomic operation function
calls that spanned 2-3 lines with a short 1-line macro call.
- Don't call mi_switch() from mtx_enter_hard() when we block while trying
to obtain a sleep mutex. Calling mi_switch() would bogusly release
Giant before switching to the next process. Instead, inline most of the
code from mi_switch() in the mtx_enter_hard() function. Note that when
we finally kill Giant we can back this out and go back to calling
mi_switch().
2000-10-20 07:26:37 +00:00
|
|
|
#include <machine/psl.h>
|
2000-09-08 21:48:06 +00:00
|
|
|
|
2000-09-07 01:33:02 +00:00
|
|
|
/* Global locks */
|
2000-10-06 02:20:21 +00:00
|
|
|
extern struct mtx clock_lock;
|
2000-09-07 01:33:02 +00:00
|
|
|
|
2001-03-28 02:40:47 +00:00
|
|
|
#define mtx_intr_enable(mutex) (mutex)->mtx_savecrit |= PSL_I
|
2000-10-20 22:44:06 +00:00
|
|
|
|
2000-09-07 01:33:02 +00:00
|
|
|
/*
|
|
|
|
* Assembly macros (for internal use only)
|
|
|
|
*------------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#define _V(x) __STRING(x)
|
|
|
|
|
2001-01-16 04:48:38 +00:00
|
|
|
#if 0
|
|
|
|
/* #ifndef I386_CPU */
|
2000-09-07 01:33:02 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* For 486 and newer processors.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Get a sleep lock, deal with recursion inline. */
|
|
|
|
#define _getlock_sleep(mtxp, tid, type) ({ \
|
2001-01-16 03:45:54 +00:00
|
|
|
int _res = MTX_UNOWNED; \
|
2000-09-07 01:33:02 +00:00
|
|
|
\
|
|
|
|
__asm __volatile ( \
|
|
|
|
" " MPLOCKED "" \
|
|
|
|
" cmpxchgl %3,%1;" /* Try */ \
|
|
|
|
" jz 1f;" /* Got it */ \
|
2001-01-16 03:45:54 +00:00
|
|
|
" andl $" _V(MTX_FLAGMASK) ",%0;" /* turn off spec bits */ \
|
|
|
|
" cmpl %0,%3;" /* already have it? */ \
|
2000-09-07 01:33:02 +00:00
|
|
|
" je 2f;" /* yes, recurse */ \
|
|
|
|
" pushl %4;" \
|
|
|
|
" pushl %5;" \
|
|
|
|
" call mtx_enter_hard;" \
|
|
|
|
" addl $8,%%esp;" \
|
|
|
|
" jmp 1f;" \
|
2000-12-04 12:38:03 +00:00
|
|
|
"2:" \
|
|
|
|
" " MPLOCKED "" \
|
|
|
|
" orl $" _V(MTX_RECURSE) ",%1;" \
|
2000-09-08 21:48:06 +00:00
|
|
|
" incl %2;" \
|
2000-09-07 01:33:02 +00:00
|
|
|
"1:" \
|
|
|
|
"# getlock_sleep" \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "+a" (_res), /* 0 */ \
|
2000-09-07 01:33:02 +00:00
|
|
|
"+m" (mtxp->mtx_lock), /* 1 */ \
|
|
|
|
"+m" (mtxp->mtx_recurse) /* 2 */ \
|
|
|
|
: "r" (tid), /* 3 (input) */ \
|
|
|
|
"gi" (type), /* 4 */ \
|
|
|
|
"g" (mtxp) /* 5 */ \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "cc", "memory", "ecx", "edx" /* used */ ); \
|
2000-09-07 01:33:02 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
/* Get a spin lock, handle recursion inline (as the less common case) */
|
|
|
|
#define _getlock_spin_block(mtxp, tid, type) ({ \
|
2001-01-16 03:45:54 +00:00
|
|
|
int _res = MTX_UNOWNED; \
|
2000-09-07 01:33:02 +00:00
|
|
|
\
|
|
|
|
__asm __volatile ( \
|
|
|
|
" pushfl;" \
|
|
|
|
" cli;" \
|
|
|
|
" " MPLOCKED "" \
|
|
|
|
" cmpxchgl %3,%1;" /* Try */ \
|
|
|
|
" jz 2f;" /* got it */ \
|
|
|
|
" pushl %4;" \
|
|
|
|
" pushl %5;" \
|
|
|
|
" call mtx_enter_hard;" /* mtx_enter_hard(mtxp, type, oflags) */ \
|
2000-12-04 12:38:03 +00:00
|
|
|
" addl $12,%%esp;" \
|
2000-09-07 01:33:02 +00:00
|
|
|
" jmp 1f;" \
|
|
|
|
"2: popl %2;" /* save flags */ \
|
|
|
|
"1:" \
|
|
|
|
"# getlock_spin_block" \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "+a" (_res), /* 0 */ \
|
2000-09-07 01:33:02 +00:00
|
|
|
"+m" (mtxp->mtx_lock), /* 1 */ \
|
2001-03-28 02:40:47 +00:00
|
|
|
"=m" (mtxp->mtx_savecrit) /* 2 */ \
|
2000-09-07 01:33:02 +00:00
|
|
|
: "r" (tid), /* 3 (input) */ \
|
|
|
|
"gi" (type), /* 4 */ \
|
|
|
|
"g" (mtxp) /* 5 */ \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "cc", "memory", "ecx", "edx" /* used */ ); \
|
2000-09-07 01:33:02 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get a lock without any recursion handling. Calls the hard enter function if
|
|
|
|
* we can't get it inline.
|
|
|
|
*/
|
|
|
|
#define _getlock_norecurse(mtxp, tid, type) ({ \
|
2001-01-16 03:45:54 +00:00
|
|
|
int _res = MTX_UNOWNED; \
|
2000-09-07 01:33:02 +00:00
|
|
|
\
|
|
|
|
__asm __volatile ( \
|
|
|
|
" " MPLOCKED "" \
|
|
|
|
" cmpxchgl %2,%1;" /* Try */ \
|
|
|
|
" jz 1f;" /* got it */ \
|
|
|
|
" pushl %3;" \
|
|
|
|
" pushl %4;" \
|
|
|
|
" call mtx_enter_hard;" /* mtx_enter_hard(mtxp, type) */ \
|
|
|
|
" addl $8,%%esp;" \
|
|
|
|
"1:" \
|
|
|
|
"# getlock_norecurse" \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "+a" (_res), /* 0 */ \
|
2000-09-07 01:33:02 +00:00
|
|
|
"+m" (mtxp->mtx_lock) /* 1 */ \
|
|
|
|
: "r" (tid), /* 2 (input) */ \
|
|
|
|
"gi" (type), /* 3 */ \
|
|
|
|
"g" (mtxp) /* 4 */ \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "cc", "memory", "ecx", "edx" /* used */ ); \
|
2000-09-07 01:33:02 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release a sleep lock assuming we haven't recursed on it, recursion is handled
|
|
|
|
* in the hard function.
|
|
|
|
*/
|
|
|
|
#define _exitlock_norecurse(mtxp, tid, type) ({ \
|
|
|
|
int _tid = (int)(tid); \
|
|
|
|
\
|
|
|
|
__asm __volatile ( \
|
|
|
|
" " MPLOCKED "" \
|
|
|
|
" cmpxchgl %4,%0;" /* try easy rel */ \
|
|
|
|
" jz 1f;" /* released! */ \
|
|
|
|
" pushl %2;" \
|
|
|
|
" pushl %3;" \
|
|
|
|
" call mtx_exit_hard;" \
|
|
|
|
" addl $8,%%esp;" \
|
|
|
|
"1:" \
|
|
|
|
"# exitlock_norecurse" \
|
|
|
|
: "+m" (mtxp->mtx_lock), /* 0 */ \
|
|
|
|
"+a" (_tid) /* 1 */ \
|
|
|
|
: "gi" (type), /* 2 (input) */ \
|
|
|
|
"g" (mtxp), /* 3 */ \
|
|
|
|
"r" (MTX_UNOWNED) /* 4 */ \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "cc", "memory", "ecx", "edx" /* used */ ); \
|
2000-09-07 01:33:02 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release a sleep lock when its likely we recursed (the code to
|
|
|
|
* deal with simple recursion is inline).
|
|
|
|
*/
|
|
|
|
#define _exitlock(mtxp, tid, type) ({ \
|
|
|
|
int _tid = (int)(tid); \
|
|
|
|
\
|
|
|
|
__asm __volatile ( \
|
|
|
|
" " MPLOCKED "" \
|
|
|
|
" cmpxchgl %5,%0;" /* try easy rel */ \
|
|
|
|
" jz 1f;" /* released! */ \
|
|
|
|
" testl $" _V(MTX_RECURSE) ",%%eax;" /* recursed? */ \
|
|
|
|
" jnz 3f;" /* handle recursion */ \
|
|
|
|
/* Lock not recursed and contested: do the hard way */ \
|
|
|
|
" pushl %3;" \
|
|
|
|
" pushl %4;" \
|
|
|
|
" call mtx_exit_hard;" /* mtx_exit_hard(mtxp,type) */ \
|
|
|
|
" addl $8,%%esp;" \
|
|
|
|
" jmp 1f;" \
|
|
|
|
/* lock recursed, lower recursion level */ \
|
2000-09-08 21:48:06 +00:00
|
|
|
"3: decl %1;" /* one less level */ \
|
2000-09-07 01:33:02 +00:00
|
|
|
" jnz 1f;" /* still recursed, done */ \
|
|
|
|
" lock; andl $~" _V(MTX_RECURSE) ",%0;" /* turn off recurse flag */ \
|
|
|
|
"1:" \
|
|
|
|
"# exitlock" \
|
|
|
|
: "+m" (mtxp->mtx_lock), /* 0 */ \
|
|
|
|
"+m" (mtxp->mtx_recurse), /* 1 */ \
|
|
|
|
"+a" (_tid) /* 2 */ \
|
|
|
|
: "gi" (type), /* 3 (input) */ \
|
|
|
|
"g" (mtxp), /* 4 */ \
|
|
|
|
"r" (MTX_UNOWNED) /* 5 */ \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "cc", "memory", "ecx", "edx" /* used */ ); \
|
2000-09-07 01:33:02 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release a spin lock (with possible recursion).
|
|
|
|
*
|
2001-01-16 03:45:54 +00:00
|
|
|
* We use xchgl to clear lock (instead of simple store) to flush posting
|
2000-09-07 01:33:02 +00:00
|
|
|
* buffers and make the change visible to other CPU's.
|
|
|
|
*/
|
- Make the mutex code almost completely machine independent. This greatly
reducues the maintenance load for the mutex code. The only MD portions
of the mutex code are in machine/mutex.h now, which include the assembly
macros for handling mutexes as well as optionally overriding the mutex
micro-operations. For example, we use optimized micro-ops on the x86
platform #ifndef I386_CPU.
- Change the behavior of the SMP_DEBUG kernel option. In the new code,
mtx_assert() only depends on INVARIANTS, allowing other kernel developers
to have working mutex assertiions without having to include all of the
mutex debugging code. The SMP_DEBUG kernel option has been renamed to
MUTEX_DEBUG and now just controls extra mutex debugging code.
- Abolish the ugly mtx_f hack. Instead, we dynamically allocate
seperate mtx_debug structures on the fly in mtx_init, except for mutexes
that are initiated very early in the boot process. These mutexes
are declared using a special MUTEX_DECLARE() macro, and use a new
flag MTX_COLD when calling mtx_init. This is still somewhat hackish,
but it is less evil than the mtx_f filler struct, and the mtx struct is
now the same size with and without mutex debugging code.
- Add some micro-micro-operation macros for doing the actual atomic
operations on the mutex mtx_lock field to make it easier for other archs
to override/optimize mutex ops if needed. These new tiny ops also clean
up the code in some places by replacing long atomic operation function
calls that spanned 2-3 lines with a short 1-line macro call.
- Don't call mi_switch() from mtx_enter_hard() when we block while trying
to obtain a sleep mutex. Calling mi_switch() would bogusly release
Giant before switching to the next process. Instead, inline most of the
code from mi_switch() in the mtx_enter_hard() function. Note that when
we finally kill Giant we can back this out and go back to calling
mi_switch().
2000-10-20 07:26:37 +00:00
|
|
|
#define _exitlock_spin(mtxp) ({ \
|
2000-09-07 01:33:02 +00:00
|
|
|
int _res; \
|
|
|
|
\
|
|
|
|
__asm __volatile ( \
|
2000-12-07 02:23:16 +00:00
|
|
|
" movl %1,%2;" \
|
|
|
|
" decl %2;" \
|
2000-09-07 01:33:02 +00:00
|
|
|
" js 1f;" \
|
2000-12-07 02:23:16 +00:00
|
|
|
" movl %2,%1;" \
|
2000-09-07 01:33:02 +00:00
|
|
|
" jmp 2f;" \
|
2001-01-16 03:45:54 +00:00
|
|
|
"1: movl $ " _V(MTX_UNOWNED) ",%2;" \
|
- Make the mutex code almost completely machine independent. This greatly
reducues the maintenance load for the mutex code. The only MD portions
of the mutex code are in machine/mutex.h now, which include the assembly
macros for handling mutexes as well as optionally overriding the mutex
micro-operations. For example, we use optimized micro-ops on the x86
platform #ifndef I386_CPU.
- Change the behavior of the SMP_DEBUG kernel option. In the new code,
mtx_assert() only depends on INVARIANTS, allowing other kernel developers
to have working mutex assertiions without having to include all of the
mutex debugging code. The SMP_DEBUG kernel option has been renamed to
MUTEX_DEBUG and now just controls extra mutex debugging code.
- Abolish the ugly mtx_f hack. Instead, we dynamically allocate
seperate mtx_debug structures on the fly in mtx_init, except for mutexes
that are initiated very early in the boot process. These mutexes
are declared using a special MUTEX_DECLARE() macro, and use a new
flag MTX_COLD when calling mtx_init. This is still somewhat hackish,
but it is less evil than the mtx_f filler struct, and the mtx struct is
now the same size with and without mutex debugging code.
- Add some micro-micro-operation macros for doing the actual atomic
operations on the mutex mtx_lock field to make it easier for other archs
to override/optimize mutex ops if needed. These new tiny ops also clean
up the code in some places by replacing long atomic operation function
calls that spanned 2-3 lines with a short 1-line macro call.
- Don't call mi_switch() from mtx_enter_hard() when we block while trying
to obtain a sleep mutex. Calling mi_switch() would bogusly release
Giant before switching to the next process. Instead, inline most of the
code from mi_switch() in the mtx_enter_hard() function. Note that when
we finally kill Giant we can back this out and go back to calling
mi_switch().
2000-10-20 07:26:37 +00:00
|
|
|
" pushl %3;" \
|
2001-01-16 03:45:54 +00:00
|
|
|
" xchgl %2,%0;" \
|
- Make the mutex code almost completely machine independent. This greatly
reducues the maintenance load for the mutex code. The only MD portions
of the mutex code are in machine/mutex.h now, which include the assembly
macros for handling mutexes as well as optionally overriding the mutex
micro-operations. For example, we use optimized micro-ops on the x86
platform #ifndef I386_CPU.
- Change the behavior of the SMP_DEBUG kernel option. In the new code,
mtx_assert() only depends on INVARIANTS, allowing other kernel developers
to have working mutex assertiions without having to include all of the
mutex debugging code. The SMP_DEBUG kernel option has been renamed to
MUTEX_DEBUG and now just controls extra mutex debugging code.
- Abolish the ugly mtx_f hack. Instead, we dynamically allocate
seperate mtx_debug structures on the fly in mtx_init, except for mutexes
that are initiated very early in the boot process. These mutexes
are declared using a special MUTEX_DECLARE() macro, and use a new
flag MTX_COLD when calling mtx_init. This is still somewhat hackish,
but it is less evil than the mtx_f filler struct, and the mtx struct is
now the same size with and without mutex debugging code.
- Add some micro-micro-operation macros for doing the actual atomic
operations on the mutex mtx_lock field to make it easier for other archs
to override/optimize mutex ops if needed. These new tiny ops also clean
up the code in some places by replacing long atomic operation function
calls that spanned 2-3 lines with a short 1-line macro call.
- Don't call mi_switch() from mtx_enter_hard() when we block while trying
to obtain a sleep mutex. Calling mi_switch() would bogusly release
Giant before switching to the next process. Instead, inline most of the
code from mi_switch() in the mtx_enter_hard() function. Note that when
we finally kill Giant we can back this out and go back to calling
mi_switch().
2000-10-20 07:26:37 +00:00
|
|
|
" popfl;" \
|
2000-09-07 01:33:02 +00:00
|
|
|
"2:" \
|
|
|
|
"# exitlock_spin" \
|
|
|
|
: "+m" (mtxp->mtx_lock), /* 0 */ \
|
|
|
|
"+m" (mtxp->mtx_recurse), /* 1 */ \
|
2001-01-16 03:45:54 +00:00
|
|
|
"=r" (_res) /* 2 */ \
|
2001-03-28 02:40:47 +00:00
|
|
|
: "g" (mtxp->mtx_savecrit) /* 3 */ \
|
2001-01-16 03:45:54 +00:00
|
|
|
: "cc", "memory", "ecx" /* used */ ); \
|
2000-09-07 01:33:02 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
#endif /* I386_CPU */
|
|
|
|
|
2001-01-21 22:34:43 +00:00
|
|
|
#undef _V
|
|
|
|
|
2000-09-08 21:48:06 +00:00
|
|
|
#endif /* _KERNEL */
|
2000-09-07 01:33:02 +00:00
|
|
|
|
|
|
|
#else /* !LOCORE */
|
|
|
|
|
|
|
|
/*
|
2001-01-20 04:14:25 +00:00
|
|
|
* Simple assembly macros to get and release mutexes.
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
*
|
|
|
|
* Note: All of these macros accept a "flags" argument and are analoguous
|
|
|
|
* to the mtx_lock_flags and mtx_unlock_flags general macros. If one
|
|
|
|
* desires to not pass a flag, the value 0 may be passed as second
|
|
|
|
* argument.
|
|
|
|
*
|
|
|
|
* XXX: We only have MTX_LOCK_SPIN and MTX_UNLOCK_SPIN for now, since that's
|
|
|
|
* all we use right now. We should add MTX_LOCK and MTX_UNLOCK (for sleep
|
|
|
|
* locks) in the near future, however.
|
2000-09-07 01:33:02 +00:00
|
|
|
*/
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
#define MTX_LOCK_SPIN(lck, flags) \
|
|
|
|
pushl %eax ; \
|
|
|
|
pushl %ecx ; \
|
|
|
|
pushl %ebx ; \
|
|
|
|
movl $(MTX_UNOWNED) , %eax ; \
|
|
|
|
movl PCPU(CURPROC), %ebx ; \
|
|
|
|
pushfl ; \
|
|
|
|
popl %ecx ; \
|
|
|
|
cli ; \
|
|
|
|
MPLOCKED cmpxchgl %ebx, lck+MTX_LOCK ; \
|
|
|
|
jz 2f ; \
|
|
|
|
cmpl lck+MTX_LOCK, %ebx ; \
|
|
|
|
je 3f ; \
|
|
|
|
pushl $0 ; \
|
|
|
|
pushl $0 ; \
|
|
|
|
pushl %ecx ; \
|
|
|
|
pushl $flags ; \
|
|
|
|
pushl $lck ; \
|
|
|
|
call _mtx_lock_spin ; \
|
|
|
|
addl $0x14, %esp ; \
|
|
|
|
jmp 1f ; \
|
|
|
|
3: movl lck+MTX_RECURSECNT, %ebx ; \
|
|
|
|
incl %ebx ; \
|
|
|
|
movl %ebx, lck+MTX_RECURSECNT ; \
|
|
|
|
jmp 1f ; \
|
2001-03-28 02:40:47 +00:00
|
|
|
2: movl %ecx, lck+MTX_SAVECRIT ; \
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
1: popl %ebx ; \
|
|
|
|
popl %ecx ; \
|
|
|
|
popl %eax
|
|
|
|
|
|
|
|
#define MTX_UNLOCK_SPIN(lck) \
|
|
|
|
pushl %edx ; \
|
|
|
|
pushl %eax ; \
|
2001-03-28 02:40:47 +00:00
|
|
|
movl lck+MTX_SAVECRIT, %edx ; \
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
movl lck+MTX_RECURSECNT, %eax ; \
|
|
|
|
testl %eax, %eax ; \
|
|
|
|
jne 2f ; \
|
|
|
|
movl $(MTX_UNOWNED), %eax ; \
|
|
|
|
xchgl %eax, lck+MTX_LOCK ; \
|
|
|
|
pushl %edx ; \
|
|
|
|
popfl ; \
|
|
|
|
jmp 1f ; \
|
|
|
|
2: decl %eax ; \
|
|
|
|
movl %eax, lck+MTX_RECURSECNT ; \
|
|
|
|
1: popl %eax ; \
|
|
|
|
popl %edx
|
2000-09-07 01:33:02 +00:00
|
|
|
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
/*
|
|
|
|
* XXX: These two are broken right now and need to be made to work for
|
|
|
|
* XXX: sleep locks, as the above two work for spin locks. We're not in
|
|
|
|
* XXX: too much of a rush to do these as we do not use them right now.
|
|
|
|
*/
|
2001-01-20 04:14:25 +00:00
|
|
|
#define MTX_ENTER(lck, type) \
|
|
|
|
pushl $0 ; /* dummy __LINE__ */ \
|
|
|
|
pushl $0 ; /* dummy __FILE__ */ \
|
|
|
|
pushl $type ; \
|
|
|
|
pushl $lck ; \
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
call _mtx_lock_XXX ; \
|
2001-01-20 04:14:25 +00:00
|
|
|
addl $16,%esp
|
|
|
|
|
|
|
|
#define MTX_EXIT(lck, type) \
|
|
|
|
pushl $0 ; /* dummy __LINE__ */ \
|
|
|
|
pushl $0 ; /* dummy __FILE__ */ \
|
|
|
|
pushl $type ; \
|
|
|
|
pushl $lck ; \
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
call _mtx_unlock_XXX ; \
|
2001-01-20 04:14:25 +00:00
|
|
|
addl $16,%esp
|
2000-12-12 03:49:58 +00:00
|
|
|
|
2000-09-08 21:48:06 +00:00
|
|
|
#endif /* !LOCORE */
|
|
|
|
#endif /* __MACHINE_MUTEX_H */
|