hardware-sync
底层硬件自旋锁、内存屏障及处理器事件 API。
详细描述
自旋锁
RP 系列微控制器提供 32 个硬件自旋锁,可用于管理对共享软件和硬件资源的互斥访问。
通常每个自旋锁本身也是一种共享资源,即同一个硬件自旋锁可以被多个高层原语使用(前提是自旋锁既不被长时间持有,也不被同一核心同时与其他自旋锁一起持有——否则可能导致死锁)。独占所有的硬件自旋锁可以单独使用,无需考虑其他软件的影响。注意,任何硬件自旋锁都不可重入获取(即硬件自旋锁本身对线程代码和 IRQ 的同时使用是不安全的),但此处默认的自旋锁相关方法(如 `spin_lock_blocking)在持锁期间总会禁用中断,因为 IRQ 处理程序和用户代码同时使用是常见且可取的场景,且自旋锁预期只被短暂持有。
RP2350 警告:由于勘误 RP2350-E2,向偏移量 +0x180 以上的新 SIO 寄存器写入会与自旋锁地址别名重叠,导致虚假的锁释放。作为对 RP2350 A2 的变通方案,SDK 默认使用原子内存访问来实现 hardware_sync_spin_lock API。
SDK 使用如下默认自旋锁分配,区分哪些自旋锁保留用于独占/特殊用途,哪些适合更通用的共享使用:
| 编号 (ID) | 描述 |
|---|---|
| 0-13 | |
| 当前保留供 SDK 及其他库独占使用。使用这些自旋锁可能会破坏 SDK 或其他库的功能。每个保留的自旋锁都有对应的 PICO_SPINLOCK_ID,可以搜索这些标识符。 | |
| 14,15 | |
| (PICO_SPINLOCK_ID_OS1 和 PICO_SPINLOCK_ID_OS2)。当前保留供与 SDK 共存的操作系统(或其他系统级软件)独占使用。 | |
| 16-23 | |
(PICO_SPINLOCK_ID_STRIPED_FIRST - PICO_SPINLOCK_ID_STRIPED_LAST)。此范围内的自 旋锁通过 next_striped_spin_lock_num() 以轮询方式分配。这些自旋锁是共享的,但从一个范围内分配编号可以降低两个使用条纹自旋锁的高层锁原语实际使用同一自旋锁的概率。 | |
| 24-31 | |
(PICO_SPINLOCK_ID_CLAIM_FREE_FIRST - PICO_SPINLOCK_ID_CLAIM_FREE_LAST)。这些保留供独占使用,在运行时通过 spin_lock_claim_unused() 按先到先得的方式分配。 |
宏
#define [SW_SPIN_LOCK_TYPE] volatile uint8_t
函数
static __force_inline void __nop (void)
在代码路径中插入一条 NOP 指令。
static __force_inline void __sev (void)
在代码路径中插入一条 SEV 指令。
static __force_inline void __wfe (void)
在代码路径中插入一条 WFE 指令。
static __force_inline void __wfi (void)
在代码路径中插入一条 WFI 指令。
static __force_inline void __dmb (void)
在代码路径中插入一条 DMB 指令。
static __force_inline void __dsb (void)
在代码路径中插入一条 DSB 指令。
static __force_inline void __isb (void)
在代码路径中插入一条 ISB 指令。
static __force_inline void __mem_fence_acquire (void)
获取内存屏障。
static __force_inline void __mem_fence_release (void)
释放内存屏障。
static __force_inline void disable_interrupts (void)
显式禁用调用核心上的中断。
static __force_inline void enable_interrupts (void)
显式启用调用核心上的中断。
static __force_inline uint32_t save_and_disable_interrupts (void)
禁用调用核心上的中断,并返回之前的中断状态。
static __force_inline void restore_interrupts (uint32_t status)
将调用核心上的中断恢复到指定状态。
static __force_inline void restore_interrupts_from_disabled (uint32_t status)
以受限转换方式将调用核心上的中断恢复到指定状态。
uint next_striped_spin_lock_num (void): 从条纹范围中返回一个自旋锁编号。void spin_lock_claim (uint lock_num): 将自旋锁标记为已使用。void spin_lock_claim_mask (uint32_t lock_num_mask): 将多个自旋锁标记为已使用。void spin_lock_unclaim (uint lock_num): 将自旋锁标记为不再使用。int spin_lock_claim_unused (bool required): 申请一个空闲的自旋锁。bool spin_lock_is_claimed (uint lock_num): 判断自旋锁是否已被申请。static __force_inline spin_lock_t * spin_lock_instance (uint lock_num)
通过编号获取硬件自旋锁实例。
static __force_inline uint spin_lock_get_num (spin_lock_t *lock)
通过实例获取硬件自旋锁编号。
static __force_inline void spin_lock_unsafe_blocking (spin_lock_t *lock)
在不禁用中断的情况下获取自旋锁(因此不安全)。
static __force_inline void spin_unlock_unsafe (spin_lock_t *lock)
在不重新启用中断的情况下释放自旋锁。
static __force_inline uint32_t spin_lock_blocking (spin_lock_t *lock)
安全地获取自旋锁。
static bool is_spin_locked (spin_lock_t *lock)
检查自旋锁当前是否被其他地方持有。
static __force_inline void spin_unlock (spin_lock_t *lock, uint32_t saved_irq)
安全地释放自旋锁。
spin_lock_t * spin_lock_init (uint lock_num)
初始化自旋锁。
void spin_locks_reset (void): 释放所有自旋锁。
宏定义文档
SW_SPIN_LOCK_TYPE RP2350
#define SW_SPIN_LOCK_TYPE volatile uint8_t
自旋锁标识符。
函数文档
__dmb
static __force_inline void __dmb (void) [static]
在代码路径中插入一条 DMB 指令。
DMB(数据内存屏障)作为内存屏障,此指令之前的所有内存访问都会在此指令之后的任何显式访问之前完成。
__dsb
static __force_inline void __dsb (void) [static]
在代码路径中插入一条 DSB 指令。
DSB(数据同步屏障)是一种特殊的数据内存屏障(DMB)。DSB 操作在此指令之前的所有显式内存访问完成后才完成。
__isb
static __force_inline void __isb (void) [static]
在代码路径中插入一条 ISB 指令。
ISB 作为指令同步屏障,它刷新处理器的流水线,使得在 ISB 指令完成之后,ISB 之后的所有指令都从缓存或内存中重新取指。
__mem_fence_acquire
static __force_inline void __mem_fence_acquire (void) [static]
获取内存屏障。
__mem_fence_release
static __force_inline void __mem_fence_release (void) [static]
释放内存屏障。
__nop
static __force_inline void __nop (void) [static]
在代码路径中插入一条 NOP 指令。
NOP 空转一个周期。在 RP2350 Arm 二进制文件中,该指令被强制为 32 位,以避免 NOP 的双发射。
__sev
static __force_inline void __sev (void) [static]
在代码路径中插入一条 SEV 指令。
SEV(发送事件)指令向两个核心都发送一个事件。
__wfe
static __force_inline void __wfe (void) [static]
在代码路径中插入一条 WFE 指令。
WFE(等待事件)指令等待多种事件之一发生,包括由任一核心上的 SEV 指令发出的事件。
__wfi
static __force_inline void __wfi (void) [static]
在代码路径中插入一条 WFI 指令。
WFI(等待中断)指令等待中断唤醒核心。
disable_interrupts
static __force_inline void disable_interrupts (void) [static]
显式禁用调用核心上的中断。
enable_interrupts
static __force_inline void enable_interrupts (void) [static]
显式启用调用核心上的中断。
is_spin_locked
static bool is_spin_locked (spin_lock_t * lock) [inline], [static]
检查自旋锁当前是否被其他地方持有。
参数
lock: 自旋锁实例
next_striped_spin_lock_num
uint next_striped_spin_lock_num (void)
从条纹范围中返回一个自旋锁编号。
以轮询方式返回 PICO_SPINLOCK_ID_STRIPED_FIRST 到 PICO_SPINLOCK_ID_STRIPED_LAST 范围内的自旋锁编号。调用者不会获得对该自旋锁的独占访问权,因此调用者必须:
.
(与其他调用者)遵守只短暂持有该自旋锁的约定(且在禁用 IRQ 的情况下持有——默认通过 spin_lock_blocking()),且不在持有其他自旋锁的同时持有它。
. 接受由于上述要求导致的短暂竞争,以及可能与其他使用者发生的竞争。
返回值
lock_num 调用者可使用的自旋锁编号(非独占)
另请参阅
PICO_SPINLOCK_ID_STRIPED_FIRST
PICO_SPINLOCK_ID_STRIPED_LAST
restore_interrupts
static __force_inline void restore_interrupts (uint32_t status) [static]
将调用核心上的中断恢复到指定状态。
参数
status: 来自 save_and_disable_interrupts()的先前中断状态
restore_interrupts_from_disabled
static __force_inline void restore_interrupts_from_disabled (uint32_t status) [static]
以受限转换方式将调用核心上的中断恢复到指定状态。
此方法仅应在当前中断状态已知为禁用时使用,例如与 save_and_disable_interrupts() 配对使用时。
参数
status: 来自 save_and_disable_interrupts()的先前中断状态
save_and_disable_interrupts
static __force_inline uint32_t save_and_disable_interrupts (void) [static]
禁用调用核心上的中断,并返回之前的中断状态。
此方法通常与 restore_interrupts_from_disabled() 配对使用,以临时禁用某段代码周围的中断,而无需关心中断之前是否已启用。
返回值
先前的中断使能状态,可通过 restore_interrupts_from_disabled() 或 restore_interrupts() 恢复。
spin_lock_blocking
static __force_inline uint32_t spin_lock_blocking (spin_lock_t * lock) [static]
安全地获取自旋锁。
此 函数在获取自旋锁之前会禁用中断。
参数
lock: 自旋锁实例
返回值
解锁时使用的中断状态,用于恢复原始状态。
spin_lock_claim
void spin_lock_claim (uint lock_num)
将自旋锁标记为已使用。
用于协作式申请硬件资源的方法。如果自旋锁已被申请,则会触发 panic。库使用此方法可检测出会以不可预知方式失败的意外配置。
参数
lock_num: 自旋锁编号
spin_lock_claim_mask
void spin_lock_claim_mask (uint32_t lock_num_mask)
将多个自旋锁标记为已使用。
用于协作式申请硬件资源的方法。如果任何自旋锁已被申请,则会触发 panic。库使用此方法可检测出会以不可预知方式失败的意外配置。
参数
lock_num_mask: 所有需要申请的自旋锁的位域(位 0 == 自旋锁 0,位 1 == 自旋锁 1,以此类推)
spin_lock_claim_unused
int spin_lock_claim_unused (bool required)
申请一个空闲的自旋锁。
参数
required: 如果为 true,则在没有可用自旋锁时触发 panic
返回值
自旋锁编号,如果 required 为 false 且无空闲自旋锁则返回 -1。
spin_lock_get_num
static __force_inline uint spin_lock_get_num (spin_lock_t * lock) [static]
通过实例获取硬件自旋锁编号。
参数
lock: 自旋锁实例
返回值
自旋锁 ID
spin_lock_init
spin_lock_t * spin_lock_init (uint lock_num)
初始化自旋锁。
自旋锁初始状态为未锁定。
参数
lock_num: 自旋锁编号
返回值
自旋锁实例
spin_lock_instance
static __force_inline spin_lock_t * spin_lock_instance (uint lock_num) [static]
通过编号获取硬件自旋锁实例。
参数
lock_num: 自旋锁 ID
返回值
自旋锁实例
spin_lock_is_claimed
bool spin_lock_is_claimed (uint lock_num)
判断自旋锁是否已被申请。
参数
lock_num: 自旋锁编号
返回值
如果已被申请则返回 true,否则返回 false。
另请参阅
spin_lock_unclaim
void spin_lock_unclaim (uint lock_num)
将自旋锁标记为不再使用。
用于协作式申请硬件资源的方法。
参数
lock_num: 要释放的自旋锁编号
spin_lock_unsafe_blocking
static __force_inline void spin_lock_unsafe_blocking (spin_lock_t * lock) [static]
在不禁用中断的情况下获取自旋锁(因此不安全)。
参数
lock: 自旋锁实例
spin_locks_reset
void spin_locks_reset (void)
释放所有自旋锁。
spin_unlock
static __force_inline void spin_unlock (spin_lock_t * lock, uint32_t saved_irq) [static]
安全地释放自旋锁。
此函数将根据参数重新启用中断。
参数
lock: 自旋锁实例saved_irq: 来自 spin_lock_blocking()函数的返回值。
另请参阅
spin_lock_blocking()
spin_unlock_unsafe
static __force_inline void spin_unlock_unsafe (spin_lock_t * lock) [static]
在不重新启用中断的情况下释放自旋锁。
参数
lock: 自旋锁实例
中文翻译版以英文版相同知识授权方式共享:CC-BY-SA 4.0。交流 Q群:498908352