Как увеличить лимит "максимально открытых файлов" в C на Mac OS X

Ограничение по умолчанию для максимального количества открытых файлов в Mac OS X составляет 256 (ulimit -n), и моему приложению требуется около 400 обработчиков файлов.

Я пытался изменить предел с помощью setrlimit(), но даже если функция выполняется правильно, я все еще ограничен 256.

Вот тестовая программа, которую я использую:

#include <stdio.h>
#include <sys/resource.h>

main()
{
  struct rlimit rlp;

  FILE *fp[10000];
  int i;

  getrlimit(RLIMIT_NOFILE, &rlp);
  printf("before %d %d\n", rlp.rlim_cur, rlp.rlim_max);

  rlp.rlim_cur = 10000;
  setrlimit(RLIMIT_NOFILE, &rlp);

  getrlimit(RLIMIT_NOFILE, &rlp);
  printf("after %d %d\n", rlp.rlim_cur, rlp.rlim_max);

  for(i=0;i<10000;i++) {
    fp[i] = fopen("a.out", "r");
    if(fp[i]==0) { printf("failed after %d\n", i); break; }
  }

}

и вывод:

before 256 -1
after 10000 -1
failed after 253

Я не могу просить людей, которые используют мое приложение, тыкать в файл /etc или что-то в этом роде. Мне нужно приложение, чтобы сделать это само по себе.

6 ответов

Решение

etresoft нашел ответ на доске обсуждений Apple:

Вся проблема здесь в вашей функции printf(). Когда вы вызываете printf (), вы инициализируете внутренние структуры данных до определенного размера. Затем вы вызываете setrlimit (), чтобы попытаться настроить эти размеры. Эта функция не работает, потому что вы уже использовали эти внутренние структуры в вашей функции printf(). Если вы используете две структуры rlimit (одну для до и одну для после) и не печатаете их до тех пор, пока не вызовете setrlimit, вы обнаружите, что можете изменить пределы текущего процесса даже в программе командной строки. Максимальное значение составляет 10240.

rlp.rlim_cur = 10000;

Две вещи.

Первый. ЛОЛ. Очевидно, вы нашли ошибку в Mac OS X' stdio. Если я исправлю вашу программу, добавлю обработку ошибок и т. Д., А также заменю fopen() на системный вызов open (), я могу легко достичь предела 10000 (что на 240 фд ниже моего 10.6.3'ограничения OPEN_MAX 10240)

Второй. RTFM: man setrlimit, Случай с максимальным количеством открытых файлов должен рассматриваться конкретно в отношении OPEN_MAX.

По какой-то причине (возможно, двоичная совместимость), вы должны определить _DARWIN_UNLIMITED_STREAMS перед включением <stdio.h>:

#define _DARWIN_UNLIMITED_STREAMS

#include <stdio.h>
#include <sys/resource.h>

main()
{
  struct rlimit rlp;

  FILE *fp[10000];
  int i;

  getrlimit(RLIMIT_NOFILE, &rlp);
  printf("before %d %d\n", rlp.rlim_cur, rlp.rlim_max);

  rlp.rlim_cur = 10000;
  setrlimit(RLIMIT_NOFILE, &rlp);

  getrlimit(RLIMIT_NOFILE, &rlp);
  printf("after %d %d\n", rlp.rlim_cur, rlp.rlim_max);

  for(i=0;i<10000;i++) {
    fp[i] = fopen("a.out", "r");
    if(fp[i]==0) { printf("failed after %d\n", i); break; }
  }

}

печать

before 256 -1
after 10000 -1
failed after 9997

Эта функция, кажется, была представлена ​​в Mac OS X 10.6.

Это может быть жестким ограничением вашего libc. Некоторые версии Solaris имеют аналогичное ограничение, потому что они хранят fd как unsigned char в FILE структура. Если это касается и вашего libc, вы, возможно, не сможете делать то, что хотите.

Насколько я знаю, такие вещи, как setrlimit влияет только на то, сколько файлов вы можете открыть open (fopen почти наверняка реализован в терминах open). Так что, если это ограничение на уровне libc, вам понадобится альтернативное решение.

Конечно, вы всегда можете не использовать fopen и вместо этого используйте open Системный вызов доступен практически для каждого варианта Unix.

Недостатком является то, что вы должны использовать write а также read вместо fwrite а также fread, которые не выполняют такие вещи, как буферизация (это все делается в вашей libc, а не самой ОС). Так что это может стать узким местом в производительности.

Можете ли вы описать сценарий, который требует 400 файлов, открытых ** одновременно **? Я не говорю, что нет такого случая, когда это необходимо. Но если вы опишите ваш вариант использования более четко, то, возможно, мы можем порекомендовать лучшее решение.

Я знаю, что это звучит глупо, но вам действительно нужно открыть 400 файлов одновременно? Кстати, вы запускаете этот код от имени root?

Mac OS не позволяет нам легко изменять лимит, как во многих операционных системах на основе Unix. Мы должны создать два файла

/Library/LaunchDaemons/limit.maxfiles.plist /Library/LaunchDaemons/limit.maxproc.plist, описывающий максимальный процесс и максимальный лимит файла. Владелец файла должен быть изменен на "root: wheel"

Это само по себе не решает проблему, по умолчанию последняя версия Mac OSX использует 'csrutil', мы должны отключить его. Чтобы отключить его, нам нужно перезагрузить Mac в режиме восстановления и оттуда отключить csrutil с помощью терминала.

Теперь мы можем легко изменить максимальное ограничение дескриптора открытого файла из самого терминала (даже в обычном режиме загрузки).

Этот метод подробно объясняется в следующей ссылке. http://blog.dekstroza.io/ulimit-shenanigans-on-osx-el-capitan/

работает для OSX-elcapitan и OSX-Seirra.

Другие вопросы по тегам