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