2010-07-02 6 views
5

La limite par défaut pour les fichiers max ouverts sur Mac OS X est 256 (ulimit -n) et mon application nécessite environ 400 gestionnaires de fichiers.Comment augmenter la limite de "fichiers ouverts maximum" en C sous Mac OS X

J'ai essayé de changer la limite avec setrlimit() mais même si la fonction exécute correctement, je suis toujours limité à 256.

Voici le programme de test que j'utilise:

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

} 

et la sortie est:

before 256 -1 
after 10000 -1 
failed after 253 

Je ne peux pas demander aux personnes qui utilisent mon application de piquer dans un fichier/etc ou quelque chose. J'ai besoin de l'application pour le faire par lui-même.

+0

Pourquoi avez-vous besoin de tant de fichiers ouverts simultanément? – sbooth

+0

Cela ne devrait pas être important, mais êtes-vous en train de tester ceci sur l'édition du serveur ou sur l'édition desktop d'OSX? Je peux m'imaginer que les gens d'Apple ont décidé de limiter le nombre de fichiers qu'une application de bureau pourrait ouvrir car l'ouverture de beaucoup est généralement une tâche orientée serveur ... –

Répondre

5

Etresoft a trouvé la réponse sur le apple discussion board:

Le problème est ici votre fonction printf().Lorsque vous appelez printf(), vous initialisez structures de données internes à une certaine taille . Ensuite, vous appelez setrlimit() à essayez d'ajuster ces tailles. Cette fonction échoue car vous avez déjà utilisé structures internes avec votre printf(). Si vous utilisez deux structures rlimit (un pour avant et un pour après), et ne les imprimer qu'après l'appel setrlimit, vous constaterez que vous pouvez modifier les limites du processus actuelle, même dans une commande ligne programme. La valeur maximale est 10240.

0

Je sais que c'est une question stupide, mais vous avez vraiment besoin de 400 fichiers ouverts en même temps? Par ailleurs, utilisez-vous ce code en tant que root, êtes-vous?

+0

oui J'ai besoin de 400 fichiers ouverts en même temps et non je ne suis pas root. Comme le dit l'homme, puisque je ne change pas la limite maximum, mais seulement la limite de courbure, je n'ai pas besoin d'être root. – acemtp

+2

Mais la limite maximale ne serait-elle pas limitée? – nategoose

5

rlp.rlim_cur = 10000;

Deux choses.

1er. LOL. Apparemment, vous avez trouvé un bogue dans le stdio de Mac OS X. Si je corrige votre programme/ajouter une erreur de gestion/etc et remplace aussi fopen() par open() syscall, je peux facilement atteindre la limite de 10000 (qui est 240 fds en dessous de mon 10.6.3 'OPEN_MAX limite 10240)

2e. RTFM: man setrlimit. Le cas des fichiers ouverts max doit être traité spécifiquement en ce qui concerne OPEN_MAX.

+1

Merci pour la réponse. Etes-vous sérieux quand vous dites qu'il pourrait être un bug dans stdio sur Mac OS X ou c'est une blague? alors la seule solution est d'utiliser syscall au lieu de la fonction C standard? – acemtp

+0

@acemtp: limitation est probablement un meilleur mot. La norme nécessite seulement libc pour garantir que vous pouvez ouvrir 8 fichiers à la fois (y compris 'stdin' /' stdout'/'stderr'!). Ce serait une limitation inhabituelle, mais pas inouïe. –

+1

@acetemp, @evan: bien stdio sur Linux n'a aucun problème pour faire face à tout ce que je lui lance. et personnellement, je qualifierais cela comme un bug. 8 fichiers à la fois ?? stdio, stdin, stderr - 3 sont déjà occupés. Fichier journal de l'application + fichier de trace - ne laisse que 3 gratuits ... Silly et un bug, si vous me demandez. – Dummy00001

2

Cela peut être une limitation stricte de votre libc. Certaines versions de Solaris ont une limitation similaire car elles stockent le fd sous la forme unsigned char dans la structure FILE. Si c'est aussi le cas pour votre libc, vous ne pourrez peut-être pas faire ce que vous voulez. Pour autant que je sache, des choses comme setrlimit n'affectent que le nombre de fichiers que vous pouvez ouvrir avec open (fopen est presque certainement implémenté en termes de open). Donc, si cette limitation est au niveau de la librairie, vous aurez besoin d'une autre solution.

Bien sûr, vous pouvez toujours utiliser fopen et utiliser à la place l'appel système open disponible sur à peu près toutes les variantes d'unix.

L'inconvénient est que vous devez utiliser write et read au lieu de fwrite et fread, qui ne le font pas des choses comme tampon (qui est tout fait dans votre libc, et non par le système d'exploitation lui-même). Cela pourrait donc être un goulot d'étranglement au niveau des performances. Pouvez-vous décrire le scénario qui nécessite 400 fichiers ouverts ** simultanément **? Je ne dis pas qu'il n'y a aucun cas où cela est nécessaire. Mais, si vous décrivez plus clairement votre cas d'utilisation, nous pourrons peut-être vous recommander une meilleure solution.

+0

limite de libc: Oui. Voir mon commentaireChanger le programme pour utiliser open() au lieu de fopen() résout le problème. Sur Linux btw fonctionne comme un charme - après avoir fait la solution évidente de remplacer le 10000 par rlp.rlim_max (mais sur Mac OS X même si c'est différent car le cap de OPEN_MAX doit aussi être vérifié). Scénario où vous avez besoin de 400 fds ... Je maintiens un serveur de réseaux spécialisé qui sauvegarde également les données sur disque. Voir des sockets 2K et ouvrir des fichiers en cours d'utilisation n'est pas rare. – Dummy00001

+0

@ Dummy00001: ok, c'est certainement un ** scénario **, mais avoir exactement ce qu'il essaie de faire peut encore aider :-P. Mais il semble que nous ayons trouvé la nature du problème. –

+0

merci de clarifier l'origine. – Dummy00001

2

Pour une raison quelconque (compatibilité peut-être binaire), vous devez définir _DARWIN_UNLIMITED_STREAMS avant d'inclure <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; } 
    } 

} 

impressions

before 256 -1 
after 10000 -1 
failed after 9997 

Cette fonction semble avoir été introduit dans Mac OS X 10.6.

-1

Mac OS ne nous permet pas de modifier facilement la limite comme dans beaucoup de systèmes d'exploitation basés sur Unix. Nous devons créer deux fichiers

/Library/LaunchDaemons/limit.maxfiles.plist /Library/LaunchDaemons/limit.maxproc.plist décrivant la limite de fichier proc max et max. La propriété du fichier doit être changé en 'root: wheel'

Cela ne résout pas le problème, par défaut la dernière version de mac OSX utilise 'csrutil', nous devons le désactiver. Pour le désactiver, nous devons redémarrer notre mac en mode de récupération et à partir de là désactiver csrutil en utilisant le terminal.

Maintenant, nous pouvons facilement changer la limite de la poignée de fichier ouverte maximale facilement à partir du terminal lui-même (même en mode de démarrage normal).

Cette méthode est expliquée en détail dans le lien suivant. http://blog.dekstroza.io/ulimit-shenanigans-on-osx-el-capitan/

fonctionne pour OSX-elcapitan et OSX-Seirra.

+0

OP demandait comment faire cela par programme, en C, pas au niveau de l'utilisateur. –