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取不同的值,该调用有不同的表现:
——*timeout为0,不管是否有文件满足要求,都立刻返回,无文件满足要求返回0,有文件满足要求返回一个正值
——timeout为NULL,select将阻塞进程,直到某个文件满足要求
——*timeout为正整数,就是等待的最长时间,即select在timeout时间内阻塞进程,过后进程被唤醒
返回值
Select调用返回时,返回值有如下情况:
1.正常情况下返回满足要求的文件描述符个数
2.经过了timeout等待后任无文件满足要求,返回值为0;
3.如果select被某个信号中断,它将返回-1并设置errno为EINTR(可见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函数
刚开始写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);