Reputation: 2218
Following this SO question and this answer in particular, it seems that calling setrlimit after a printf make it not working.
Here is the example code:
#include <stdio.h>
#include <sys/resource.h>
int main()
{
struct rlimit rlp;
FILE *fp[10000];
int i;
printf("Hello\n");
rlp.rlim_cur = 10000;
rlp.rlim_max = RLIM_INFINITY;
setrlimit(RLIMIT_NOFILE, &rlp);
getrlimit(RLIMIT_NOFILE, &rlp);
printf("limit %lld %lld\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; }
}
}
Here is the console output:
Hello
limit 10000 9223372036854775807
failed after 4861
If I comment the first printf
, here is the console output:
limit 10000 9223372036854775807
failed after 9967
Is there any reason for that?
[Edit] I am running MAc OS X 10.7.5 with Xcode 4.6.2.
Upvotes: 0
Views: 942
Reputation: 20402
Here's a better version of the program that demonstrates more facets of the problem.
#include <stdio.h>
#include <sys/resource.h>
#include <err.h>
#include <fcntl.h>
int
main(int argc, char **argv)
{
struct rlimit rl;
int i;
rl.rlim_cur = 10;
rl.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_NOFILE, &rl))
err(1, "setrlimit");
printf("Hello\n");
rl.rlim_cur = 100;
rl.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_NOFILE, &rl))
err(1, "setrlimit");
if (getrlimit(RLIMIT_NOFILE, &rl))
err(1, "getrlimit");
printf("limit %lld\n", rl.rlim_cur);
for(i = 0; i < 10000; i++) {
FILE *fp;
#if 1
if ((fp = fopen("foo", "r")) == NULL) {
err(1, "failed after %d", i);
}
#else
if (open("foo", O_RDONLY) == -1) {
err(1, "failed after %d", i);
}
#endif
}
return 0;
}
If you run this program with the "#if 1" changed to "#if 0" it works as expected. It looks like MacOS reads limits for open files once during initialization of stdio in libc and doesn't read them again later. Your first call to printf initializes stdio in libc and that caches whatever the rlimit value was for number of open files.
Running dtruss on a trivial "hello, world" shows:
$ cat > hw.c
#include <stdio.h>
int main() { printf("hello, world\n"); return 0; }
$ cc -Wall -o hw hw.c && sudo dtruss ./hw 2>&1 | grep rlimit
getrlimit(0x1008, 0x7FFF58875AE8, 0x7FFF8BE92470) = 0 0
$
Which shows that this is in fact what happens.
This is something that you should take up with Apple though, it smells like a bug.
Upvotes: 1