poll 設備 select 文件多路監控 自動建立設備文件

Select系統調用用於多路監控,當沒有一個文件知足要求時,select將阻塞調用進程node

int select(int maxfd, fd_set * readfds, fd_set * writefds, fe_set * exceptfds, const struct timeval * timeout)linux

——maxfd:文件描述符的範圍,比待檢測的最大文件描述符大1函數

——readfds:被讀監控的文件描述符集測試

——writefds:被寫監控的文件描述符集this

——exceptfds:被異常監控的文件描述符集spa

——timeout:定時器。code

Timeout取不一樣的值,該調用有不一樣的表現:orm

——*timeout0,無論是否有文件知足要求,都馬上返回,無文件知足要求返回0,有文件知足要求返回一個正值隊列

——timeoutNULLselect將阻塞進程,直到某個文件知足要求進程

——*timeout爲正整數,就是等待的最長時間,即selecttimeout時間內阻塞進程,事後進程被喚醒

返回值

Select調用返回時,返回值有以下狀況:

1.正常狀況下返回知足要求的文件描述符個數

2.通過了timeout等待後任無文件知足要求,返回值爲0

3.若是select被某個信號中斷,它將返回-1並設置errnoEINTR(可見select引發的阻塞爲INTERRUOPTIBLE阻塞)

4.若是出錯,返回-1並設置相應的errno


使用方法

1.將要監控的文件添加到文件描述符集(被讀、寫、異常監控的文件描述符集)

2.調用select開始監控

3.判斷文件是否發生變化


系統提供了4個宏對描述符集進行操做:
#include <sys/select.h>

void FD_SET(int fd, fd_set *fdset)

void FD_CLR(int fd, fd_set *fdset)

void FD_ZERO(fd_set * fdset)

void FD_ISSET(int fd, fd_set * fdset)

FD_SET將文件描述符fd添加到文件描述符集fdset中;

FD_CLR從文件描述符集fdset中清除文件描述符fd

FD_ZERO清空文件描述符集fdset

在調用select後使用FD_ISSET來檢測文件描述符集fdset中的文件fd是否發生變化

    FD_ZERO(&fds); //清空集合
    FD_SET(fd1, &fds); //設置描述符
    FD_SET(fd2, &fds); //設置描述符
    maxfdp = fd1 + 1; //描述符最大值加1,假設fd1>fd2
    switch(select(maxfdp, &fds, NULL,    NULL, &timeout))
        case -1: exit(-1);break;//select/ //錯誤,退出程序
        case 0:break;
        default: if( FD_ISSET(fd1, &fds)) //測試fd1是否可讀

poll方法函數

unsigned int (*poll)(struct file *filp, poll_table *wait)

Poll設備方法負責完成:
1.使用poll_wait將等待隊列添加到poll_table

2.返回描述設備是否可讀或可寫的掩碼:

——POLLIN:設備可讀

——POLLRDNORM:數據可讀

——POLLOUT:設備可寫

——POLLWRNORM:數據可寫

設備可讀一般返回(POLLIN|POLLRDNORM

設備可寫一般返回(POLLOUT|POLLWRNORM

static unsigned int mem_poll(struct file * filp, poll_table * wait)
{
    struct scull_pipe *dev = filp->private_data;
    unsigned int mask = 0;
/*把等待隊列添加到poll_table*/
    poll_wait(filp, &dev->inq, wait);
/*返回掩碼*/
    if(有數據可讀)
       Mask = POLLIN | POLLRDNORM;//設備可讀
    rerurn mask;
}

Poll方法只是作一個登記,真正的阻塞發生在select.c中的do_select函數


自動建立設備文件(2.6內核)

剛開始寫Linux設備驅動程序的時候,不少時候都是利用mknod命令手動建立設備節點,實際上Linux內核爲咱們提供了一組函數,能夠用來在模塊加載的時候自動在/dev目錄下建立相應設備節點,並在卸載模塊時刪除該節點,固然前提條件是用戶空間移植了udev。

udev(mdev)存在於應用層。利用udev(mdev)在驅動初始化的代碼裏調用class_create爲該設備建立一個class,再爲每一個設備調用device_create建立對應的設備。

busy_box裏默認沒有udev(mdev),所以首先要配置busy_box,讓其支持mdev,才能用mdev

struct class和device_create(…) 以及device_create(…)都定義在/include/linux/device.h中,應用時加上頭文件。

   struct class * myclass=class_create(THIS_MODULE, 「by_device_driver」);// 第一個參數指定類的全部者是哪一個模        塊,第二個參數指定類名。 

   //建立一個設備節點,節點名爲DEVICE_NAME

   device_create(myclass, NULL,MKDEV(major_num, 0), NULL, 「my_device」); //第一個參數指定所要建立的設備所從       屬的類,第二個參數是這個設備的父設備,若是沒有就指定爲NULL,第三個參數是設備號,第四個參數是設備回         調數據,第五個參數是設備名字。

當驅動被加載時,udev(mdev)就會自動在/dev下建立my_device設備文件

例子

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

MODULE_LICENSE ("GPL");

int hello_major = 555;
int hello_minor = 0;
int number_of_devices = 1;

struct cdev cdev;
    dev_t dev = 0;

struct file_operations hello_fops = {
      .owner = THIS_MODULE
};

static void char_reg_setup_cdev (void)
{
       int error, devno = MKDEV (hello_major, hello_minor);
       cdev_init (&cdev, &hello_fops);
       cdev.owner = THIS_MODULE;
       cdev.ops = &hello_fops;
       error = cdev_add (&cdev, devno , 1);
       if (error)
           printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);

}

struct class *my_class;

static int __init hello_2_init (void)
{
       int result;
       dev = MKDEV (hello_major, hello_minor);
       result = register_chrdev_region (dev, number_of_devices, "hello");
       if (result<0) {
           printk (KERN_WARNING "hello: can't get major number %d/n", hello_major);
           return result;
     }

     char_reg_setup_cdev ();

     /* create your own class under /sysfs */
     my_class = class_create(THIS_MODULE, "my_class");

     if(IS_ERR(my_class)) 
     {
          printk("Err: failed in creating class./n");
          return -1; 
      }

      /* register your own device in sysfs, and this will cause udev to create corresponding device node */
      device_create( my_class, NULL, MKDEV(hello_major, 0),NULL, "hello" "%d", 0 );//"hello" "%d", 0 就是hello0

      printk (KERN_INFO "Registered character driver/n");
      return 0;
}

static void __exit hello_2_exit (void)
 {
       dev_t devno = MKDEV (hello_major, hello_minor);

       cdev_del (&cdev);

       device_destroy(my_class, MKDEV(adc_major, 0));         //delete device node under /dev
       class_destroy(my_class);                               //delete class created by us

       unregister_chrdev_region (devno, number_of_devices);

       printk (KERN_INFO "char driver cleaned up/n");
}

module_init (hello_2_init);module_exit (hello_2_exit);

相關文章
相關標籤/搜索