LDD3源码学习日记<八>

一、用户空间的poll和select测试函数

在使用者两个函数之前,需要先安装scullpipe设备,下面是他们的测试代码和注释:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <unistd.h>  
#include <linux/poll.h>  
#include <sys/time.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
  
int main(int argc, char *argv[])  
{  
    int fd0, fd1, fd2, fd3;  
    struct pollfd poll_fd[4];  
    char buf[100];  
    int retval;  
    /*如果没有指定参数,或者参数不等于read和wtite,打印提示信息*/
    if(argc != 2 || ((strcmp(argv[1], "read") != 0) && (strcmp(argv[1], "write") != 0)))  
    {  
        printf("usage: ./poll_test read|write\n");  
        return -1;  
    }  
  
    fd0 = open("/dev/scullpipe0", O_RDWR);  //打开设备scullpipe0
    if ( fd0 < 0)  
    {  
        printf("open scullpipe0 error\n");  
        return -1;  
    }  
      
    fd1 = open("/dev/scullpipe1", O_RDWR);  //打开设备scullpipe1
    if ( fd1 < 0)  
    {  
        printf("open scullpipe1 error\n");  
        return -1;  
    }  
      
    fd2 = open("/dev/scullpipe2", O_RDWR);  //打开设备scullpipe2
    if ( fd2 < 0)  
    {  
        printf("open scullpipe2 error\n");  
        return -1;  
    }  
      
    fd3 = open("/dev/scullpipe3", O_RDWR);  //打开设备scullpipe3
    if ( fd3 < 0)  
    {  
        printf("open scullpipe3 error\n");  
        return -1;  
    }  
  
    if(strcmp(argv[1], "read") == 0)  	//如果是read
    {  
        poll_fd[0].fd = fd0;  		
        poll_fd[1].fd = fd1;  
        poll_fd[2].fd = fd2;  
        poll_fd[3].fd = fd3;  
  
        poll_fd[0].events = POLLIN | POLLRDNORM;  	//检查是否可读,一般为固定搭配
        poll_fd[1].events = POLLIN | POLLRDNORM;  
        poll_fd[2].events = POLLIN | POLLRDNORM;  
        poll_fd[3].events = POLLIN | POLLRDNORM;  
  
        retval = poll(poll_fd, 4, 10000); 		//监测poll_fd数组里面的4个文件,并设置超时时间为10,000毫秒 
    }  
    else  
    {  
        poll_fd[0].fd = fd0;  
        poll_fd[1].fd = fd1;  
        poll_fd[2].fd = fd2;  
        poll_fd[3].fd = fd3;  
  
        poll_fd[0].events = POLLOUT | POLLWRNORM;  	//检查是否可写
        poll_fd[1].events = POLLOUT | POLLWRNORM;  
        poll_fd[2].events = POLLOUT | POLLWRNORM;  
        poll_fd[3].events = POLLOUT | POLLWRNORM;  
          
        retval = poll(poll_fd, 4, 10000);  
    }  
  
    if (retval == -1)  					//poll返回一个负数,说明poll调用出错
    {  
        printf("poll error!\n");  
        return -1;  
    }  
    else if (retval)  					//poll函数如果返回一个正数,代表内核返回了状态(保存在pollfd.revents中)的文件描述符的个数
    {  
        if(strcmp(argv[1], "read") == 0)  
        {  
            if(poll_fd[0].revents & (POLLIN | POLLRDNORM))  
            {  
                printf("/dev/scullpipe0 is readable!\n");  
                memset(buf, 0, 100);  
                read(fd0, buf, 100);  
                printf("%s\n", buf);  
            }  
  
            if(poll_fd[1].revents & (POLLIN | POLLRDNORM))  
            {  
                printf("/dev/scullpipe1 is readable!\n");  
                memset(buf, 0, 100);  
                read(fd1, buf, 100);  
                printf("%s\n", buf);  
            }  
  
            if(poll_fd[2].revents & (POLLIN | POLLRDNORM))  
            {  
                printf("/dev/scullpipe2 is readable!\n");  
                memset(buf, 0, 100);  
                read(fd2, buf, 100);  
                printf("%s\n", buf);  
            }  
  
            if(poll_fd[3].revents & (POLLIN | POLLRDNORM))  
            {  
                printf("/dev/scullpipe3 is readable!\n");  
                memset(buf, 0, 100);  
                read(fd3, buf, 100);  
                printf("%s\n", buf);  
            }  
        }  
        else  							
        {  
            if(poll_fd[0].revents & (POLLOUT | POLLWRNORM))  
            {  
                printf("/dev/scullpipe0 is writable!\n");  
            }  
  
            if(poll_fd[1].revents & (POLLOUT | POLLWRNORM))  
            {  
                printf("/dev/scullpipe1 is writable!\n");  
            }  
  
            if(poll_fd[2].revents & (POLLOUT | POLLWRNORM))  
            {  
                printf("/dev/scullpipe2 is writable!\n");  
            }  
  
            if(poll_fd[3].revents & (POLLOUT | POLLWRNORM))  
            {  
                printf("/dev/scullpipe3 is writable!\n");  
            }  
        }  
    }  
    else  //如果poll返回0,表明是因为超时而返回的
    {  
        if(strcmp(argv[1], "read") == 0)  
        {  
            printf("No data within ten seconds.\n");  
        }  
        else  
        {  
            printf("Can not write within ten seconds.\n");  
        }  
    }  
  
    return 0;  
}  

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <unistd.h>  
#include <sys/time.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
  
int main(int argc, char *argv[])  
{  
    fd_set rfds, wfds;  
    int fd0, fd1, fd2, fd3;  
    char buf[100];  
    int retval;      
  
    /* Wait up to ten seconds. */  
    struct timeval tv;  
    tv.tv_sec = 10;  
    tv.tv_usec = 0;  
  
    if(argc != 2 || ((strcmp(argv[1], "read") != 0) && (strcmp(argv[1], "write") != 0)))  
    {  
        printf("usage: ./select_test read|write\n");  
        return -1;  
    }  
  
    fd0 = open("/dev/scullpipe0", O_RDWR);  
    if ( fd0 < 0)  
    {  
        printf("open scullpipe0 error\n");  
        return -1;  
    }  
      
    fd1 = open("/dev/scullpipe1", O_RDWR);  
    if ( fd1 < 0)  
    {  
        printf("open scullpipe1 error\n");  
        return -1;  
    }  
      
    fd2 = open("/dev/scullpipe2", O_RDWR);  
    if ( fd2 < 0)  
    {  
        printf("open scullpipe2 error\n");  
        return -1;  
    }  
      
    fd3 = open("/dev/scullpipe3", O_RDWR);  
    if ( fd3 < 0)  
    {  
        printf("open scullpipe3 error\n");  
        return -1;  
    }  
  
    if(strcmp(argv[1], "read") == 0)  
    {  
        FD_ZERO(&rfds);  
        FD_SET(fd0, &rfds);  
        FD_SET(fd1, &rfds);  
        FD_SET(fd2, &rfds);  
        FD_SET(fd3, &rfds);  
        retval = select(fd3 + 1, &rfds, NULL, NULL, &tv);  
    }  
    else  
    {  
        FD_ZERO(&wfds);  
        FD_SET(fd0, &wfds);  
        FD_SET(fd1, &wfds);  
        FD_SET(fd2, &wfds);  
        FD_SET(fd3, &wfds);  
        retval = select(fd3 + 1, NULL, &wfds, NULL, &tv);  
    }  
  
    if (retval == -1)  
    {  
        printf("select error!\n");  
        return -1;  
    }  
    else if (retval)  
    {  
        if(strcmp(argv[1], "read") == 0)  
        {  
            if(FD_ISSET(fd0, &rfds))  
            {  
                printf("/dev/scullpipe0 is readable!\n");  
                memset(buf, 0, 100);  
                read(fd0, buf, 100);  
                printf("%s\n", buf);  
            }  
  
            if(FD_ISSET(fd1, &rfds))  
            {  
                printf("/dev/scullpipe1 is readable!\n");  
                memset(buf, 0, 100);  
                read(fd1, buf, 100);  
                printf("%s\n", buf);  
            }  
  
            if(FD_ISSET(fd2, &rfds))  
            {  
                printf("/dev/scullpipe2 is readable!\n");  
                memset(buf, 0, 100);  
                read(fd2, buf, 100);  
                printf("%s\n", buf);  
            }  
  
            if(FD_ISSET(fd3, &rfds))  
            {  
                printf("/dev/scullpipe3 is readable!\n");  
                memset(buf, 0, 100);  
                read(fd3, buf, 100);  
                printf("%s\n", buf);  
            }  
        }  
        else  
        {  
            if(FD_ISSET(fd0, &wfds))  
            {  
                printf("/dev/scullpipe0 is writable!\n");  
            }  
  
            if(FD_ISSET(fd1, &wfds))  
            {  
                printf("/dev/scullpipe1 is writable!\n");  
            }  
  
            if(FD_ISSET(fd2, &wfds))  
            {  
                printf("/dev/scullpipe2 is writable!\n");  
            }  
  
            if(FD_ISSET(fd3, &wfds))  
            {  
                printf("/dev/scullpipe3 is writable!\n");  
            }  
        }  
    }  
    else  
    {  
        if(strcmp(argv[1], "read") == 0)  
        {  
            printf("No data within ten seconds.\n");  
        }  
        else  
        {  
            printf("Can not write within ten seconds.\n");  
        }  
    }  
  
    return 0;  
}  
下面是测试结果图:


二、驱动程序的poll

用户空间的poll和select都会调用到驱动程序的poll,下面是scullpipe驱动程序的poll实现

/*****************************************************************************************/
/*poll函数应该实现两个功能:

一是把能标志轮询状态变化的等待队列加入到poll_table中,这通过调用poll_wait函数实现。

二是返回指示能进行的I/O操作的标志位。

poll函数的第二个参数poll_table,是内核中用来实现poll,select系统调用的结构体,对于驱动开发者来说,
不必关心其具体内容,可以把poll_table看成是不透明的结构体,只要拿过来使用就可以了。驱动程序通过poll_wait函数,
把能够唤醒进程,改变轮询状态的等待队列加入到poll_table中。该函数定义如下:
void poll_wait (struct file *, wait_queue_head_t *, poll_table *); 
对于poll函数的第二个功能,返回的标志位与用户空间相对应,最常用的标志位是POLLIN | POLLRDNORM和POLLOUT | POLLWRNORM,
分别标志可进行非阻塞的读和写操作。*/
/*******************************************************************************************/

static unsigned int scull_p_poll(struct file *filp, poll_table *wait)
{
	struct scull_pipe *dev = filp->private_data;
	unsigned int mask = 0;

	/*
	 * The buffer is circular; it is considered full
	 * if "wp" is right behind "rp" and empty if the
	 * two are equal.
	 */
	down(&dev->sem);
	/*调用poll_wait函数将读等待队列加入到poll_table中*/
	poll_wait(filp, &dev->inq,  wait);
	/*调用poll_wait函数将写等待队列加入到poll_table中*/
	poll_wait(filp, &dev->outq, wait);
	/*如果有内容可读,设置可读标志位**/
	if (dev->rp != dev->wp)
		mask |= POLLIN | POLLRDNORM;	/* readable */
	if (spacefree(dev))
	/*如果有空间可写,设置可写标志位*/
		mask |= POLLOUT | POLLWRNORM;	/* writable */
	up(&dev->sem);
	/*将标志位返回*/
	return mask;
}
参考博客:http://blog.csdn.net/liuhaoyutz/article/details/7401418


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值