- 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)
阅读(1597) | 评论(2) | 转发(0) |