<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      七、設備驅動中的阻塞與非阻塞 IO(二)

      7.2 輪詢

      7.2.1 介紹

        在用戶程序中的 select() 和 poll() 函數最終會使設備驅動中的 poll() 函數被執行。

        設備驅動程序中的輪詢函數原型:

      1   /** 用于詢問設備是否可以非阻塞的讀寫。當詢問條件未觸發時,用戶空間進行 select() 和 poll() 將引起進程阻塞 */
      2     unsigned int (*poll) (struct file *filp, struct poll_table_struct *wait);
      • wait:輪詢表指針。
      • 這個函數應該進行兩項工作:
        • 對可能引起設備文件狀態變化的等待隊列調用 poll_wait() 函數,將對應的等待隊列頭部添加到 poll_table 中
        • 返回表示是否能對設備進行無阻塞讀、寫訪問的掩碼

        

       7.2.2 globalfifo 支持輪詢

       globalfifo.c

        1 #include <linux/module.h>
        2 #include <linux/fs.h>
        3 #include <linux/init.h>
        4 #include <linux/cdev.h>
        5 #include <linux/slab.h>
        6 #include <linux/uaccess.h>
        7 #include <linux/mutex.h>
        8 #include <linux/wait.h>
        9 #include <linux/sched/signal.h> ///< 內核>5.0 使用
       10 //#include <linux/sched.h>
       11 #include <linux/poll.h>
       12 
       13 #define GLOBALFIFO_SIZE      0x1000
       14 #define MEM_CLEAR           0X1
       15 //#define GLOBALFIFO_MAGIC     'g'
       16 //#define MEM_CLEAR           _IO(GLOBALFIFO_MAGIC, 0)
       17 #define GLOBALFIFO_MAJOR    230
       18 #define DEVICE_NUMBER       10
       19 
       20 static int globalfifo_major = GLOBALFIFO_MAJOR;
       21 module_param(globalfifo_major, int, S_IRUGO);
       22 
       23 struct globalfifo_dev {
       24     struct cdev cdev;
       25     /** 
       26      *  目前 FIFO 中有效數據長度 
       27      *  current_len = 0, 表示 FIFO 為空
       28      *  current_len = GLOBALFIFO_SIZE, 表示 FIFO 滿
       29      */
       30     unsigned int current_len;   
       31     unsigned char mem[GLOBALFIFO_SIZE];
       32     struct mutex mutex;
       33     wait_queue_head_t r_wait;   ///< 讀等待隊列頭
       34     wait_queue_head_t w_wait;   ///< 寫等待隊列頭
       35 };
       36 
       37 struct globalfifo_dev *globalfifo_devp;
       38 
       39 /** 
       40  * 這里涉及到私有數據的定義,大多數遵循將文件私有數據 pirvate_data 指向設備結構體,
       41  * 再用 read write llseek ioctl 等函數通過 private_data 訪問設備結構體。
       42  * 對于此驅動而言,私有數據的設置是在 open 函數中完成的
       43  */
       44 static int globalfifo_open(struct inode *inode, struct file *filp)
       45 {
       46     /**
       47      *  NOTA: 
       48      *      container_of 的作用是通過結構體成員的指針找到對應結構體的指針。
       49      *      第一個參數是結構體成員的指針
       50      *      第二個參數是整個結構體的類型
       51      *      第三個參數為傳入的第一個參數(即結構體成員)的類型
       52      *      container_of 返回值為整個結構體指針
       53      */ 
       54     struct globalfifo_dev *dev = container_of(inode->i_cdev, struct globalfifo_dev, cdev);
       55     filp->private_data = dev;
       56     return 0;
       57 }
       58 
       59 static int globalfifo_release(struct inode *inode, struct file *filp)
       60 {
       61     return 0;
       62 }
       63 
       64 static long globalfifo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
       65 {
       66     struct globalfifo_dev *dev = filp->private_data;
       67 
       68     switch(cmd){
       69     case MEM_CLEAR:
       70         mutex_lock(&dev->mutex);
       71         memset(dev->mem, 0, GLOBALFIFO_SIZE);
       72         printk(KERN_INFO "globalfifo is set to zero\n");
       73         mutex_unlock(&dev->mutex);
       74         break;
       75     default:
       76         return -EINVAL;
       77     }
       78 
       79     return 0;
       80 }
       81 
       82 static unsigned int globalfifo_poll(struct file *filp, struct poll_table_struct *wait)
       83 {
       84     unsigned int mask = 0;
       85     struct globalfifo_dev *dev = filp->private_data;
       86 
       87     mutex_lock(&dev->mutex);
       88 
       89     poll_wait(filp, &dev->r_wait, wait);
       90     poll_wait(filp, &dev->w_wait, wait);
       91 
       92     if(dev->current_len != 0) {
       93         mask |= POLLIN | POLLRDNORM;
       94     }
       95 
       96     if(dev->current_len != GLOBALFIFO_SIZE){
       97         mask |= POLLIN | POLLWRNORM;
       98     }
       99 
      100     mutex_unlock(&dev->mutex);
      101     return mask;
      102 }
      103 
      104 
      105 static loff_t globalfifo_llseek(struct file *filp, loff_t offset, int orig)
      106 {
      107     loff_t ret = 0;
      108     switch(orig) {
      109     case 0: /** 從文件開頭位置 seek */
      110         if(offset < 0){
      111             ret = -EINVAL;
      112             break;
      113         }
      114         if((unsigned int)offset > GLOBALFIFO_SIZE){
      115             ret = -EINVAL;
      116             break;
      117         }
      118         filp->f_pos = (unsigned int)offset;
      119         ret = filp->f_pos;
      120         break;
      121     case 1: /** 從文件當前位置開始 seek */
      122         if((filp->f_pos + offset) > GLOBALFIFO_SIZE){
      123             ret = -EINVAL;
      124             break;
      125         }
      126         if((filp->f_pos + offset) < 0){
      127             ret = -EINVAL;
      128             break;
      129         }
      130         filp->f_pos += offset;
      131         ret = filp->f_pos;
      132         break;
      133     default:
      134         ret = -EINVAL;
      135         break;
      136     }
      137 
      138     return ret;
      139 }
      140 
      141 static ssize_t globalfifo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
      142 {
      143     unsigned int count = size;
      144     int ret = 0;
      145     struct globalfifo_dev *dev = filp->private_data;
      146     
      147     DECLARE_WAITQUEUE(wait, current);   ///< 將當前進程加入到 wait 等待隊列
      148     mutex_lock(&dev->mutex);
      149     add_wait_queue(&dev->w_wait, &wait);   ///< 添加等待隊列元到讀隊列頭中
      150 
      151     /** 判斷設備是否可寫 */
      152     while(dev->current_len == GLOBALFIFO_SIZE){
      153         /** 若是非阻塞訪問, 設備忙時, 直接返回 -EAGAIN */
      154         if(filp->f_flags & O_NONBLOCK) {
      155             ret = -EAGAIN;
      156             goto out;
      157         }
      158         
      159         __set_current_state(TASK_INTERRUPTIBLE);    ///<改變進程狀態為睡眠
      160         schedule();
      161         if(signal_pending(current)){    ///< 因為信號而喚醒
      162             ret = -ERESTARTSYS;
      163             goto out2;
      164         }
      165     }
      166 
      167     if(count > GLOBALFIFO_SIZE - dev->current_len)
      168         count = GLOBALFIFO_SIZE - dev->current_len;
      169     
      170     if(copy_from_user(dev->mem + dev->current_len, buf, count)){
      171         ret = -EFAULT;
      172         goto out;
      173     } else {
      174         dev->current_len += count;
      175         printk(KERN_INFO "written %u bytes(s), current len:%d\n", count, dev->current_len);
      176 
      177         wake_up_interruptible(&dev->r_wait);    ///< 喚醒讀等待隊列
      178         ret = count;
      179     }
      180 out:
      181     mutex_unlock(&dev->mutex);
      182 out2:
      183     remove_wait_queue(&dev->w_wait, &wait); ///< 移除等待隊列
      184     set_current_state(TASK_RUNNING);
      185     return ret;
      186 }
      187 
      188 /**
      189  * *ppos 是要讀的位置相對于文件開頭的偏移,如果該偏移大于或等于 GLOBALFIFO_SIZE,意味著已經獨到文件末尾
      190  */
      191 static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
      192 {
      193     unsigned int count = size;
      194     int ret = 0;
      195     struct globalfifo_dev *dev = filp->private_data;
      196 
      197     DECLARE_WAITQUEUE(wait, current);   ///< 將當前進程加入到 wait 等待隊列
      198     mutex_lock(&dev->mutex);
      199     add_wait_queue(&dev->r_wait, &wait);   ///< 添加等待隊列元到讀隊列頭中
      200 
      201     /** 等待 FIFO 非空,即判斷設備是否可讀 */
      202     while(dev->current_len == 0) {
      203         /** 若是非阻塞訪問, 設備忙時, 直接返回 -EAGAIN */
      204         /** filp->f_flags 是用戶空間 */
      205         if(filp->f_flags & O_NONBLOCK) {
      206             ret = -EAGAIN;
      207             goto out;
      208         }
      209 
      210         /** 
      211          *  阻塞訪問,調度其他進程執行 
      212          *  FIFO 為空的情況下,讀進程阻塞,必須依賴寫進程往 FIFO 里面寫東西喚醒它;
      213          *  但寫的進程為了 FIFO,它必須拿到這個互斥體來訪問 FIFO 這個臨界資源;
      214          *  如果讀進程把自己調度出去之前不釋放這個互斥體,那么讀寫進程之間就死鎖了
      215          */
      216         __set_current_state(TASK_INTERRUPTIBLE);    ///<改變進程狀態為睡眠
      217         mutex_unlock(&dev->mutex);
      218         schedule();
      219         if(signal_pending(current)){    ///< 因為信號而喚醒
      220             ret = -ERESTARTSYS;
      221             goto out2;
      222         }
      223 
      224         mutex_lock(&dev->mutex);
      225     }
      226 
      227     /** 要讀取的字節數大于設備文件中的有效數據長度 */
      228     if(count > dev->current_len)
      229         count = dev->current_len;
      230     
      231     /** 從用戶空間拷貝數據 */
      232     if(copy_to_user(buf, dev->mem, count)) {
      233         ret = -EFAULT;
      234         goto out;
      235     } else {
      236         /** FIFO 中數據前移 */
      237         memcpy(dev->mem, dev->mem + count, dev->current_len - count);
      238         dev->current_len -= count;  ///< 有效數據長度減少
      239         printk(KERN_INFO "read %u bytes(s), current_len: %d\n", count, dev->current_len);
      240 
      241         wake_up_interruptible(&dev->w_wait);    ///< 喚醒寫等待隊列
      242 
      243         ret = count;
      244     }
      245 out:
      246     mutex_unlock(&dev->mutex);
      247 out2:
      248     remove_wait_queue(&dev->r_wait, &wait); ///< 移除等待隊列
      249     set_current_state(TASK_RUNNING);
      250     return ret;
      251 }
      252 
      253 static const struct file_operations globalfifo_fops = {
      254     .owner = THIS_MODULE,
      255     .poll = globalfifo_poll,
      256     .llseek = globalfifo_llseek,
      257     .read = globalfifo_read,
      258     .write = globalfifo_write,
      259     .unlocked_ioctl = globalfifo_ioctl,
      260     .open = globalfifo_open,
      261     .release = globalfifo_release,
      262 };
      263 
      264 
      265 /**
      266  * @brief  globalfifo_setup_cdev     
      267  *
      268  * @param  dev
      269  * @param  index    次設備號
      270  */
      271 static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
      272 {
      273     int err;
      274     int devno = MKDEV(globalfifo_major, index);
      275 
      276     /** 使用 cdev_init 即是靜態初始化了 cdev */
      277     cdev_init(&dev->cdev, &globalfifo_fops);
      278     dev->cdev.owner = THIS_MODULE;
      279 
      280     /** 設備編號范圍設置為1,表示我們只申請了一個設備 */
      281     err = cdev_add(&dev->cdev, devno, 1);
      282     if(err)
      283         printk(KERN_NOTICE "Error %d adding globalfifo%d\n", err, index);
      284 }
      285 
      286 static int __init globalfifo_init(void)
      287 {
      288     int ret;
      289     int i;
      290     dev_t devno = MKDEV(globalfifo_major, 0);
      291 
      292     if(globalfifo_major)
      293         ret = register_chrdev_region(devno, DEVICE_NUMBER, "globalfifo");
      294     else {
      295         ret = alloc_chrdev_region(&devno, 0, DEVICE_NUMBER, "globalfifo");
      296         globalfifo_major = MAJOR(devno);
      297     }
      298 
      299     if(ret < 0)
      300         return ret;
      301 
      302     globalfifo_devp = kzalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);
      303     if(!globalfifo_devp){
      304         ret = -ENOMEM;
      305         goto fail_malloc;
      306     }
      307 
      308     for(i = 0; i < DEVICE_NUMBER; i++){
      309         globalfifo_setup_cdev(globalfifo_devp + i, i);
      310     }
      311     
      312     mutex_init(&globalfifo_devp->mutex);
      313 
      314     /** 初始化讀寫等待隊列 */
      315     init_waitqueue_head(&globalfifo_devp->r_wait);
      316     init_waitqueue_head(&globalfifo_devp->w_wait);
      317 
      318 fail_malloc:
      319     unregister_chrdev_region(devno, 1);
      320     return ret;
      321 }
      322 
      323 static void __exit globalfifo_exit(void)
      324 {
      325     int i;
      326     for(i = 0; i < DEVICE_NUMBER; i++) {
      327         cdev_del(&(globalfifo_devp + i)->cdev);
      328     }
      329     kfree(globalfifo_devp);
      330     unregister_chrdev_region(MKDEV(globalfifo_major, 0), DEVICE_NUMBER);
      331 }
      332 
      333 module_init(globalfifo_init);
      334 module_exit(globalfifo_exit);

      epoll_test.c

       1     }
       2 
       3     epfd = epoll_create(1);
       4     if(epfd < 0) {
       5         perror("epoll_create()");
       6         return ;
       7     }
       8 
       9     bzero(&ev_globalfifo, sizeof(struct epoll_event));
      10     ev_globalfifo.events = EPOLLIN | EPOLLPRI;
      11     err = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev_globalfifo);
      12     if(err < 0) {
      13         perror("epoll_ctl()");
      14         return ;
      15     }
      16     err = epoll_wait(epfd, &ev_globalfifo, 1, 15000);
      17     if(err < 0) {
      18         perror("epoll_wait()");
      19     } else if(err == 0) {
      20         printf("No data input in FIFO within 15 seconds.\n");
      21     } else {
      22         printf("FIFO is not empty.\n");
      23     }
      24 
      25     err = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev_globalfifo);
      26     if(err < 0) {
      27         perror("epoll_ctl()");
      28         return ;
      29     }
      30 
      31     return;
      32 
      33 }

      Makefile

       1 .PHONY:all clean test
       2 
       3 TEST_SRC := poll_test.c
       4 TEST_TARGET := poll_test
       5 
       6 ifneq ($(KERNELRELEASE),)
       7 
       8 obj-m := globalfifo.o
       9 
      10 else
      11 LINUX_KERNEL := $(shell uname -r)
      12 LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
      13 CURRENT_PATH  := $(shell pwd)
      14 EXTRA_CFLAGS += -DDEBUG
      15 
      16 all:
      17     make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
      18 clean:
      19     rm -fr *.ko *.o *.mod.o *.mod.c *.symvers *.order .*.ko *.cmd .tmp_versions $(TEST_TARGET)
      20 
      21 test:
      22     gcc -o $(TEST_TARGET) $(TEST_SRC)
      23 endif

       

      posted @ 2019-11-01 15:01  游戲進行中  閱讀(364)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 中文字幕 日韩 人妻 无码| 免费特黄夫妻生活片| 激情综合色综合久久综合| 少妇太爽了在线观看免费视频| 国产成人综合网在线观看| 亚洲精品麻豆一区二区| 国产高在线精品亚洲三区| 九九热在线精品视频免费| 最近中文字幕完整版hd| 久久精品国产再热青青青| 蜜芽久久人人超碰爱香蕉| 久久精品国产久精国产| 最近中文字幕国产精品| 一区二区三区黄色一级片| 永久免费av网站可以直接看的| 久久在线视频免费观看| 国产成人午夜精品影院| 亚洲禁精品一区二区三区| 亚洲中文字幕伊人久久无码 | 人妻系列无码专区免费| 国产精品一亚洲av日韩| 日本久久久免费高清| 国产精品久久蜜臀av| 天堂网在线.www天堂在线资源| 成人3D动漫一区二区三区| 东京热一精品无码av| 一本色道久久加勒比综合| 国产在线精品国偷产拍| 大地资源免费视频观看| 国产精品线在线精品| 欧美亚洲国产一区二区三区| 国产麻豆成人传媒免费观看| 少妇精品无码一区二区免费视频| 成年视频人免费网站动漫在线| 桦川县| 日本道高清一区二区三区| 亚洲高清日韩专区精品| www内射国产在线观看| 日日碰狠狠添天天爽五月婷| 人妻一区二区三区三区| 女人裸体性做爰视频|