OS中很多操作是必须保证不被打断的,方法有很多,比如禁止中断,采用信号灯建立临界区等等。相对于粗鲁地禁止掉中断,利用临界区的方法更加灵活。
临界区的实现依赖于对某一参考数据的原子修改。
在x86中,使用了带前缀lock的test and set指令来实现对信号的原子修改。
在MIPS中用了一种新方法:配套使用ll(link load,链接加载)和sc(store conditionally,条件存储)指令。硬件保证自最后的ll开始,如果后继执行没有竞争发生(当前指令流没有被中断过),sc才会成功地写指定位置,并且它还会返回一个0或者1的值到寄存器中指示成功还是失败。1为成功,0为失败。比如:
ll t1, 0(t0) #执行ll指令,硬件开始监控
#some other insts here, modify t1, set sem, etc
sc t1, 0(t0) #执行是否成功依赖于前面是否发生过竞争
beq t1, zero, TryAgain
如果以上代码没有被中断(竞争未发生),则sc执行后t1寄存器内保存的值被设置为1,否则被设置为0。
有了ll/sc,我们可以确切地知道信号灯是否设置成功,于是也就可以实现临界区了。ll/sc是为多处理器引入的,但是,即使在单处理器环境下它同样适用。它避免了禁用中断的问题,可以减少最坏情况下中断延迟时带来的影响。
Reference:《See MIPS Run 2nd》 5.8.4