linux设备驱动--非阻塞IO与select,poll调用 (续1)

        在《linux设备驱动--非阻塞IOselect,poll调用》中给出了驱动中poll函数的一般写法,很简单明了。但是为什么这么写,还是要稍微追究一下的。


        首先,用manselect看下select的用法:

NAME

select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O

multiplexing


SYNOPSIS

/*According to POSIX.1-2001 */

#include<sys/select.h>


/*According to earlier standards */

#include<sys/time.h>

#include<sys/types.h>

#include<unistd.h>


intselect(int nfds, fd_set *readfds, fd_set *writefds,

fd_set*exceptfds, struct timeval *timeout);


voidFD_CLR(int fd, fd_set *set);

int FD_ISSET(int fd, fd_set *set);

voidFD_SET(int fd, fd_set *set);

voidFD_ZERO(fd_set *set);


select的简短描述如下:

select()and pselect() allow a program to monitor multiple file

descriptors, waiting until one or more of the file descriptors become

"ready"for some class of I/O operation (e.g., input possible). A file

descriptor is considered ready if it is possible to perform the corre‐

spondingI/O operation (e.g., read(2)) without blocking.

大意是:selectpselect允许程序监控多个文件描述符,一直到一个或多个文件描述“准备”可以被某类IO操作。如果相关的非阻塞的IO操作可以执行,我们就认为文件描述符“准备”好了。


man手册最后给出了select函数的一个简单例子:

#include<stdio.h>

#include<stdlib.h>

#include<sys/time.h>

#include<sys/types.h>

#include<unistd.h>

int

main(void)

{

fd_setrfds;

structtimeval tv;

intretval;

/*Watch stdin (fd 0) to see when it has input. */

FD_ZERO(&rfds);

FD_SET(0,&rfds);

/*Wait up to five seconds. */

tv.tv_sec= 5;

tv.tv_usec= 0;

retval= select(1, &rfds, NULL, NULL, &tv);

/*Don't rely on the value of tv now! */

if(retval == -1)

perror("select()");

elseif (retval)

printf("Datais available now.\n");

/*FD_ISSET(0, &rfds) will be true. */

else

printf("Nodata within five seconds.\n");

exit(EXIT_SUCCESS);

}



这个例子是监听文件描述符0的,文件描述符012分别定位stdinstdoutstderr


这个看起来简单,其实还是有点不简单的。

Fd_set这个定义是啥?从字面上看,就是fdset,代表一簇文件描述符。


typedef__kernel_fd_set fd_set;

#undef__NFDBITS

#define__NFDBITS (8 * sizeof(unsigned long)) //8×4 = 32

#undef__FD_SETSIZE

#define__FD_SETSIZE 1024

#undef__FDSET_LONGS

#define__FDSET_LONGS (__FD_SETSIZE/__NFDBITS) //1024/32 = 32

#undef__FDELT

#define __FDELT(d) ((d)/ __NFDBITS)

#undef__FDMASK

#define __FDMASK(d) (1UL<< ((d) % __NFDBITS))

typedefstruct {

unsignedlong fds_bits [__FDSET_LONGS];

}__kernel_fd_set;



这样一看,fd_set就是一个包含着数组的的结构体。


Fd_set实际上是用到了bitmapbitmap的一些常见应用可以看《》;没想到的是bitmap除了linux中文件系统的omfs(较简单的fs)中有应用,在select中也有应用。


这里还看不出为何是bitmap,看了

voidFD_CLR(int fd, fd_set *set);

int FD_ISSET(int fd, fd_set *set);

voidFD_SET(int fd, fd_set *set);

voidFD_ZERO(fd_set *set);

这四个函数的实现后,就会清楚。


这四个函数的具体实现与cpu的架构相关,以arch\mips\include\asm\posix_types.h为例:


#ifdefined(__KERNEL__)

#undef__FD_SET

static__inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set*__fdsetp)

{

unsignedlong __tmp = __fd / __NFDBITS;

unsignedlong __rem = __fd % __NFDBITS;

__fdsetp->fds_bits[__tmp]|= (1UL<<__rem);

}

#undef__FD_CLR

static__inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set*__fdsetp)

{

unsignedlong __tmp = __fd / __NFDBITS;

unsignedlong __rem = __fd % __NFDBITS;

__fdsetp->fds_bits[__tmp]&= ~(1UL<<__rem);

}

#undef__FD_ISSET

static__inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set*__p)

{

unsignedlong __tmp = __fd / __NFDBITS;

unsignedlong __rem = __fd % __NFDBITS;

return(__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;

}

/*

*This will unroll the loop for the normal constant case (8 ints,

*for a 256-bit fd_set)

*/

#undef__FD_ZERO

static__inline__ void __FD_ZERO(__kernel_fd_set *__p)

{

unsignedlong *__tmp = __p->fds_bits;

int__i;

if(__builtin_constant_p(__FDSET_LONGS)) {

switch(__FDSET_LONGS) {

case16:

__tmp[0] = 0; __tmp[ 1] = 0;

__tmp[2] = 0; __tmp[ 3] = 0;

__tmp[4] = 0; __tmp[ 5] = 0;

__tmp[6] = 0; __tmp[ 7] = 0;

__tmp[8] = 0; __tmp[ 9] = 0;

__tmp[10]= 0; __tmp[11] = 0;

__tmp[12]= 0; __tmp[13] = 0;

__tmp[14]= 0; __tmp[15] = 0;

return;

case8:

__tmp[0] = 0; __tmp[ 1] = 0;

__tmp[2] = 0; __tmp[ 3] = 0;

__tmp[4] = 0; __tmp[ 5] = 0;

__tmp[6] = 0; __tmp[ 7] = 0;

return;

case4:

__tmp[0] = 0; __tmp[ 1] = 0;

__tmp[2] = 0; __tmp[ 3] = 0;

return;

}

}

__i= __FDSET_LONGS;

while(__i) {

__i--;

*__tmp= 0;

__tmp++;

}

}

#endif/* defined(__KERNEL__) */



FD_SETFD_CLR来看,很明显看出是bitmap的操作。


了解这里的bitmap对后面select系统调用的分析很有帮助,先到这里.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值