分类: LINUX
2008-11-13 09:06:51
linux下at91rm9200 RTC实时时钟驱动程序部分等待对列wait_queue简单理解
文章来源:http://gliethttp.cublog.cn
1.wait_queue_head_t类型
wait_queue_t类型
DECLARE_WAIT_QUEUE_HEAD(at91_rtc_wait)宏
DECLARE_WAITQUEUE(wait, current)宏
均在include/linux/wait.h中有定义
2.static DECLARE_WAIT_QUEUE_HEAD(at91_rtc_wait);
定义队列头at91_rtc_wait,以后等待相应事件发生的应用程序将创建一个包含应用程序自身足够信息的wait队列,然后将那个wait队列
作为at91_rtc_wait双向链表的第一个链表元素插入,队列头at91_rtc_wait原来的第一个双向链表元素将被链接成双向链表的第2个元素
3.at91_rtc_read读取函数的理解
gliethttp 2007-06-14驱动学习
ssize_t at91_rtc_read(struct file * file, char *buf, size_t count, loff_t * ppos)
{
DECLARE_WAITQUEUE(wait, current); //对于多个应用程序分别同时调用at91_rtc_read,那么每个应用程序都对应一个局部
unsigned long data; //变量wait,DECLARE_WAITQUEUE宏将每个应用程序对应的cpu上下文current存放到
ssize_t retval; //相应应用程序占有的局部变量wait中
if (count < sizeof(unsigned long))
return -EINVAL;
add_wait_queue(&at91_rtc_wait, &wait);//将当前应用程序局部变量wait插入到at91_rtc_wait队列头,作为第一个链表元素
set_current_state(TASK_INTERRUPTIBLE);//设置当前进程为可中断,那么任何对该应用程序的信号操作,都会唤醒该应用程序
for (;;) { //使得应用程序能够从schedule();函数返回,继续执行for(;;)循环体
spin_lock_irq(&at91_rtc_lock);
data = rtc_irq_data;
if (data != 0) {
rtc_irq_data = 0;
break;
}
spin_unlock_irq(&at91_rtc_lock);
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
goto out;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
goto out;
}
schedule();
}
spin_unlock_irq(&at91_rtc_lock);
data -= 0x100;
retval = put_user(data, (unsigned long *) buf);
if (!retval)
retval = sizeof(unsigned long);
out:
set_current_state(TASK_RUNNING);
remove_wait_queue(&at91_rtc_wait, &wait);
remove_wait_queue(&at91_rtc_update, &wait);
return retval;
}
举一个例子来说:如果有5个应用程序p1,p2,p3,p4,p5都试图调用了at91_rtc_read读取数据,那么将会有5个wait局部变量w1,w2,w3,w4,w5被创建,每个局部变量都存储着相应应用程序的足够调度信息,假设5个应用程序的创建的顺序是p1->p2->p3->p4->p5,那么at91_rtc_wait队列头中的5个待唤醒的进程wait的链接顺序为at91_rtc_wait->w5->w4->w3->w2->w1。
3.at91_rtc_interrupt中断函数的配对理解
gliethttp 2007-06-14驱动学习
static void at91_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned int rtsr = AT91_SYS->RTC_SR & AT91_SYS->RTC_IMR;
if (rtsr) {
if (rtsr & AT91C_RTC_ALARM)
rtc_irq_data |= (AT91_RTC_AF | AT91_RTC_IRQF);
if (rtsr & AT91C_RTC_SECEV)
rtc_irq_data |= (AT91_RTC_UF | AT91_RTC_IRQF);
if (rtsr & AT91C_RTC_ACKUPD)
wake_up_interruptible(&at91_rtc_update);
rtc_irq_data += 0x100;
AT91_SYS->RTC_SCCR = rtsr;
//gliethttp 2007-06-14
wake_up_interruptible(&at91_rtc_wait);//将唤醒at91_rtc_wait队列头中包含了5个进程调度信息的5个wait对应的应用程序
kill_fasync(&at91_rtc_async_queue, SIGIO, POLL_IN);
}
}
小结:多个wait_queue的链接是通过双向链表完成的,wait_queue结构中含有struct list_head task_list;双向链表结构域,所以所有
多个wait_queue之间的关联操作都是通过list_add(),list_del(),list_entry()等链表函数简单的完成。