interrupt
[TOC] include/linux/interrupt.hor_softirq_pending 软中断待处理状态12345678DEFINE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat);EXPORT_PER_CPU_SYMBOL(irq_stat);#define local_softirq_pending_ref irq_stat.__softirq_pending#define local_softirq_pending() (__this_cpu_read(local_softirq_pending_ref))#define set_softirq_pending(x) (__this_cpu_write(local_softirq_pending_ref, (x)))#define or_softirq_pending(x) (__this_cpu_or(local_softirq_pending_ref, (x))) raise_timer_softirq 定时器软中断12345678static inli...
irq_work
[toc] include/linux/irq_work.h__IRQ_WORK_INIT1234567#define __IRQ_WORK_INIT(_func, _flags) (struct irq_work){ \ .node = { .u_flags = (_flags), }, \ .func = (_func), \ .irqwait = __RCUWAIT_INITIALIZER(irqwait), \}#define IRQ_WORK_INIT(_func) __IRQ_WORK_INIT(_func, 0) kernel/irq_work.c IRQ上下文延迟工作(IRQ Context Deferred Work) 在安全时机执行来自中断的紧急任务历史与背景这项技术是为了解决什么特定问题而诞生的?kernel/irq_work.c 实现的irq_work机制是为了解决一个非常特殊且棘手的内核同步问题:如何从一个“硬中断(Hard IRQ)”上下文中,安全地执行一个需要“中...
debug_locks
[TOC] debug_locks 各种锁的常用调试工具的通用位置: 自旋锁、rwlocks、mutex 和 rwsems。 debug_locks 的介绍debug_locks 是 Linux 内核中用于调试各种锁(如自旋锁、自读写锁、互斥锁和读写信号量)的工具。它提供了一种机制,用于检测锁的使用错误,并在发现问题时记录或报告相关信息。 特点 全局控制:通过全局标志 debug_locks,可以一次性启用或禁用所有锁的调试功能。 静默模式:支持通过 debug_locks_silent 实现“静默失败”,即在检测到锁错误时不打印任何信息到控制台。 原子操作:使用 xchg 等原子操作确保在多线程环境中安全地切换调试状态。 减少噪声:在检测到第一个锁错误后,可以关闭后续的调试输出,避免日志被大量错误信息淹没。 使用场景 锁错误检测: 在开发和调试阶段,用于检测锁的使用错误,例如死锁、锁未正确释放等问题。 适用于调试自旋锁(spinlock)、读写锁(rwlock)、互斥锁(mutex)和读写信号量(rwsem)等。 内核模块开发: 在开发内核模块时,debug_lo...
local_lock
[toc] include/linux/local_lock.h Per-CPU数据锁(Lock for Per-CPU Data) 一种为保护Per-CPU数据而生的超轻量级锁历史与背景这项技术是为了解决什么特定问题而诞生的?local_lock是一种高度特化的、以性能为首要目标的锁,它的诞生是为了解决一个非常具体的问题:如何以最低的开销来保护Per-CPU(每CPU)数据。 Per-CPU数据是指内核为每个CPU都创建了一个独立副本的数据。理论上,一个CPU上的代码应该只访问自己的那份数据副本。在这种理想情况下,并发访问的来源只有两种: 抢占(Preemption):当前任务在访问Per-CPU数据时被一个更高优先级的任务抢占,而这个新任务也访问了同一个Per-CPU变量。 中断(Interrupts):一个硬中断或软中断在当前CPU上发生,其中断处理程序访问了同一个Per-CPU变量。 传统的解决方案是使用spinlock。但是,spinlock是为解决多CPU(SMP)间的并发而设计的,它涉及到昂贵的原子操作和可能导致缓存行争用的内存总线流量。对于...
rwlock
[toc] include/linux/rwlock.h 读写锁(Read-Write Lock) 允许多读者并发访问的同步原语历史与背景这项技术是为了解决什么特定问题而诞生的?读写锁(Read-Write Lock, rwlock)是为了解决一个非常普遍的并发访问模式的性能问题:对共享数据的访问是“读多写少”。 在使用简单的互斥锁(mutex)或自旋锁(spinlock)时,任何时候都只允许一个任务进入临界区,无论它是读取还是写入。这对于读操作来说是过度限制的,因为读操作本身不会修改数据,允许多个读者同时读取是安全的。如果一个数据结构被内核中成百上千个地方频繁地读取,而只被少数几个地方偶尔写入,那么使用互斥锁会导致所有读者被迫串行执行,极大地降低了系统的并发性能。 rwlock的诞生就是为了优化这种场景。它提供了一种更精细的锁定机制: 读锁(共享锁):允许多个读者同时持有读锁。 写锁(排他锁):与互斥锁一样,任何时候只允许一个写者持有写锁。 互斥规则:当有任何读者持有读锁时,写者必须等待;当有写者持有写锁时,所有读者和其他写者都必须等待。 它的发展经历了...
spinlock
[toc] kernel/locking/spinlock.c 自旋锁(Spinlock) 内核中最基础的高性能对称多处理器(SMP)锁历史与背景这项技术是为了解决什么特定问题而诞生的?自旋锁(Spinlock)是为了解决**对称多处理器(SMP)**系统中最基础的并发控制问题而诞生的:如何保护一段极短的、在任何执行上下文中都可能被访问的临界区。 在单处理器(UP)系统中,要保护一段临界区,最简单的方法是禁用本地中断。这样可以确保在执行临界区代码时,不会被中断处理程序打断,从而避免了并发。 然而,在多处理器(SMP)系统中,禁用本地CPU的中断并不能阻止另一个CPU同时执行并访问同一块共享数据。因此,需要一种CPU之间的互斥机制。自旋锁就是为此设计的最底层、最高效的锁。它主要解决: SMP互斥:提供一种在多个CPU之间进行互斥的机制。 原子上下文(Atomic Context)保护:中断处理程序、软中断、tasklet等上下文是不能睡眠的。自旋锁通过“忙等待”而不是“睡眠”来等待锁,因此它是唯一可以在这些原子上下文中安全使用的锁类型。 它的发展经历了哪些重...
seqlock
[toc] include/linux/seqlock.h 顺序锁(Sequence Lock) 针对读多写少场景的无锁读者优化历史与背景这项技术是为了解决什么特定问题而诞生的?seqlock(顺序锁)是一种高度特化的同步原语,它的诞生是为了解决一个在传统读写锁(rw_lock)中存在的经典性能问题:写者饥饿(Writer Starvation)。 在标准的读写锁模型中,当一个或多个读者持有读锁时,任何试图获取写锁的写者都必须等待。如果读者频繁地、接连不断地到来,那么写者可能会被无限期地延迟,即“饿死”。这在某些读操作极其频繁、写操作较少的场景下会成为严重的性能瓶颈。 seqlock通过颠覆这个模型来解决问题:它赋予写者绝对的优先权。一个写者永远不会被读者阻塞,它可以随时进入临界区并修改数据,即使当时有读者正在读取。为了在这种“不加保护”的读取中保证数据的一致性,它引入了一个序列计数器,让读者自己来检测在读取期间是否有写者介入,并在检测到冲突时进行重试。 它的发展经历了哪些重要的里程碑或版本迭代? 作为一种优化模式被引入:seqlock不是一个通用的锁,而是作...
rwsem
[TOC] kernel/locking/rwsem.c 读写信号量(Read-Write Semaphore) 内核中可睡眠的读写锁历史与背景这项技术是为了解决什么特定问题而诞生的?kernel/locking/rwsem.c 实现的读写信号量(Read-Write Semaphore, rwsem)是为了解决rwlock_t(读写自旋锁)无法解决的一类“读多写少”场景的并发控制问题:当临界区的执行时间较长,或者在临界区内需要睡眠时,如何高效地进行读写并发控制。 rwlock_t是一个自旋锁,它要求临界区必须极短且绝对不能睡眠。然而,在内核的许多路径中(特别是与用户空间交互的系统调用),临界区可能很长,并且包含可能导致睡眠的操作(如copy_from_user、kmalloc(GFP_KERNEL)或等待I/O)。 rwsem正是为了这种可睡眠的、读多写少的场景而设计的。它是一个睡眠锁,提供了与rwlock_t相同的逻辑: 允许多个读者并发进入。 只允许一个写者独占进入。 读者和写者互斥。 当一个任务试图获取一个被占用的rwsem时,它不会自旋...
clocksource
[toc] kernel/time/clocksource.c 时钟源管理(Clocksource Management) 内核时间的原始动力历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了在Linux内核中创建一个统一的、可插拔的硬件时钟源抽象层。内核需要一个可靠的方式来读取时间的流逝,而不同的硬件平台提供了种类繁多的硬件定时器/计数器,例如x86上的TSC和HPET,ARM上的System Counter等。这些硬件在精度、稳定性、访问开销等方面都千差万别。 kernel/time/clocksource.c的诞生就是为了解决这个硬件异构性的问题: 抽象硬件差异:它提供了一个标准的struct clocksource接口,将所有不同硬件定时器的具体实现(如如何读取其计数器)封装起来,为上层的timekeeping子系统提供一个统一的、与硬件无关的视图。 选择最佳时钟源:系统中可能同时存在多个可用的时钟源。内核需要一种机制来评估它们各自的优劣(基于频率、分辨率、稳定性等),并从中自动选择一个最佳的来驱动整个系统的时间。 保证可靠性...
hrtimer
[toc] kernel/time/hrtimer.c 高精度定时器(High-Resolution Timers) 纳秒级精度的事件调度历史与背景这项技术是为了解决什么特定问题而诞生的?kernel/time/hrtimer.c 实现了**高精度定时器(High-Resolution Timers)框架,它的诞生是为了解决内核中日益增长的、对亚毫秒级(sub-millisecond)甚至纳秒级(nanosecond)**定时精度的需求。 传统的jiffies定时器(timer_list)虽然开销极低,但其精度受限于系统的心跳频率HZ(通常在4ms到10ms之间)。这对于许多现代应用来说是完全不够的: 用户空间API支持:POSIX标准定义了nanosleep()、clock_nanosleep()和高精度POSIX定时器,这些API要求内核能够提供远超jiffies精度的定时能力。 多媒体与音频:专业的音频应用为了实现低延迟处理,需要在非常精确的时间点(例如每1-2毫秒)被唤醒来填充声卡缓冲区。 网络与金融:高频交易和某些低延迟网络协议需要对超时进行微秒级...