kernel/spinlock.c
113 lines
1// Mutual exclusion spin locks.23#include "types.h"4#include "param.h"5#include "memlayout.h"6#include "spinlock.h"7#include "riscv.h"8#include "proc.h"9#include "defs.h"1011void12initlock(struct spinlock *lk, char *name)13{14 lk->name = name;15 lk->locked = 0;16 lk->cpu = 0;17}1819// Acquire the lock.20// Loops (spins) until the lock is acquired.21void22acquire(struct spinlock *lk)23{24 push_off(); // disable interrupts to avoid deadlock.25 if(holding(lk))26 panic("acquire");2728 // On RISC-V, sync_lock_test_and_set turns into an atomic swap:29 // a5 = 130 // s1 = &lk->locked31 // amoswap.w.aq a5, a5, (s1)32 while(__sync_lock_test_and_set(&lk->locked, 1) != 0)33 ;3435 // Tell the C compiler and the processor to not move loads or stores36 // past this point, to ensure that the critical section's memory37 // references happen strictly after the lock is acquired.38 // On RISC-V, this emits a fence instruction.39 __sync_synchronize();4041 // Record info about lock acquisition for holding() and debugging.42 lk->cpu = mycpu();43}4445// Release the lock.46void47release(struct spinlock *lk)48{49 if(!holding(lk))50 panic("release");5152 lk->cpu = 0;5354 // Tell the C compiler and the CPU to not move loads or stores55 // past this point, to ensure that all the stores in the critical56 // section are visible to other CPUs before the lock is released,57 // and that loads in the critical section occur strictly before58 // the lock is released.59 // On RISC-V, this emits a fence instruction.60 __sync_synchronize();6162 // Release the lock, equivalent to lk->locked = 0.63 // This code doesn't use a C assignment, since the C standard64 // implies that an assignment might be implemented with65 // multiple store instructions.66 // On RISC-V, sync_lock_release turns into an atomic swap:67 // s1 = &lk->locked68 // amoswap.w zero, zero, (s1)69 __sync_lock_release(&lk->locked);7071 pop_off();72}7374// Check whether this cpu is holding the lock.75// Interrupts must be off.76int77holding(struct spinlock *lk)78{79 int r;80 r = (lk->locked && lk->cpu == mycpu());81 return r;82}8384// push_off/pop_off are like intr_off()/intr_on() except that they are matched:85// it takes two pop_off()s to undo two push_off()s. Also, if interrupts86// are initially off, then push_off, pop_off leaves them off.8788void89push_off(void)90{91 int old = intr_get();9293 // disable interrupts to prevent an involuntary context94 // switch while using mycpu().95 intr_off();9697 if(mycpu()->noff == 0)98 mycpu()->intena = old;99 mycpu()->noff += 1;100}101102void103pop_off(void)104{105 struct cpu *c = mycpu();106 if(intr_get())107 panic("pop_off - interruptible");108 if(c->noff < 1)109 panic("pop_off");110 c->noff -= 1;111 if(c->noff == 0 && c->intena)112 intr_on();113}114