/* * Unix kernel has an expensive get_unused_fd() function : * This is because semantics of Unix mandates that a open()/pipe()/socket()/ call always returns the lowest fd, not a random one. * Linux use a linear scan of a table of bits. * A program handling 1.000.000 files scans about 128 KB of ram, with a spinlock held : No other thread can get a fd. * * The trick is to use this library to make sure 64 low fds are available, so that the standard unix functions * dont have to scan a lot of fd before finding a free one. * And remap them using fcntl(F_DUPFD) at precise slots we manage ourselfs. */ #include #include #include #include # define MAXFDS 1500000 struct { pthread_mutex_t lock; unsigned int cache_fd; unsigned int next_alloc; unsigned int *cache_tab; } fdd; void fdcache_init() { pthread_mutex_init(&fdd.lock, NULL); fdd.cache_tab = calloc(MAXFDS, sizeof(unsigned int)); fdd.next_alloc = 64; } int fdcache_dupfd(int fd) { int ret; pthread_mutex_lock(&fdd.lock); if (fdd.cache_fd == 0) fdd.cache_fd = fdd.next_alloc++; ret = fcntl(fd, F_DUPFD, fdd.cache_fd); if (ret != -1) { fdd.cache_fd = fdd.cache_tab[ret]; pthread_mutex_unlock(&fdd.lock); close(fd); return ret; } else { pthread_mutex_unlock(&fdd.lock); return fd; } } void fdcache_closefd(int fd) { if (fd == -1) return; close(fd); pthread_mutex_lock(&fdd.lock); fdd.cache_tab[fd] = fdd.cache_fd; fdd.cache_fd = fd; pthread_mutex_unlock(&fdd.lock); }