Linux驱动总结3
if(_IOC_NR(cmd)> ioarg = &mem_devp-> condition);当condition为真时,等待队列头queue对应的队列被唤醒,否则继续堵塞。这种情况下不能被信号打断。 wait_event_interruptible(queue,condition);当condition为真时,等待队列头queue对应的队列被唤醒,否则继续堵塞。这种情况下能被信号打断。 4、唤醒等待队列 wait_up(wait_queue_head_t *q),唤醒该等待队列头对应的所有等待。 wait_up_interruptible(wait_queue_head_t *q)唤醒处于TASK_INTERRUPTIBLE的等待进程。 应该成对的使用。即wait_event于wait_up,而wait_event_interruptible与wait_up_interruptible。 wait_event和wait_event_interruptible的实现都是采用宏的方式,都是一个重新调度的过程,如下所示: #define wait_event_interruptible(wq, condition) ({ int __ret = 0; if (!(condition)) __wait_event_interruptible(wq, condition, __ret); __ret; }) #define __wait_event_interruptible(wq, condition, ret) do { /*此处存在一个声明等待队列的语句,因此不需要再重新定义一个等待队列节点*/ DEFINE_WAIT(__wait); for (;;) { /*此处就相当于add_wait_queue()操作,具体参看代码如下所示*/ prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); if (condition) break; if (!signal_pending(current)) { /*此处是调度,丢失CPU,因此需要wake_up函数唤醒当前的进程 根据定义可知,如果条件不满足,进程就失去CPU,能够跳出for循环的出口只有 1、当条件满足时2、当signal_pending(current)=1时。 1、就是满足条件,也就是说wake_up函数只是退出了schedule函数, 而真正退出函数还需要满足条件 2、说明进程可以被信号唤醒。也就是信号可能导致没有满足条件时就唤醒当前的进程。 这也是后面的代码采用while判断的原因.防止被信号唤醒。 */ schedule(); continue; } ret = -ERESTARTSYS; break; } finish_wait(&wq, &__wait); } while (0) #define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function) #define DEFINE_WAIT_FUNC(name, function) wait_queue_t name = { .private = current, .func = function, .task_list = LIST_HEAD_INIT((name).task_list), } void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state) { unsigned long flags; wait->flags &= ~WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); if (list_empty(&wait->task_list)) /*添加节点到等待队列*/ __add_wait_queue(q, wait); set_current_state(state); spin_unlock_irqrestore(&q->lock, flags); } 唤醒的操作也是类似的。 #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL) void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, void *key) { unsigned long flags; spin_lock_irqsave(&q->lock, flags); __wake_up_common(q, mode, nr_exclusive, 0, key); spin_unlock_irqrestore(&q->lock, flags); } static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int wake_flags, void *key) { wait_queue_t *curr, *next; list_for_each_entry_safe(curr, next, &q->task_list, task_list) { unsigned flags = curr->flags; if (curr->func(curr, mode, wake_flags, key) && (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) break; } } 等待队列通常用在驱动程序设计中的堵塞读写操作,并不需要手动的添加节点到队列中,直接调用即可实现,具体的实现方法如下: 1、在设备结构体中添加等待队列头,由于读写都需要堵塞,所以添加两个队列头,分别用来堵塞写操作,写操作。 #include struct mem_dev { char *data; unsigned long size; /*添加一个并行机制*/ spinlock_t lock; /*添加一个等待队列t头*/ wait_queue_head_t rdqueue; wait_queue_head
Linux驱动总 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)