深入讲解读写信号量(下)

接上文深入讲解读写信号量(上)

(3)乐观自旋

① rwsem_can_spin_on_owner

rwsem_can_spin_on_owner用于判断当前任务是否可以进行乐观自旋

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

② rwsem_spin_on_owner

rwsem_spin_on_owner 是rwsem自旋实现的地方,从字面就可以看出,它会不停的去查询owner的状态,实现自旋

与乐观自旋owner state相关的状态

乐观自旋失败总结:

1.writer持锁

a.reader/writer乐观自旋失败原因:need_resched() || writer不在cpu上 || nonspinable

2.reader持锁

a.reader乐观自旋失败原因:nonspinable || (handoff标记 && (need_resched() || rt_task ))

b.writer乐观自旋失败原因:nonspinable || need_reshced() || timeout || rt_task

Writer乐观自旋尝试持锁

Reader乐观自旋尝试持锁

乐观自旋成功后:

3. read持锁慢速路径

4. read持锁总结

1.reader持锁前,没有其它人持锁,快速路径中持锁成功

2.reader持锁前,有reader持锁,但是没有writer等待,没有设置handoff标记,reader持锁数量没有溢出,快速路径中持锁成功

3.reader持锁前,有reader持锁,但是有writer等待

a.乐观自旋中,拿到了osq锁,进入乐观自旋,没有设置handoff标记,则持锁成功

b.乐观自旋失败,走慢速路径,睡眠等待被唤醒

4.reader持锁前,有writer持锁,乐观自旋失败后,走慢速路径,睡眠等待被唤醒

5. read释放锁

六、rwsem write

同read一样,write持锁也有3种状态

快速路径

中速路径

慢速路径

1. write持锁快速路径

write持锁快速路径比较简单,直接调用

atomic_long_try_cmpxchg_acquire(&sem->count, &tmp, RWSEM_WRITER_LOCKED)

只有当锁没有人持有时,才能成功

2. write持锁中速路径

与reader持锁的实现是一模一样的

3.write持锁慢速路径

(1)handoff

设置RWSEM_FLAG_HANDOFF 的作用:防止处于wait list第一个等待者饿死

因为加入了osq乐观自旋,存在一种情况,任务持锁失败,被挂入wait list中的第一个,同时也存在处于rwsem乐观自旋状态的任务,owner释放了锁,那么该锁大概率会被乐观自旋的任务抢走,如果持续的有乐观自旋状态任务来抢锁,那么wait list中的任务可能会被饿死。

1.rwsem_try_read_lock_unqueued/rwsem_try_write_lock_unqueued时会直接返回

2.reader持锁情况下,另外的reader再来持锁时,也不会成功

3.rwsem_down_read_slowpath 时,如果wait list空的,且是writer持锁或者设置了handoff则不能获得锁(正常是可以的,因为是读者持锁)

4.rwsem_try_write_lock 时,可以直接返回

设置RWSEM_FLAG_HANDOFF的地方

1.在rwsem_down_write_slowpath 慢速路径被唤醒后,如果满足这个条件(wstate == WRITER_FIRST) && (rt_task(current) || time_after(jiffies, waiter.timeout),会将wstate 设置成WRITER_HANDOFF,然后调用rwsem_try_write_lock去拿锁,若锁还有人持有,则将RWSEM_FLAG_HANDOFF 标志置上,这样在其它任务正常的路径上拿锁就不会成功了。

2.在rwsem_mark_wake 流程中,如果是writer持锁,wait list第一个等待者是reader且超过timeout的时间没有拿到锁,也会把RWSEM_FLAG_HANDOFF 标志置上。

1.如果已经设置了handoff 且 wstate == WRITER_NOT_FIRST,则直接返回,在rwsem_mark_wake 里,如果reader等的时间太长,会设置handoff bit,不能让reader饿死。

  1. 锁被持有的情况,如果设置了handeroff 或者不是WRITER_HANDOFF,则直接return false。否则把handoff标置设上,然后也会return false,第二次进来的时候,如果没有人持锁,这个线程就能持锁成功,这是为了避免在这个线程被唤醒后,被spiner把锁给偷了2次。

(2)慢速路径过程

  1. 如果设置了WRITER_HANDOFF,则直接调用rwsem_spin_on_owner,如果返回的是无人持锁,则直接去拿锁,就不需要睡眠了。

  2. 如果WRITER_HANDOFF 已经设置了,就不走后面的流程了,因为后面的流程也是为了设置handoff标记。

  3. 是第一个waiter 且 是rt task 或者 超时了,会设置writer_handoff标记,这个标记可以让这个线程不会被spiner把锁再次偷走为什么要判断这个,设想一个场景,假设该writer从睡眠被唤醒,说明锁被释放后把它唤醒了,它本来可以去拿到锁,但是失败了,说明被spiner偷走了为了防止这个现象再次发生,就要设置handoff 标记,让其它人偷不了锁。

4. write释放锁

七、总结

文中所讲的有很大一部分都是源码,很细节的东西。如果大家看的云里雾里的,不要怀疑自己。尽管文档是我一字一句写出来的,并且反复回味了非常多遍,但是我在碰到很细节的问题时,仍然要回头再去看文档的描述才能弄清楚原因。对于读写信号量,我的建议如下:

1.只想了解个大概。可以看下rwsem的结构,osq的概念,搞懂reader/writer持锁后,又有reader/writer进来持锁以及有乐观自旋任务的情况下,会有哪些可能即可。

2.想深入弄懂原理。对着代码好好研究一番。rwsem还是会复杂一些,弄清除了这个,再看其它锁的实现时,应该会更得心应手了。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值