Information Technology Reference
In-Depth Information
/*
*Lockamutex(possiblyinterruptible),slowpath:
*/
staticinlineint__sched
__mutex_lock_common(structmutex*lock)
{
structtask_struct*task=current;
structmutex_waiterwaiter;
unsignedlongflags;
preempt_disable();
spin_lock_mutex(&lock->wait_lock,flags);
/*addwaitingtaskstotheendofthewaitqueue(FIFO):*/
list_add_tail(&waiter.list,&lock->wait_list);
waiter.task=task;
As shown in the excerpt above, the thread first disables interrupts, grabs
the lock's
waitlock
guard, and adds itself to the locks's
waitlist
.
Next in
mutexlockcommon()
is the main loop:
for(;;){
/*
*Letstrytotakethelockagain-thisisneededevenif
*wegethereforthefirsttime(shortlyafterfailingto
*acquirethelock),tomakesurethatwegetawakeuponce
*it'sunlocked.Lateron,ifwesleep,thisisthe
*operationthatgivesusthelock.Wexchgitto-1,so
*thatwhenwereleasethelock,weproperlywakeupthe
*otherwaiters:
*/
if(atomic_xchg(&lock->count,-1)==1)
break;
/*didntgetthelock,gotosleep:*/
spin_unlock_mutex(&lock->wait_lock,flags);
preempt_enable_no_resched();
schedule();
preempt_disable();
spin_lock_mutex(&lock->wait_lock,flags);
}
In this loop, the thread atomically swaps the value of the lock with -1 using an
atomic read-modify-write
atomicxchg
instruction. If the previous state was 1
(free), the lock is now owned by the calling thread, and it breaks out of the loop.
Otherwise, the thread clears the
waitlock
spinlock guard, moves itself off the
ready queue, reenables interrupts (
preemptenablenoresched()
), and sus-
pends its own execution to switch the processor to another thread (
schedule()
).
Later, when the thread runs again, it returns from
schedule()
, disables
interrupts, and reacquires the lock's guard.
Eventually, the thread breaks out of the loop, which means that it found a
moment when the lock was in the free state (the lock's
count
was 1), and at
that moment it set the lock to the \busy, possible waiters" state (by setting
count=-1
.) The thread now has the lock, and it cleans up before exiting the
acquire slow path as follows:
/*gotthelock-rejoice!*/