Давайте посмотрим, как это работает внутри (я использую ядро 4.1.20). Способ размещения файловых дескрипторов в Linux с помощью __alloc_fd. Когда вы делаете открытый системный вызов, вызывается do_sys_open. Эта процедура получает бесплатный дескриптор файла от get_unused_fd_flags:
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
...
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op);
get_unused_d_flags вызывает __alloc_fd, устанавливая минимальное и максимальное значения fd:
int get_unused_fd_flags(unsigned flags)
{
return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
}
__ alloc_fd получает таблицу дескрипторов файлов для процесса и получает fd в виде next_fd, которое фактически установлено с момента предыдущего запуска:
int __alloc_fd(struct files_struct *files,
unsigned start, unsigned end, unsigned flags)
{
...
fd = files->next_fd;
...
if (start <= files->next_fd)
files->next_fd = fd + 1;
Итак, вы можете видеть, как файловые дескрипторы действительно растут монотонно ... до определенного момента. Когда fd достигает максимума, __alloc_fd попытается найти наименьший неиспользуемый дескриптор файла:
if (fd < fdt->max_fds)
fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, fd);
На этом этапе файловые дескрипторы больше не будут монотонно расти, а вместо этого будут пытаться найти свободные файловые дескрипторы. После этого, если таблица заполнится, она будет расширена:
error = expand_files(files, fd);
В этот момент они снова будут монотонно расти.
Надеюсь, это поможет