曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 6337|回复: 0
打印 上一主题 下一主题

FD_ZERO(),FD_ISSET(), FD_SET(),FD_ZERO()|设置文件描述符集

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-3-27 15:45:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
FD_CLR(),FD_ISSET(), FD_SET(),FD_ZERO() 这几个函数配合 select() 使用,他们的作用是用来设置文件描述符集合。文件描述符集合类型表示为 fd_set 。
关于 select() 函数可参考:http://www.groad.net/bbs/read.php?tid-1064.html
关于 fd_set() 类型的说明可参考:http://www.groad.net/bbs/read.php?tid-1063.html

这些函数定义如下:
[C++] 纯文本查看 复制代码
#define FD_SET(fd,fdsetp)    __FD_SET(fd,fdsetp)
#define FD_CLR(fd,fdsetp)    __FD_CLR(fd,fdsetp)
#define FD_ISSET(fd,fdsetp)    __FD_ISSET(fd,fdsetp)
#define FD_ZERO(fdsetp)        __FD_ZERO(fdsetp)


这些函数在不同的平台上实现的方法有些不同。许多平台使用 C 语言来实现,而 x86 32位平台上则用汇编语言来实现,下面就对这个平台的实现进行说明。
FD_ZERO
[C++] 纯文本查看 复制代码
#define __FD_ZERO(fdsetp)                    \
do {                                \
    int __d0, __d1;                        \
    asm volatile("cld ; rep ; stosl"            \
             : "=m" (*(__kernel_fd_set *)(fdsetp)),    \
               "=&c" (__d0), "=&D" (__d1)        \
             : "a" (0), "1" (__FDSET_LONGS),        \
               "2" ((__kernel_fd_set *)(fdsetp))    \
             : "memory");                \
} while (0)

传递进宏中的参数的是文件描述符集合类型 fd_set 的指针 fdsetp 。对整个集合的清零方法是使用 stosl 指令,stosl 指令是将 eax 寄存器中的值不断的填充 edi 寄存器所指向的地址,然后这个地址自动加 4 (stosl 中的 l 后缀表明是双字递增),循环填充的次数由 ecx 中的值来指定。

FD_SET
[C++] 纯文本查看 复制代码
#define __FD_SET(fd,fdsetp)                    \
    asm volatile("btsl %1,%0":                \
             "+m" (*(__kernel_fd_set *)(fdsetp))    \
             : "r" ((int)(fd)))

FD_CLR
[C++] 纯文本查看 复制代码
#define __FD_CLR(fd,fdsetp) \
        __asm__ __volatile__("btrl %1,%0": \
            "+m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd)))

上面两个宏都使用 btsl 来设置或清零文件描述符集中的相应位。

FD_ISSET
[C++] 纯文本查看 复制代码
#define __FD_ISSET(fd,fdsetp) (__extension__ ({ \
        unsigned char __result; \
        __asm__ __volatile__("btl %1,%2 ; setb %0" \
            :"=q" (__result) :"r" ((int) (fd)), \
            "m" (*(__kernel_fd_set *) (fdsetp))); \
        __result; }))

先使用 bt 指令测试 fd 指定的位是否为 1,若为 1,则设置 CF=1,然后 setb 设置 __result 为 1,否则 __result 为 0 。整个宏的返回值就是 __result 。

当使用 _ansi 标志编译带有 gcc 扩展特性的程序时,为了避免发出警告,要使用 __extension__ 标签。比如在 glibc 中使用带有 long long 类型声明的函数时就会使用该标签。

关于 bts, btr 指令参考:http://www.groad.net/bbs/read.php?tid-3294.html
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 01:08 , Processed in 0.086597 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表