1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| static inline void arch_spin_lock(arch_spinlock_t *lock) { int my_ticket; int tmp; int inc = 0x10000; __asm__ __volatile__ ( " .set push # arch_spin_lock \n" " .set noreorder \n" " \n" "1: ll %[ticket], %[ticket_ptr] \n" # ticket_ptr(lock->lock), 取出lock->lock 到 ticket(tmp) ll 原子操作, 取出一个word " addu %[my_ticket], %[ticket], %[inc] \n" # my_ticket <- ticket(tmp) + 0x10000 这里应该是ticket + 1的意思, ticket自增,即当前的调用取的号+1, " sc %[my_ticket], %[ticket_ptr] \n" # lock->lock <- my_ticket # 把ticket + 1后存回到 lock->ticket, 这个代表更新当前发的所有号, 来了一个新调用, 说明这个调用要抢资源, 给它分一个号 " beqz %[my_ticket], 1b \n" # sc失败, 返回结果0, 跳转回1b, 说明有其他cpu或中断在该指令执行前偷偷调用sc 把 tick_ptr给修改了, 这时sc会失败, 返回1b 重新来这个操作 " srl %[my_ticket], %[ticket], 16 \n" # my_ticket <- ticket(tmp) >> 16 my_ticket <- lock->ticket 换算ticket + 1 " andi %[ticket], %[ticket], 0xffff \n" # ticket(tmp) = ticket(tmp) & 0xffff tmp<- lock->serving_now " bne %[ticket], %[my_ticket], 4f \n" # lock->ticket 与 lock->serving_now 不相等, 调转到 4f, 说明不是本上下文上的锁, 需要等待, 如相等,往下走 !!!! " subu %[ticket], %[my_ticket], %[ticket] \n" # tmp <- lock->serving_now - lock->ticket, 相等的, tmp变成0了, 因为在延迟槽里,不相等的话 tmp <- lock->serving_now - lock->ticket "2: \n" " .subsection 2 \n" # # 程序后半段, !!!! 拼在函数jr ra 后面,正常情况下走不到这里, 注意跳转前 subu %[ticket], %[my_ticket], %[ticket] 在延迟槽里, 总是会执行 "4: andi %[ticket], %[ticket], 0x1fff \n" # lock->ticket 与 lock->serving_now 不相等时,走到这, tmp <- tmp & 0x1fff 取(lock->serving_now)0-12位 " sll %[ticket], 5 \n" # tmp << 5 " \n" "6: bnez %[ticket], 6b \n" # tmp 不为0 , 循环tmp-1, 直到tmp 变成0 " subu %[ticket], 1 \n" # 循环体, 每次tmp-1 " \n" " lhu %[ticket], %[serving_now_ptr] \n" # tmp <- lock->h.serving_now, 这个地方会从内存中更新serving_now, 别的调用方可能会放锁,导致serving_now变化, 因此这里需要更新 " beq %[ticket], %[my_ticket], 2b \n" # my_ticket 与 lock->serving_now 相等,则跳到2b, 调到2b后,函数就可以马上出去了 " subu %[ticket], %[my_ticket], %[ticket] \n" # tmp <- lock->h.serving_now - lock->ticket " b 4b \n" # 回到4b, 重新等 " subu %[ticket], %[ticket], 1 \n" # tmp - 1 " .previous \n" " .set pop \n" : [ticket_ptr] "+m" (lock->lock), [serving_now_ptr] "+m" (lock->h.serving_now), [ticket] "=&r" (tmp), [my_ticket] "=&r" (my_ticket) : [inc] "r" (inc)); smp_llsc_mb(); }
|