Chinaunix首页 | 论坛 | 博客
  • 博客访问: 301061
  • 博文数量: 47
  • 博客积分: 1411
  • 博客等级: 上尉
  • 技术积分: 500
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-23 09:10
文章分类

全部博文(47)

文章存档

2009年(3)

2008年(4)

2007年(14)

2006年(26)

我的朋友

分类: C/C++

2006-02-23 21:02:36

- Why hack
    Because of the requirement. That want a client to create more connections as possible as

it could to make benchmark test.
    As we know that the process resource of NOFILE(number of open file) is normal 1024, that

limit us to create file descriptor which is more than 1024. So do socket() call.
And the FD_XXX macro is not safe for fd larger than 1024 if the you just use one fd_set

struct to describe the sets.

- Analysis
    As smart linux, we can call setrlimit to set the NOFILE to 1MB(NR_OPEN marco in fs.h),

this is what we can take adventage of. Still another problem for fd_set struct and FD_XXX

macro. What's the internal of fd_set? Have a glance at Posix_types.h in Kernel Tree:

    #define NFDBITS    (8 * sizeof(unsigned long))
    typedef struct {
        unsigned long fds_bits [__FDSET_LONGS];
    } __kernel_fd_set;
    typedef __kernel_fd_set fd_set;

    So fd_set is just a pack of unsigned long array, which actually is bitmaps. We can

directly use following to access and contol:

    int fd;  /* which use for select */
    fd_set fds[ARRAY_SIZE];
    ...
    *((unsigned long*)fds + fd/NFDBITS)

    So we can write our own FD_XXX to access the fds. But does the select API accept this?

We again to look at sys_select syscall in select.c in Kernel Tree:
   
    size = FDS_BYTES(n); // n is max fd which is the first parameter of select
    bits = select_bits_alloc(size); // size is the bitmap size kmalloc here
    if (!bits)
        goto out_nofds;
    fds.in      = (unsigned long *)  bits;
    fds.out     = (unsigned long *) (bits +   size);
    fds.ex      = (unsigned long *) (bits + 2*size);
    fds.res_in  = (unsigned long *) (bits + 3*size);
    fds.res_out = (unsigned long *) (bits + 4*size);
    fds.res_ex  = (unsigned long *) (bits + 5*size);
    // kernel alloc it's own bitmaps and copy bitmaps from user space
    if ((ret = get_fd_set(n, inp, fds.in)) ||
        (ret = get_fd_set(n, outp, fds.out)) ||
        (ret = get_fd_set(n, exp, fds.ex)))
        goto out;

    Now it's clear, the fd sets size is corresponding to max fd to select. So the size of

fd_sets passing to call select, must be consistented to max fd.
    But here another problem, the kernel alloc for file descriptor increasely, so when the

connections increases the max fd increases too, same as the fd_set size. We must call

setrlimit to limit the max fd, the kernel will alloc file descriptor from beginning if the

max fd is alloced.

- Realization
   
    Define:

    #define NR_FDSETS    ((MAX_FD/sizeof(fd_set)/8)+1)
   
    #define SFD_SET(fd, fds)    \
    ( ((unsigned long *)fds)[(fd)/NFDBITS] \
    |= (1 << ((fd) % NFDBITS)))
   
    #define SFD_ZERO(fds)    \
    memset((void *)fds, 0, sizeof(fds));

    #define SFD_CLR(fd, fds)    \
    ( ((unsigned long *)fds)[(fd)/NFDBITS] \
    &= ~(1 << ((fd) % NFDBITS)))
   
    #define SFD_ISSET(fd, fds)    \
    ( ((unsigned long *)fds)[(fd)/NFDBITS] \
    & (1 << ((fd) % NFDBITS)))

    Usage:
    fd_set fds[NR_FDSETS];
    ....
    SFD_ZERO(fds)
    SFD_CLR(fd, fds)
    SFD_SET(fd, fds)
    SFD_ISSET(fd, fds)
阅读(1590) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~