]>
Commit | Line | Data |
---|---|---|
974e3884 A |
1 | #include <stdio.h> |
2 | #include <err.h> | |
3 | #include <errno.h> | |
4 | #include <unistd.h> | |
5 | #include <sys/resource.h> | |
a9aaacca A |
6 | #include <stdlib.h> |
7 | #include <sys/sysctl.h> | |
974e3884 A |
8 | |
9 | #include <darwintest.h> | |
10 | ||
11 | #define FILE_LIMIT 100 | |
12 | ||
a9aaacca A |
13 | /* |
14 | * Validate: | |
15 | * (1) the maximum number of fds allowed open per process | |
16 | * implemented by the kernel matches what sysconf expects: | |
17 | * 32 bit: OPEN_MAX | |
18 | * 64 bit: RLIM_INFINITY | |
19 | * (2) fopen does not fail when NOFILE is unlimited. | |
20 | */ | |
21 | T_DECL(stdio_PR_63187147_SC_STREAM_MAX, "_SC_STREAM_MAX test") | |
22 | { | |
23 | struct rlimit rlim; | |
24 | long stream_max, saved_stream_max, open_count, i; | |
25 | int maxfilesperproc, err; | |
26 | size_t maxfilesperproc_size = sizeof(maxfilesperproc); | |
27 | FILE **fp = NULL; | |
28 | const char *filename = "fopen_test"; | |
29 | ||
30 | T_SETUPBEGIN; | |
31 | ||
32 | saved_stream_max = sysconf(_SC_STREAM_MAX); | |
33 | T_LOG("Initial stream_max %ld", saved_stream_max); | |
34 | ||
35 | /* Decide the maximum number of fds allowed by the kernel */ | |
36 | err = sysctlbyname("kern.maxfilesperproc", &maxfilesperproc, &maxfilesperproc_size, NULL, 0); | |
37 | T_EXPECT_POSIX_SUCCESS(err, "sysctlbyname(\"kern.maxfilesperproc\") returned %d", err); | |
38 | T_LOG("kern.maxfilesperproc %d", maxfilesperproc); | |
39 | ||
40 | /* | |
41 | * Raise RLIMIT_NOFILE to RLIM_INFINITY, note that this does NOT update | |
42 | * __stream_max in findfp.c | |
43 | */ | |
44 | err = getrlimit(RLIMIT_NOFILE, &rlim); | |
45 | T_EXPECT_POSIX_SUCCESS(err, "getrlimit(RLIMIT_NOFILE)"); | |
46 | T_LOG("Initial RLIMIT_NOFILE rlim.cur: 0x%llx", rlim.rlim_cur); | |
47 | rlim.rlim_cur = RLIM_INFINITY; | |
48 | err = setrlimit(RLIMIT_NOFILE, &rlim); | |
49 | T_EXPECT_POSIX_SUCCESS(err, "setrlimit(RLIMIT_NOFILE) to RLIM_INFINITY"); | |
50 | err = getrlimit(RLIMIT_NOFILE, &rlim); | |
51 | T_EXPECT_POSIX_SUCCESS(err, "New RLIMIT_NOFILE rlim_cur: 0x%llx", rlim.rlim_cur); | |
52 | ||
53 | T_SETUPEND; | |
54 | ||
55 | /* | |
56 | * Test 1 (sysconf with _SC_STREAM_MAX): the largest value sysconf | |
57 | * returns for _SC_STREAM_MAX is OPEN_MAX (32 bit) or | |
58 | * RLIM_INFINITY (64 bit) | |
59 | */ | |
60 | stream_max = sysconf(_SC_STREAM_MAX); | |
61 | T_EXPECT_NE_LONG((long)-1, stream_max, "stream_max %ld", stream_max); | |
62 | #if __LP64__ | |
63 | T_EXPECT_EQ((long)RLIM_INFINITY, stream_max, "sysconf returned 0x%lx", stream_max); | |
64 | #else | |
65 | T_EXPECT_EQ((long)OPEN_MAX, stream_max, "sysconf returned 0x%lx", stream_max); | |
66 | #endif | |
67 | ||
68 | /* | |
69 | * Test 2 (__stream_max in findfp.c): exercise __sfp by calling fopen | |
70 | * saved_stream_max + 1 times. Note that we call fopen() up to | |
71 | * maxfilesperproc times in case fopen() goes nuts. | |
72 | */ | |
73 | fp = malloc(sizeof(FILE *) * (size_t)maxfilesperproc); | |
74 | T_EXPECT_NOTNULL(fp, "Allocated %d FILE pointers", maxfilesperproc); | |
75 | for (i = 0; i < saved_stream_max + 1 && i < maxfilesperproc; i++) { | |
76 | if (i == saved_stream_max) { | |
77 | T_LOG("The very next fopen should trigger __sfp to update __stream_max and fopen shouldn't fail "); | |
78 | } | |
79 | fp[i] = fopen(filename, "r"); | |
80 | T_QUIET; T_EXPECT_NOTNULL(fp, "%ld: fopen(%s, \"r\")", i, filename); | |
81 | } | |
82 | open_count = i; | |
83 | ||
84 | for (i = 0; i < open_count; i++) { | |
85 | fclose(fp[i]); | |
86 | } | |
87 | free(fp); | |
88 | ||
89 | T_LOG("saved_stream_max %ld stream_max %ld fopen %ld files", saved_stream_max, stream_max, open_count); | |
90 | } | |
91 | ||
b061a43b | 92 | T_DECL(stdio_PR_22813396, "STREAM_MAX is affected by changes to RLIMIT_NOFILE") |
974e3884 A |
93 | { |
94 | struct rlimit theLimit; | |
95 | getrlimit( RLIMIT_NOFILE, &theLimit ); | |
96 | theLimit.rlim_cur = FILE_LIMIT; | |
97 | setrlimit( RLIMIT_NOFILE, &theLimit ); | |
98 | ||
99 | long stream_max = sysconf(_SC_STREAM_MAX); | |
100 | T_EXPECT_EQ_LONG(stream_max, (long)FILE_LIMIT, "stream_max = FILE_LIMIT"); | |
101 | ||
102 | FILE *f; | |
103 | for(int i = 3; i < stream_max; i++) { | |
104 | if((f = fdopen(0, "r")) == NULL) { | |
105 | T_FAIL("Failed after %d streams", i); | |
106 | } | |
107 | } | |
108 | ||
109 | f = fdopen(0, "r"); | |
110 | T_EXPECT_NULL(f, "fdopen fail after stream_max streams"); | |
111 | ||
112 | theLimit.rlim_cur = FILE_LIMIT + 1; | |
113 | setrlimit( RLIMIT_NOFILE, &theLimit ); | |
114 | ||
115 | f = fdopen(0, "r"); | |
116 | T_EXPECT_NOTNULL(f, "fdopen succeed after RLIMIT_NOFILE increased"); | |
117 | } | |
b061a43b A |
118 | |
119 | T_DECL(stdio_PR_22813396_close, "STREAM_MAX is enforced properly after fclose") | |
120 | { | |
121 | struct rlimit theLimit; | |
122 | getrlimit( RLIMIT_NOFILE, &theLimit ); | |
123 | theLimit.rlim_cur = FILE_LIMIT; | |
124 | setrlimit( RLIMIT_NOFILE, &theLimit ); | |
125 | ||
126 | long stream_max = sysconf(_SC_STREAM_MAX); | |
127 | T_EXPECT_EQ_LONG(stream_max, (long)FILE_LIMIT, "stream_max = FILE_LIMIT"); | |
128 | ||
129 | FILE *f; | |
130 | for(int i = 3; i < stream_max - 1; i++) { | |
131 | if((f = fdopen(0, "r")) == NULL) { | |
132 | T_FAIL("Failed after %d streams", i); | |
133 | } | |
134 | } | |
135 | ||
136 | // the last stream is for dup(0), it needs to be fclose'd | |
137 | FILE *dupf = NULL; | |
138 | T_EXPECT_NOTNULL(dupf = fdopen(dup(0), "r"), NULL); | |
139 | ||
140 | T_EXPECT_NULL(f = fdopen(0, "r"), "fdopen fail after stream_max streams"); | |
141 | ||
142 | T_EXPECT_POSIX_ZERO(fclose(dupf), "fclose succeeds"); | |
143 | ||
144 | f = fdopen(0, "r"); | |
145 | T_WITH_ERRNO; T_EXPECT_NOTNULL(f, "fdopen succeed after fclose"); | |
146 | } | |
147 |