《linux驱动开发阻塞和非阻塞IO》由会员分享,可在线阅读,更多相关《linux驱动开发阻塞和非阻塞IO(11页珍藏版)》请在金锄头文库上搜索。
1、linux设备中的阻塞和非阻塞I/O一、等待队列在linux驱动程序中,可以使用等待队列来实现阻塞进程的唤醒。等待队列 是以队列为基础数据结构,与进程调度机制紧密结合,能够用于实现内核中的 异步事件通知机制。等待队列可以用来同步对系统资源的访问,在内核中,信号量也是依赖于等待队列来实现的。作用:所有的等待资源的任务都被放入到等待队列中。二、实现等待队列是一个队列数据结构所以,队列有等待队列头和等待队列项。 -1、定义“等待队列头”wait_queue_head_t my_head;ZZZZJ在使用的时候要先初始化以下,定义了几个队列,就初始化几次。Jr12、初始化“等待队列头”ini t_wa
2、itqueue_head(&m y_head);lock);16 lockdep_set_class(&q-lock/ key);17 INIT LIST_HLAD(fiq-ta5k list);18 第一句话的意思是自旋锁的初始化。最后一句话的意思是初始化队列头 在include/linux/list.h中有实现代码:28 gtatiu inline 甘oid INIT_LIST_HEAD(stnK:t list h亡ad29 30 list-next - list;31 list-prev = list;32 在内核中为了方便使用,有一个宏可以完成等待队列头的定义和初始化:DECLARE_
3、WAIT-QUEUE_HEAD(name); name 为队列头的名字k3、定义等待队列DECLARE_WAITQUEUE(name,tsk);定义并初始化一个名为name的等待队列name就是等待队列的名字,也是等待队列头的名字,tsk 一般是写如当前 的任务(进程)current (内核中的全局变量,代表当前任务)。4、添加/移除等待队列void fastcall add_wait_queue(wait_queue_heat_t *q,wait_queue_t *wait); void fastcall remove_wait_queue(wait_queue_head_t *q ,wai
4、t_queue_t*wait) (5、等待事件wait_eve nt(queue,c on diti on);不可中断的等待事件wait_eve nt_in terruptible(queue,co nditio n);可中断的等待事件,所以在使用时候,要先判断是否由于中断返回还是有资源返回。wait_eve nt_timeout(queue,c on diti on ,timeout);timeout 是等待的时间,超时就 会返回,同样的也是不可中断的wait_eve nt_in terruptible_timeout(queue,c on diti on ,timeout);同样的是可中断
5、,使用的时候也要判断。Condition为满足的条件。.-6、唤醒队列void wake_up(wait_queue_head_t *queue)唤醒等待队列中的所有的任务void wake_up_i nterruptible(wait_queue_head_t *queue)只 唤醒可中断等待 的任务,7、在等待队列上睡眠sleep_o n(wait_queue_head_t *q)把当前任务设置为不可中断,不可中断的 等待态,并创建一个等待队列,并加入这个新创建的等待队列in terruptible_sleep_o n( wait_queue_head_t *q);与 上面的一样,就是,设
6、置 状态为可中断的等待态。三、程序分析在本程序中用到了简单睡眠和手动睡眠两种方法。本驱动程序中的缓冲区是一个循环的缓冲区,类似与循环队列。当rp = rw时候说明缓冲区空,定rp与rw相差1时候,说明缓冲区满。操作和循环队列类似。程序的源代码如下:1、头文件驱动程序中所需要的头文件如下:printk()f min() */kmalloc() */ everything.fjinQlu血 tinclude /* tinclude include /* tinclude /*error codes */ size_t */tinclude linux/pgjb h tinclude Iinclud
7、e tincLude 16 tinclude 11 #include 12 include tinctude ajor=25B;213、设备结构体定义212223242526272829弭313233static struct scullpipe* scull_p_devices: 台tat让 int 与m叙丘iitt Mull._pipE *心亡越);严定Afi*结构绞時struct scullpipe (wait_queue_head_t Inqr outq; 匚har *buffer, *end;int buffersize; char *rpr *wp; int nreaders, n
8、writers; struct semaphore sen; struct cdev cdev;;/*定义可埃和可写等持队列*/*定义缓冲区的开始和结束*/*塚冲区的大小*/*可读和可写在3(冲区中的位竄*/ /* number of openings for r/w */ /*定义借号*S/* 定Jdcdev*/3839 轴414 24S444545+ 748495051525554555657设备结构体中定义了设备的资源,包括等待队列,对于设备来说也是一种资源, 信号也是设备的资源。4、open函数open函数中对于一些只有open时才用到的资源进行初始化和分配,并不 一定要在加载函数中分
9、配。static int scull_p_open(struet inode *inod电 struct filestruct scull.pipe *dev;/*定义设备结构体描針 严通id成员門眈取的夠构体的芦地址T dev = container of(inodei cdev, struct scutl pipej cdev): /:将设备越构休的首地址放到珀结构体中的private.data咸员中智 flip-private data = dev; 厂可中斷的获得信号単“ if (down_interruptible(&dev-sem)return -ERESTARTSYS;严返回Ms
10、并继续执行这个函fit*/ 初IS化蘿沖区U if (!dev-buffer) 八为缓冲区申请空RT/dev-btiffer = kmallocf scull.p_buffer, GFP_KERNEL): if C!dev-buffer) 八如啊申请失号量.并出倩返回咛 up(&dew-sem); return -EHOMEH;535gdew-end = dev-buffer + devbuffersize;dev-rp = devwp = devbuffer; /* rd and wr from the beginning */6162/* use f modej not f flaas;
11、its cleaner (fs/ooen tells why) */63/*struct file结构ft 4s f_mode中用来保存用户叩的打开文件的方式64if (filp-f_nKde S FMODE-READ)厂判断是否是以读打开的柿65dev-n readers* + ;八读的用户*广/66if (filp-f_node & FMODE.WRITE)严判斷星否以宥的方式打开輪/67dev-nwriters+;严写的用户和料aaup(&dev-sem);厂释放信号童吟69return fl;70卜_71bul3 4 5 6 7 8 9 0 12 3 4 57 7 7 7 7 7 7
12、8 8 8 8 8 89295949596979899 100101102Ifll104105106 107 lee 109 lie in 112 115 114I = dev-wp) 1玄亡厂it5、close 函数static int scull p reLease(struct inode * inodeT struct file *filp) struct scull.pipe *dev = filp-private_data;/*获取设备结构体*/ down(&dev-sem);严获取信号if (flip-f_nde & FMODE.READ) dev-nreaders-;严读者if (Hlp-f_mode b FMODE_WRITE) dev-nwriters-*;写者- -*/if (dev-nreaders + dev-nwriters =) kfree(dev-buffer);厂算放3!冲区空间存/ dev-buffer