只有多任务系统才需要mutex,这点应该不用解释,在l4系统中实现mutex 的本质
就是让无法获得mutex的任务,通过调度交出当前运行权,交由其他任务继续运行,
当获得mutex的任务在释放mutex时,如果发现有对metex的lock请求,也同样交出运行权,
然后前面无法获得mutex的任务或将继续运行,重新进行lock mutex测试,然后继续上面的流程,
获得就继续运行,没有获得就交出运行权
先看下mutex的结构:
- struct mutex {
- L4_Word_t fHolder;
- L4_Word_t fNeeded;
- L4_Word_t fCount;
- };
具体的流程图如下:
上图中如果 mutex lock 不成功,调用thread_swith切换到fHolder所保存的 ,已经成功mutex lock的
的thread
实现代码:
- stmdb sp!, {r4, r5, lr} /* r4 and r5 are local variables,
- lr needed when we do the syscall */
- /* r4 -- saved lock address */
- ldr r4, [r0]
- /* Here we load the utcb address */
- mov r3, #0xff000000
- /* r5 -- saved UTCB address ,liunote see arch\arm\libs\l4\include\vregs.h */
- ldr r5, [r3, #0xff0] /* uctb => 0xff000ff0 */
- /* From here r4 and r5 are safe, the thread_switch
- syscall will not trash these registers */
- /* r0 is tmp */
- /* First we set the point at which we want to
- be restarted in case of preemption */
- adr r0, preempt_handler
- str r0, [r5, #__L4_TCR_PREEMPT_CALLBACK_IP*4] /* preempt_callback_ip */
- /* And then we enable the preemption callback to
- occur */
- mov r0, #32
- strb r0, [r5, #TCR_PREEMPT_FLAGS] /* arch\arm\libs\l4\include\vregs.h __L4_TCR_PREEMPT_FLAGS 's last byte !!! */
- LABEL(preempt_handler) /* If preempt we restart here */
- /* r0 is lock holder */
- ldr r0, [r4]
- /* r1 is me (real tid is in the user-defined handle)*/
- ldr r1, [r5, #__L4_TCR_USER_DEFINED_HANDLE*4]
- /* test if lock holder is == 0 */
- cmp r0, #0 /* mutex-> fHolder 为0,表示没有被占*/
- beq grab_lock /* liunote , get lock ok !!! */
- /* or if lock holder is me */
- cmp r0, r1
- beq exit_path /* We already have the lock so we jump forward to
- the part where we turn off preemption and return */
- /* we couldn't get the lock so we fall through to here */
- /* r0 holds lock holder, will be argument to the system call */
- /* r1 is temp */
- /* Load syscall ptr */ /* liunote : r0 is lock holder (mutex-> fHolder), 然后L4_ThreadSwitch 切换到lock holer 去了 */
- ldr ip, =L4_ThreadSwitch
- mov r1, #1
- str r1, [r4, #4] /* Let current lock holder know there is contention liunote [r4,#4] ==> mutex -> fNeeded =1 ,让目前holder 住的thread 知道有其他mutex 请求
- so that it knows to yield at the end of its timeslice , 这样时间片到了要放弃,或者unlock muxtex时主动放弃*/
- /* Load branch address */
- ldr ip, [ip]
- stmdb sp!, {r4-r11}
- mov lr, pc
- /* do the system call */
- mov pc, ip
- ldmia sp!, {r4-r11}
- /* After syscall return to preempt_handler */ /* 没有lock 住的thread 到这里thread switch , 然后会切回来继续执行lock !!! */
- b preempt_handler
- LABEL(grab_lock)
- /* The lock is free -- we try to grab it before being preempted */
- /* r0 is tmp */
- mov r0, #0
- str r0, [r4, #4] /* If we get this far, then noone of a higher priority than liunote [r4,#4] ==> mutex -> fNeeded =0
- us wants the lock, so we can unset the yield needed flag */
- /* Now we store ourself as the lock handler, this is transaction complete, although
- we still might be preempted right here, in which case we validaly have the lock
- and the preempt handler will go through sucessfully */
- str r1, [r4] /* mutex-> fHolder = thread user define handler (__L4_TCR_USER_DEFINED_HANDLE) !!! */
- strb r0, [r5, #TCR_PREEMPT_FLAGS] /* liunote 设置utcb的__L4_TCR_PREEMPT_FLAGS 最后1byte 为0 */
- ldmia sp!, {r4, r5, pc} /* RETURN POINT */
- LABEL(exit_path)
- /* Exit path that occurs if we were preempted, before returning --
- same as above, however we need to zero, r0 first */
- mov r0, #0
- strb r0, [r5, #TCR_PREEMPT_FLAGS]
- ldmia sp!, {r4, r5, pc} /* RETURN POINT */
mutex unlock 的实现很简单:
- struct mutex *mtx = (struct mutex *) *mutex;
- mtx->fHolder = 0;
- if (mtx->fNeeded) {
- mtx->fNeeded = 0;
- L4_ThreadSwitch(L4_nilthread); /*
- }
关于L4_ThreadSwitch 切到nil thread,表示放弃运行,交由系统调度
阅读(1863) | 评论(0) | 转发(0) |