2010-07-02 31 views
5

Domyślnym limitem maksymalnych otwartych plików w systemie Mac OS X jest 256 (ulimit -n), a moja aplikacja potrzebuje około 400 programów do obsługi plików.Jak zwiększyć limit "maksymalnych otwartych plików" w C na Mac OS X

Próbowałem zmienić limit z setrlimit(), ale nawet wtedy, gdy funkcja wykonuje prawidłowo, nadal jestem ograniczona do 256.

Oto program testów używam:

#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; } 
    } 

} 

i wyjście to:

before 256 -1 
after 10000 -1 
failed after 253 

Nie mogę prosić ludzi, którzy używają mojej aplikacji, do włożenia plików/etc. Potrzebuję aplikacji, aby zrobić to sama.

+0

Dlaczego potrzebujesz tak wielu plików otwartych jednocześnie? – sbooth

+0

Nie to powinno mieć znaczenie, ale czy testujesz to w wydaniu na serwerze lub na desktopowej wersji OSX? Mogę sobie wyobrazić, że ludzie z jabłek postanowili ograniczyć liczbę plików, które może otworzyć aplikacja komputerowa, ponieważ otwieranie wielu jest zwykle zadaniem zorientowanym na serwer ... –

Odpowiedz

5

etresoft znaleźć odpowiedź na apple discussion board:

Cały problem tutaj jest funkcja Twój printf().Po wywołaniu printf(), inicjujesz wewnętrzne struktury danych do pewnego rozmiaru . Następnie wywołaj setrlimit() do spróbuj dostosować te rozmiary. Ta funkcja nie działa, ponieważ masz już używasz wewnętrznych struktur z printf(). Jeśli użyć dwóch rlimit struktur (po jednym dla przed i po jednym dla), a nie robić wydrukować je dopiero po wywołaniu setrlimit, można zauważyć, że można zmienić granice obecnej procesu nawet w poleceniu linia program. Maksymalna wartość wynosi 10240.

0

Wiem, że to głupie pytanie, ale naprawdę potrzebujesz 400 plików otwartych w tym samym czasie? Przy okazji, czy uruchamiasz ten kod jako root?

+0

Tak, potrzebuję 400 plików otwartych w tym samym czasie i nie, nie jestem rootem. jak mówi mężczyzna, ponieważ nie zmieniam maksymalnego limitu, ale tylko limit cur, nie muszę być rootem. – acemtp

+2

Ale czy maksymalny limit limitu nie byłby limitem? – nategoose

5

rlp.rlim_cur = 10000;

Dwie rzeczy.

1st. LOL. Najwyraźniej znalazłeś błąd w stdio systemu Mac OS X. Jeśli naprawię twój program/dodaję obsługę błędów/etc, a także zamieniam fopen() na open() syscall, mogę łatwo osiągnąć limit 10000 (co jest 240 fds poniżej mojego 10,6.3 "limit OPEN_MAX 10240)

2nd. RTFM: man setrlimit. Przypadek max otwartych plików musi być traktowany konkretnie w odniesieniu do OPEN_MAX.

+1

Thx za odpowiedź. Czy jesteś poważny, gdy mówisz, że może to być błąd w stdio na Mac OS X lub żart? , więc jedynym rozwiązaniem jest użycie syscall zamiast standardowej funkcji C? – acemtp

+0

@acemtp: ograniczenie jest prawdopodobnie lepszym słowem. Standard wymaga tylko libc, aby zagwarantować, że możesz otworzyć 8 plików na raz (w tym 'stdin' /' stdout'/'stderr'!). Byłoby to niezwykłe ograniczenie, ale nie było to niesłychane. –

+1

@ acetemp, @evan: dobrze stdio na Linuksie nie ma problemów z radzeniem sobie z tym, co na niego rzucam. i osobiście zakwalifikuję to jako błąd. 8 plików naraz? stdio, stdin, stderr - 3 są już zajęte. Plik dziennika aplikacji + plik śledzenia - pozostawia tylko 3 za darmo ... Głupi i błąd, jeśli mnie pytasz. – Dummy00001

2

To może być trudne ograniczenie twojej libc. Niektóre wersje solaris mają podobne ograniczenie, ponieważ przechowują one jako strukturę unsigned char. Jeśli tak jest również w przypadku twojej libc, możesz nie być w stanie zrobić, co chcesz.

Z tego co wiem, rzeczy takie jak setrlimit wpływają tylko na to, ile plików można otworzyć za pomocą open (fopen jest prawie na pewno zaimplementowany pod względem open). Więc jeśli to ograniczenie jest na poziomie libc, będziesz potrzebować alternatywnego rozwiązania.

Oczywiście zawsze można nie używać fopen i zamiast tego używać wywołania systemowego open dostępnego w prawie każdym wariancie systemu UNIX.

Minusem jest to, że trzeba użyć write i read zamiast fwrite i fread, które nie robić rzeczy, jak buforowanie (to wszystko zrobić w libc, a nie przez sam OS). Więc może to być wąskie gardło wydajności.

Czy można opisać scenariusz, który wymaga 400 plików otwartych ** jednocześnie **? Nie mówię, że nie ma przypadku, w którym jest to potrzebne. Jeśli jednak lepiej opisasz swój przypadek użycia, być może będziemy mogli polecić lepsze rozwiązanie.

+0

limit libc: Tak. Zobacz mój komentarz.Zmiana programu na open() zamiast fopen() rozwiązuje problem. Na Linuksie btw działa jak urok - po dokonaniu oczywistej poprawki zastąpienia 10000 rlp.rlim_max (ale na Mac OS X nawet to jest inne, ponieważ trzeba również sprawdzić limit OPEN_MAX). Scenariusz, w którym potrzebujesz 400 fds ... Posiadam wyspecjalizowany serwer sieciowy, który również przesyła dane na dysk. Oglądanie gniazd 2K i otwieranie plików w użyciu nie jest rzadkością. – Dummy00001

+0

@ Dummy00001: OK, to z pewnością ** scenariusz **, ale mając acemtp opisać dokładnie to, co stara się zrobić, może nadal pomóc :-P. Wygląda jednak na to, że znaleźliśmy naturę problemu. –

+0

dziękuję za wyjaśnienie pochodzenia. – Dummy00001

2

Z jakiegoś powodu (kompatybilność może binarny), trzeba określić _DARWIN_UNLIMITED_STREAMS przed tym <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; } 
    } 

} 

drukuje

before 256 -1 
after 10000 -1 
failed after 9997 

Funkcja ta wydaje się mieć został wprowadzony w systemie Mac OS X 10.6.

-1

Mac OS nie pozwala na łatwą zmianę limitu, tak jak w wielu systemach operacyjnych opartych na Uniksie. Musimy stworzyć dwa pliki

/Library/LaunchDaemons/limit.maxfiles.plist /Library/LaunchDaemons/limit.maxproc.plist opisujące proc max i max limitu pliku. Własność pliku musi zostać zmieniona na "root: wheel"

Samo to nie rozwiąże problemu, domyślnie najnowsza wersja mac OSX używa "csrutil", musimy go wyłączyć. Aby go wyłączyć, musimy zrestartować nasz mac w trybie odzyskiwania i stamtąd wyłączyć csrutil za pomocą terminala.

Teraz możemy z łatwością łatwo zmienić maksymalny limit otwierania pliku z samego terminala (nawet w normalnym trybie rozruchu).

Ta metoda została szczegółowo objaśniona w poniższym łączu. http://blog.dekstroza.io/ulimit-shenanigans-on-osx-el-capitan/

działa dla OSX-elcapitan i OSX-Seirra.

+0

OP pytał, jak to zrobić programowo, w C, a nie na poziomie użytkownika. –