阻塞IO,异步通知,中断,时间定时器(Linux驱动2)

    xiaoxiao2021-03-25  52

    1 阻塞和非阻塞IO

    说明: 阻塞IO,当资源不可用时,进程就阻塞住.非阻塞IO,当资源不可用时,进程不被阻塞. 系统通过等待队列实现阻塞IO,等待队列的调度与系统调度有关. 非阻塞IO,需要用户不断查询状态.用户侧通过select,FD_SET等宏来实现,驱动侧需要实现poll函数. 变量 wait_queue_head_t head wait_queue_t wait 函数 DECLARE_WAIT_QUEUE_HEAD(name) DECLARE_WAITQUEUE(name,tsk) init_waitqueue_head(&head) wait_event(&head,condition) wake_up(&head) add_wait_queue(&head,&wait) remove_wait_queue(&head,&wait) wait_event_interruptible wait_event_timeout wait_event_interruptible_timeout wake_up_interruptible 用法: 阻塞IO 1、 xx_device{ cdev cdev; ... wait_queue_head_t queue;//在设备定义中条件等待队列头. } 2、处理阻塞的地方 DECLEAR_WAITQUEUE(wait,current); add_wait_queue(dev->queue,&wait) ... if(!available){//资源不可用 __set_current_state(TASK_INTERRUPTIBLE);//设置浅睡眠状态 if(filep->flags & O_NOBLOCK){//非阻塞方式打开 ret= -EAGAIN; goto out; } schedule(); if(signal_pending(current)){//被其他信号唤醒 ret=-ERESTARTSYS; goto out; } } 处理正常事务... out:remove_wait_queue(dev->queue,&wait);//移除等待队列 __set_current_state(TASK_RUNNING);//设置进程状态 return ret; 别的函数 当允许访问资源时 wake_up_interruptible(&dev->queue); 非阻塞IO 1、用户侧 fd_set rd,wt; FD_ZERO(&rd);FD_ZERO(&wt) FD_SET(fd,&rd);FD_SET(fd,&wt); .... select(fd+1,fd_set *rd,fd_set*wt,fd_set*exp,struct timeval *time); if(FD_ISSET(fd,&rd)) do read work if(FD_ISSET(fd,&wr)) do write work 2、驱动侧 xx_poll(struct file *filep,poll_table *wait) { dev=filep->private_data; poll_wait(dev->rd_queue,wait); poll_wait(dev->wr_queue,wait); if(可读) mask |=POLLIN|POLLRDNORMAL; if(可写) mask |=POLLOUT|POLLWRNORMAL; return mask; } struct file_operations xx_fops={ ... .poll=xx_poll; }

    2 异步通知

    说明: 用户侧通过设置回调函数,当资源可用时,通过回调函数的形式,异步通知用户侧.相当于系统对用户侧的中断.

    变量:

    fasync_struct typedef void(*sighandler_t)(int);

    函数:

    用户侧 signal(undigned long no,sighandler_t handler);//注册回调函数 fcntl(fd,cmd,data) 驱动侧 fasync_helper kill_fasync

    用法:

    用户侧 xx_handler(int) { ... } signal(fd,handler) fcntl(fd,F_SETOWN,getpid());//设置own,让驱动侧知道向哪里发送消息 flag=fcntl(fd,F_GETFL); fcntl(fd,F_SETFL,flag|FASYNC);设置驱动侧fasync标志 驱动侧 设备结构体中定义fasync_struct xx_dev{ cdev cdev; ... struct fasync_struct *fasync_queue; } 实现xx_fasync函数 xx_fasync(int fd,struct file *filep,int mode) { fasync_helper(fd,filep,mode,&dev->fasync_queue);//调用fasync_helper函数 } 在资源可用时调用kill_fasync函数 if(available) kill_fasync(&dev->fasync_queue,sig,POLL_XX); 在release中,注销函数 xx_fasync(-1,filep,0);

    3 中断 说明:

    中断用于打断当前程序.在linux中为取得效率的平衡,采用下半部处理方式,处理中断.下半部处理方式有tasklet,work,softirq.中断程序中上半部处理需要紧急处理部分,下半部处理不需要紧急处理部分.上下部处理根据情况来选择,不一定一定要. tasklet和softirq工作于原子上下文,工作队列工作于进程上下文,所以工作队列可以阻塞,而tasklet和softirq不能有阻塞.

    变量:

    tasklet_t tsklet work_struct wk DECLARE_TASKLET(tsklet,tsklet_fun,data)//联系结构与下半部处理函数

    函数:

    register_irq(unsigned int irq,irq_handler_t handler,unsigned long irqflags,const char * name,void *dev_id) free_irq(unsigned int irq,void * dev_id); disable_irq(int irq);//需要等待中断处理完 enable_irq(int irq); disable_irq_nosync(int irq);//不需要等待中断处理完 tasklet_schedule(xx_tsk); schedule_work(xx_wk); INIT_WORK(wk,xx_work_fun,data);//联系工作队列中的结构与处理函数

    用法

    xx_init() { request_irq(irq,xx_irqhandler,flags,”xx_irq”,NULL); if you want use work in bh INIT_WORK(&xx_wk,work_fun,NULL); } xx_irqhandler(int irq,void dev_id,struct pt_regs regs) { … schedule_work(&xx_wk); or tasklet_schedule(&xx_tsk); return IRQ_HANDLED; } xx_exit() { … free_irq(irq,NULL); } 如果想用tasklet下半部 void xx_tasklet_fun(unsigned int) { } DECLARE_TASKLET(xx_tsk,xx_tasklet_fun,NULL) 扩展: local_irq_eanble,local_irq_disable//允许,禁止本地cpu中断

    共享中断:

    说明:

    多个设备,共享一个硬件中断线的情况.共享中断需要将flags设置成IRQF_SHARED,系统会遍历所有共享中断的处理函数,直到返回IRQ_HANDLED.在上半部,应当读取中断状态,如果不是属于本身的中断应当立即返回IRQ_NONE;

    4时间定时器:

    说明:

    时间定时器最终依赖硬件定时器来工作,当时钟中断发生时,系统会检测各个时间定时器,到期的时间定时器函数作为软中断在底半部执行.

    变量:

    timer_list timer HZ 每秒钟中断次数,一般100 jiffies 当前中断次数.一秒钟有hz个jiffies. 函数: init_timer(&timer) add_timer(&timer) del_timer(&timer) mod_timer(&timer,unsigned long expries) DEFINE_TIEMER(name,fun,expires) TIMER_INITIALIZER(name,fun,dara) msecs_to_jiffies 将毫秒转换成jiffies

    用法:

    sturct xx_dev={ struct cdev cdev; … struct timer_list xx_timer; } struct xx_dev dev; xx_init() { init_timer(&dev.xx_timer); dev.xx_timer.function=do_timer; dev.xx_timer.data=.. dev.xx_timer.expires=jiffies+时间间隔; } xx_exit() { del_timer(&dev.xx_timer); } do_timer(unsigned long arg) { mod_timer(&dev.xx_timer,新时间) 或者 dev.xx_timer.expires=新时间 add_timer(&dev.xx_timer); }

    扩展:delay_work

    说明:

    对于周期性任务,还可以用delay_work来完成.

    变量:

    struct delay_work work;

    函数:

    schedule_delay_work(struct delay_work *,unsigned long dealy)

    用法:

    struct delay_work work; xx_fun1() { schedule_delay_work(&work,delay); } xx_do_work(unsigned long time) { schedule_delay_work(&work,delay); }

    5延迟:

    说明:

    延迟有忙延迟,休眠延迟.忙延迟占用cpu时间,休眠延迟不占用cpu时间. 函数: ndelay udelay mdelay msleep 不可被打断 msleep_interruptiable 可被打断 ssleep timer_before(a,b) a在b之前 timer_after(a,b) a在b之后

    转载请注明原文地址: https://ju.6miu.com/read-32963.html

    最新回复(0)