I was looking at this implementation of spinlocks, and in particular, the acquire and release functions:
void
acquire(struct spinlock *lk)
{
pushcli(); // disable interrupts to avoid deadlock.
if(holding(lk))
panic("acquire");
// The xchg is atomic.
// It also serializes, so that reads after acquire are not
// reordered before it.
while(xchg(&lk->locked, 1) != 0)
;
lk->cpu = cpu;
getcallerpcs(&lk, lk->pcs);
}
// Release the lock.
void
release(struct spinlock *lk)
{
if(!holding(lk))
panic("release");
lk->pcs[0] = 0;
lk->cpu = 0;
xchg(&lk->locked, 0);
popcli();
}
What is the purpose of the pushcli()
and popcli()
if the xchg function is atomic? Wouldn't atomicity ensure that only one thread is able to change the value of the lock at any instance and not be interrupted? Why do we have to explicitly disable interruptions to prevent deadlocks?