在Linux驱动开发中,wake_up_interruptible
是一个关键函数,用于唤醒处于可中断睡眠状态(TASK_INTERRUPTIBLE)的进程。以下是其核心要点和使用方法:
功能与用途
- 唤醒进程:当驱动中的某个条件满足(如数据就绪、硬件操作完成),调用此函数唤醒等待队列中的进程。
- 适用场景:常用于阻塞式操作(如字符设备的
read
/write
),避免进程忙等待,提升系统效率。
函数原型
int wake_up_interruptible(wait_queue_head_t *q);
- 参数:
q
是等待队列头(wait_queue_head_t
),指向进程等待的队列。 - 返回值:成功唤醒的进程数。若返回0,表示无进程被唤醒。
关键特性
- 仅唤醒可中断进程:
- 仅唤醒处于
TASK_INTERRUPTIBLE
状态的进程,忽略TASK_UNINTERRUPTIBLE
状态。 - 与
wake_up
不同,后者会唤醒所有状态的进程。
- 仅唤醒处于
- 信号处理:
- 若进程被信号中断,
wake_up_interruptible
仍会返回非零值,驱动需处理-ERESTARTSYS
错误码。
- 若进程被信号中断,
典型使用流程
1. 定义等待队列头
wait_queue_head_t wq;
DECLARE_WAIT_QUEUE_HEAD(wq); // 初始化等待队列头
2. 条件变量与唤醒逻辑
static int data_available = 0; // 条件标志
// 在中断处理或数据就绪时唤醒进程
void irq_handler(void) {
data_available = 1;
wake_up_interruptible(&wq); // 唤醒等待队列中的进程
}
3. 进程阻塞等待
ssize_t device_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) {
// 等待条件满足或被信号中断
if (wait_event_interruptible(wq, data_available != 0)) {
return -ERESTARTSYS; // 被信号中断,返回错误
}
// 条件满足,处理数据...
data_available = 0; // 重置条件
return count;
}
注意事项
- 条件检查:
- 唤醒后需重新检查条件(如
data_available
),避免虚假唤醒。 - 示例中的
wait_event_interruptible
宏已自动处理条件检查和等待队列操作。
- 唤醒后需重新检查条件(如
- 中断上下文安全:
wake_up_interruptible
可在中断上下文调用,因其不涉及睡眠操作。
- 避免忙等待:
- 确保唤醒逻辑与条件变量正确配合,防止进程反复唤醒后立即休眠。
示例场景
- 字符设备驱动:
- 用户空间调用
read
时,若数据未就绪,进程进入TASK_INTERRUPTIBLE
睡眠。 - 硬件中断触发时,设置标志并调用
wake_up_interruptible
,唤醒等待进程。
- 用户空间调用
总结
wake_up_interruptible
是驱动中实现阻塞式I/O的核心机制,通过协调等待队列和条件变量,高效管理进程状态转换。正确使用可提升驱动性能,同时需注意信号处理和条件检查,确保系统稳定性。