poll 设备 select 文件多路监控 自动创建设备文件

Select系统调用用于多路监控,当没有一个文件满足要求时,select将阻塞调用进程

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

——maxfd:文件描述符的范围,比待检测的最大文件描述符大1

——readfds:被读监控的文件描述符集

——writefds:被写监控的文件描述符集

——exceptfds:被异常监控的文件描述符集

——timeout:定时器。

Timeout取不同的值,该调用有不同的表现:

——*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);


你可能感兴趣的:(select,poll,设备,自动创建设备文件,文件多路监控)