select
是一种同步I/O复用机制,在大多数操作系统中都有实现,移植性较好;但是能够监听的文件描述符个数有限,而且采用轮询方式,效率较低。
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
select
实现为系统调用,详细如下:
#define __NFDBITS (8 * sizeof(unsigned long))
#define __FD_SETSIZE 1024
#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS)
typedef struct {
unsigned long fds_bits [__FDSET_LONGS];
} __kernel_fd_set;
typedef __kernel_fd_set fd_set;
fd_set
为文件描述符集合,是一个结构体类型,里面是一个unsigned long
型数组,在64位机上__FDSET_LONGS
值为16,则这个数组可以表示16×8×8=1024位,每一位表示一个文件描述符标志位,总共可以表示1024个文件描述符。这样可以方便直接用移位操作获取或设置文件描述符状态。
typedef long __kernel_time_t;
typedef long __kernel_suseconds_t;
struct timeval {
__kernel_time_t tv_sec; /* seconds */
__kernel_suseconds_t tv_usec; /* microseconds */
};
struct timeval
为超时时间类型,可以指定秒和微秒数。
下面为系统调用定义,SYSCALL_DEFINE5
为5个参数的系统调用宏扩展。
SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
fd_set __user *, exp, struct timeval __user *, tvp)
{
struct timespec end_time, *to = NULL;
struct timeval tv;
int ret;
if (tvp) { //设置了超时时间
if (copy_from_user(&tv, tvp, sizeof(tv))) //将用户空间设置的超时时间拷贝到内核空间
return