thttpd源码之Fdwatch.c

此文件实现I/O多路复用的功能(select,kqueue,poll,devpoll),提供抽象的操作接口,从而保证了接口的单一性和可移植性。

接口:

/* Figure out how many file descriptors the system allows, and
** initialize the fdwatch data structures. Returns -1 on failure.
*/
int fdwatch_get_nfiles( void );
/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */
void fdwatch_add_fd( int fd, void* client_data, int rw );
/* Delete a descriptor from the watch list. */
void fdwatch_del_fd( int fd );
/* Do the watch. Return value is the number of descriptors that are ready,
** or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means
** wait indefinitely.
*/
int fdwatch( long timeout_msecs );
/* Check if a descriptor was ready. */
int fdwatch_check_fd( int fd );
/* Get the client data for the next returned event. Returns -1 when there
** are no more events.
*/
void* fdwatch_get_next_client_data( void );
/* Generate debugging statistics syslog message. */
void fdwatch_logstats( long secs );


//该函数用于获得当前可以复用的fd的最大个数,并初始化数据结构
int fdwatch_get_nfiles( void )
{
    int i;
#ifdef RLIMIT_NOFILE
    struct rlimit rl;
#endif /* RLIMIT_NOFILE */

    /* Figure out how many fd's we can have. */
	进程所能打开的最大文件描述符数
    nfiles = getdtablesize();
#ifdef RLIMIT_NOFILE
    /* If we have getrlimit(), use that, and attempt to raise the limit. */
	//设置资源限制的最大fd值 
    if ( getrlimit( RLIMIT_NOFILE, &rl ) == 0 )
	{
	nfiles = rl.rlim_cur;
	if ( rl.rlim_max == RLIM_INFINITY )
	    rl.rlim_cur = 8192;         /* arbitrary */
	else if ( rl.rlim_max > rl.rlim_cur )
	    rl.rlim_cur = rl.rlim_max;
	if ( setrlimit( RLIMIT_NOFILE, &rl ) == 0 )
	    nfiles = rl.rlim_cur;
	}
#endif /* RLIMIT_NOFILE */

#if defined(HAVE_SELECT) && ! ( defined(HAVE_POLL) || defined(HAVE_DEVPOLL) || defined(HAVE_KQUEUE) )
    /* If we use select(), then we must limit ourselves to FD_SETSIZE. */
	//select I/O,不能超过FD_SETSIZE(32)
    nfiles = MIN( nfiles, FD_SETSIZE );
#endif /* HAVE_SELECT && ! ( HAVE_POLL || HAVE_DEVPOLL || HAVE_KQUEUE ) */

    /* Initialize the fdwatch data structures. */
	//初始化数据结构
    nwatches = 0;
    fd_rw = (int*) malloc( sizeof(int) * nfiles );
    fd_data = (void**) malloc( sizeof(void*) * nfiles );
    if ( fd_rw == (int*) 0 || fd_data == (void**) 0 )
	return -1;
    for ( i = 0; i < nfiles; ++i )
	fd_rw[i] = -1;
    if ( INIT( nfiles ) == -1 )
	return -1;

    return nfiles;
}
//添加需要监控的fd,rw为FDW_READ(0)或FDW_WRITE(1)
void fdwatch_add_fd( int fd, void* client_data, int rw )
{
	//检查fd是否在范围之内,并且检查fd是否已经存在
    if ( fd < 0 || fd >= nfiles || fd_rw[fd] != -1 )
	{
		syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_add_fd!", fd );
		return;
	}
    ADD_FD( fd, rw );
    fd_rw[fd] = rw;
    fd_data[fd] = client_data;
}
#def
ine ADD_FD( fd, rw )       select_add_fd( fd, rw )//select I/O
//select I/O 添加fd
static void select_add_fd( int fd, int rw )
{
    if ( nselect_fds >= nfiles )
    {
		syslog( LOG_ERR, "too many fds in select_add_fd!" );
		return;
    }
    //index-->fd(通过index找到fd)
    select_fds[nselect_fds] = fd;
    switch ( rw )
    {
	case FDW_READ: FD_SET( fd, &master_rfdset ); break;
	case FDW_WRITE: FD_SET( fd, &master_wfdset ); break;
	default: break;
    }
    if ( fd > maxfd )
	maxfd = fd;
    //fd-->index 通过fd找到数组(select_fds)位置index
    select_fdidx[fd] = nselect_fds;
    ++nselect_fds;
}

//删除监测的fd
void fdwatch_del_fd( int fd )
{
    if ( fd < 0 || fd >= nfiles || fd_rw[fd] == -1 )
	{
		syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_del_fd!", fd );
		return;
	}
	//重点在DEL_FD
    DEL_FD( fd );
    fd_rw[fd] = -1;
    fd_data[fd] = (void*) 0;
}
#define DEL_FD( fd )           select_del_fd( fd ) //select I/O
//select I/O 删除fd
static void select_del_fd( int fd )
 {
    int idx = select_fdidx[fd];  //获取fd在select_fds的位置

    if ( idx < 0 || idx >= nfiles )
	{
		syslog( LOG_ERR, "bad idx (%d) in select_del_fd!", idx );
		return;
	}

    --nselect_fds;//select_add_fd函数中末尾++nselect_fds;
	//把最后的fd,和fd对应的index替换要删除的fd和fd的index//比较绕
    select_fds[idx] = select_fds[nselect_fds]; 
    select_fdidx[select_fds[idx]] = idx;       
    select_fds[nselect_fds] = -1;
    select_fdidx[fd] = -1;

    FD_CLR( fd, &master_rfdset );
    FD_CLR( fd, &master_wfdset );

    if ( fd >= maxfd )
		maxfd_changed = 1;
}

//在大循环中,将master_fdset的值赋值给working_fdset然后调用select传入working_fdset进行检测,检测的时候由参数timeout_msecs决定
int	fdwatch( long timeout_msecs )
{
    ++nwatches;
    nreturned = WATCH( timeout_msecs );
    next_ridx = 0;
    return nreturned;
}

#define WATCH( timeout_msecs ) select_watch( timeout_msecs )

static int	select_watch( long timeout_msecs )
{
    int mfd;
    int r, idx, ridx;

    working_rfdset = master_rfdset;
    working_wfdset = master_wfdset;
    mfd = select_get_maxfd();
    if ( timeout_msecs == INFTIM )
       r = select(
           mfd + 1, &working_rfdset, &working_wfdset, (fd_set*) 0,
           (struct timeval*) 0 );
    else
	{
		struct timeval timeout;
		timeout.tv_sec = timeout_msecs / 1000L;
		timeout.tv_usec = ( timeout_msecs % 1000L ) * 1000L;
		r = select(
		mfd + 1, &working_rfdset, &working_wfdset, (fd_set*) 0, &timeout );
	}
    if ( r <= 0 )
	return r;

    ridx = 0;
    for ( idx = 0; idx < nselect_fds; ++idx )
		if ( select_check_fd( select_fds[idx] ) )
		{
			select_rfdidx[ridx++] = select_fds[idx];
			if ( ridx == r )
			break;
		}

    return ridx;	/* should be equal to r */
}

可以看出,fdwatch.c文件是对多路复用I/O的封装,提供抽象接口,,从而可以正常的处理小规模的服务器并发。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值