lockdep_assert_held() 是 Linux 内核中的一个断言宏,用于验证在代码执行到特定点时,指定的锁已经被持有。这是一种锁定点注释机制,属于 Linux 内核死锁检测系统 Lockdep 的一部分[5][6]。
工作原理
lockdep_assert_held() 宏的主要功能是在运行时验证锁的状态,确保在执行关键代码段时,必要的锁已经被获取。这有助于防止由于锁使用不当而导致的并发问题,例如竞态条件和死锁。
在 Linux 内核源码中,我们可以看到它的实际应用场景:
void resched_curr(struct rq *rq)
{
struct task_struct *curr = rq->curr;
int cpu;
lockdep_assert_held(&rq->lock);
/* 检查当前进程是否已经设置了调度标志,如果是,则不用再设置一遍,直接返回 */
if (test_tsk_need_resched(curr))
return;
/* 根据rq获取CPU */
cpu = cpu_of(rq);
/* 如果CPU = 当前CPU,则设置当前进程需要调度标志 */
if (cpu == smp_processor_id()) {
/* 设置当前进程需要被调度出去的标志,这个标志保存在进程的thread_info结构上 */
set_tsk_need_resched(curr);
/* 设置CPU的内核抢占 */
set_preempt_need_resched();
return;
}
/* 如果不是处于当前CPU上,则设置当前进程需要调度,并通知其他CPU */
if (set_nr_and_not_polling(curr))
smp_send_reschedule(cpu);
else
trace_sched_wake_idle_without_ipi(cpu);
}
在这个例子中,lockdep_assert_held(&rq->lock) 确保在执行 resched_curr() 函数时,运行队列的锁 rq->lock 已经被持有[1]。
使用场景
lockdep_assert_held() 主要在以下场景中使用:
-
关键代码段保护:确保在访问共享资源时已经获取了适当的锁。
-
调度器代码:如上例所示,在进程调度相关的代码中,确保在修改运行队列状态时持有相应的锁[1][7]。
-
驱动程序开发:在设备驱动程序中保护共享资源访问[5]。
-
防止死锁:作为 Lockdep 系统的一部分,帮助开发者识别潜在的死锁问题[6]。
与其他锁断言的区别
Linux 内核中还有其他类似的锁断言宏,如:
- lockdep_assert_not_held():断言指定的锁当前未被持有
- lockdep_is_held():检查锁是否被持有,但不会断言失败
这些断言宏在开发和调试阶段非常有用,可以帮助开发者验证锁的使用是否符合预期,从而减少并发相关的错误。
在实际应用中,lockdep_assert_held() 是一种防御性编程技术,有助于确保代码的并发安全性,特别是在复杂的内核子系统中,如进程调度器、内存管理器等。
Citations:
[1] https://www.cnblogs.com/tolimit/p/4335681.html
[2] https://www.cnblogs.com/binlovetech/p/17373667.html
[3] https://rebootcat.com/2020/09/26/epoll_cookbook/
[4] https://github.com/gatieme/LDD-LinuxDeviceDrivers/blob/master/study/kernel/01-process/05-schedule/09-tuning/02-sched_feature/README.md
[5] https://github.com/apachecn/apachecn-linux-zh/blob/master/docs/linux-kernel-prog/13.md
[6] https://blog.csdn.net/weixin_43780213/article/details/133639729
[7] https://s3.shizhz.me/linux-sched/cfs-sched/logic-preempt
[8] https://blog.csdn.net/qq_41104683/article/details/132128593