Information Technology Reference
In-Depth Information
waitlist
is empty. Finally, if
count
is negative, the lock is locked and there
may be threads on the
waitlist
.
Note that to coordinate the fast and slow paths, the implementation uses
atomic operations whenever it needs to manipulate
count
. Then, as long as a
lock stays in the first two states,
lock()
and
unlock()
stay on their fast paths.
Acquiring the lock. To acquire a lock, a thread calls
mutexlock()
, which
is defined in
kernel/mutex.c
:
voidmutex_lock(structmutex*lock)
{
__mutex_fastpath_lock(&lock->count,__mutex_lock_slowpath);
}
On a 32-bit x86 machine,
mutexfastpathlock()
is defined in
arch/x86/include/asm/mutex32.h
:
/**
*Changethecountfrom1toavaluelowerthan1,andcall<fn>ifit
*wasn't1originally.ThisfunctionMUSTleavethevaluelowerthan1
*evenwhenthe"1"assertionwasn'ttrue.
*/
#define__mutex_fastpath_lock(count,fail_fn)
\
do{
\
unsignedintdummy;
\
asmvolatile(LOCK_PREFIX" decl(%%eax)\n"
\
" jns1f\n"
\
" call"#fail_fn"\n"
\
"1:\n"
\
:"=a"(dummy)
\
:"a"(count)
\
:"memory","ecx","edx");
\
}while(0)
The syntax of this inline assembly is a bit baroque, but the function itself is
simple. Near the end, the notation
:"a"(count)
says that before running this
assembly code, the x86
eax
register should be initialized to hold the parameter
count
; notice from above that
count
holds the address of the mutex's
atomict
count
field. Thus, the first x86 assembly instruction
LOCKPREFIXdecl(%%eax)
is an atomic read-modify-write instruction that reads the old value of count
from memory, decrements it, and stores the new value back to memory; the
LOCKPREFIX
directive tells the assembler to use a version of the decrement
instruction that executes atomically.
The second instruction
jns1f
(\jump if not signed") implements the fast
path. If the new value of
count
is zero, then this conditional jump instruc-
tion jumps to the end of the assembly code snippet (to the
1:
label), and
mutexfastpathlock()
returns. In this case, the lock is acquired in just two
instructions!
On the other hand, if the new value of
count
is negative, the
jns
instruction
falls through, and the
call#failfn
instruction calls the
mutexlockslowpath()
function.
The slowpath function is implemented by
mutexlockcommon()
, as de-
scribed in the following excerpts from
kernel/mutex.c
.