]>
Commit | Line | Data |
---|---|---|
a50341be | 1 | // -*- C++ -*- |
4f67a81c | 2 | |
a50341be | 3 | // Utility subroutines for the C++ library testsuite. |
acba97b8 | 4 | // |
f1717362 | 5 | // Copyright (C) 2002-2016 Free Software Foundation, Inc. |
acba97b8 | 6 | // |
7 | // This file is part of the GNU ISO C++ Library. This library is free | |
8 | // software; you can redistribute it and/or modify it under the | |
9 | // terms of the GNU General Public License as published by the | |
6bc9506f | 10 | // Free Software Foundation; either version 3, or (at your option) |
acba97b8 | 11 | // any later version. |
12 | // | |
13 | // This library is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | // | |
18 | // You should have received a copy of the GNU General Public License along | |
6bc9506f | 19 | // with this library; see the file COPYING3. If not see |
20 | // <http://www.gnu.org/licenses/>. | |
acba97b8 | 21 | // |
acba97b8 | 22 | |
23 | #include <testsuite_hooks.h> | |
24 | ||
ac7a2146 | 25 | #ifdef _GLIBCXX_RES_LIMITS |
acba97b8 | 26 | #include <unistd.h> |
cc757d9d | 27 | #include <sys/time.h> |
28 | #include <sys/resource.h> | |
a50341be | 29 | #endif |
4a5f206f | 30 | |
a50341be | 31 | #include <list> |
32 | #include <string> | |
33 | #include <stdexcept> | |
34 | #include <clocale> | |
6f020cc1 | 35 | #include <cstdlib> |
a50341be | 36 | #include <locale> |
15bfe2ae | 37 | #include <cxxabi.h> |
acba97b8 | 38 | |
007b777a | 39 | // If we have <sys/types.h>, <sys/ipc.h>, and <sys/sem.h>, then assume |
40 | // that System V semaphores are available. | |
41 | #if defined(_GLIBCXX_HAVE_SYS_TYPES_H) \ | |
42 | && defined(_GLIBCXX_HAVE_SYS_IPC_H) \ | |
43 | && defined(_GLIBCXX_HAVE_SYS_SEM_H) | |
44 | #define _GLIBCXX_SYSV_SEM | |
45 | #endif | |
46 | ||
47 | #ifdef _GLIBCXX_SYSV_SEM | |
48 | #include <sys/types.h> | |
49 | #include <sys/ipc.h> | |
50 | #include <sys/sem.h> | |
51 | #endif | |
52 | ||
56dcf3cc | 53 | namespace __gnu_test |
acba97b8 | 54 | { |
ac7a2146 | 55 | #ifdef _GLIBCXX_RES_LIMITS |
a50341be | 56 | void |
57 | set_memory_limits(float size) | |
58 | { | |
acba97b8 | 59 | struct rlimit r; |
e973eec4 | 60 | // Cater to the absence of rlim_t. |
a50341be | 61 | __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur))(size * 1048576); |
acba97b8 | 62 | |
63 | // Heap size, seems to be common. | |
ac7a2146 | 64 | #if _GLIBCXX_HAVE_LIMIT_DATA |
acba97b8 | 65 | getrlimit(RLIMIT_DATA, &r); |
66 | r.rlim_cur = limit; | |
67 | setrlimit(RLIMIT_DATA, &r); | |
68 | #endif | |
69 | ||
70 | // Resident set size. | |
ac7a2146 | 71 | #if _GLIBCXX_HAVE_LIMIT_RSS |
acba97b8 | 72 | getrlimit(RLIMIT_RSS, &r); |
73 | r.rlim_cur = limit; | |
74 | setrlimit(RLIMIT_RSS, &r); | |
75 | #endif | |
76 | ||
77 | // Mapped memory (brk + mmap). | |
ac7a2146 | 78 | #if _GLIBCXX_HAVE_LIMIT_VMEM |
acba97b8 | 79 | getrlimit(RLIMIT_VMEM, &r); |
80 | r.rlim_cur = limit; | |
81 | setrlimit(RLIMIT_VMEM, &r); | |
82 | #endif | |
83 | ||
46284b1c | 84 | // Virtual memory. On x86_64-linux, the default is -z |
85 | // max-page-size=0x200000 which means up to 2MB of address space | |
86 | // are accounted for PROT_NONE mappings between text and data | |
87 | // segments of each shared library. There are 4 shared libs | |
88 | // involved in addition to the dynamic linker, maybe 5 if libgomp | |
89 | // is being used as well. Use at least 20MB address space limit. | |
0f40b49c | 90 | #if defined(__x86_64__) && defined(__linux__) |
46284b1c | 91 | if (limit < 20971520) |
92 | limit = 20971520; | |
0f40b49c | 93 | #endif |
46284b1c | 94 | |
667bb867 | 95 | // On HP-UX 11.23, a trivial C++ program that sets RLIMIT_AS to |
96 | // anything less than 128MB cannot "malloc" even 1K of memory. | |
97 | // Therefore, we skip RLIMIT_AS on HP-UX. | |
ac7a2146 | 98 | #if _GLIBCXX_HAVE_LIMIT_AS && !defined(__hpux__) |
acba97b8 | 99 | getrlimit(RLIMIT_AS, &r); |
100 | r.rlim_cur = limit; | |
101 | setrlimit(RLIMIT_AS, &r); | |
102 | #endif | |
a50341be | 103 | } |
104 | ||
776d5901 | 105 | #else |
a50341be | 106 | void |
107 | set_memory_limits(float) { } | |
108 | #endif | |
109 | ||
ac7a2146 | 110 | #ifdef _GLIBCXX_RES_LIMITS |
111 | void | |
112 | set_file_limit(unsigned long size) | |
113 | { | |
114 | #if _GLIBCXX_HAVE_LIMIT_FSIZE | |
115 | struct rlimit r; | |
116 | // Cater to the absence of rlim_t. | |
117 | __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur))(size); | |
118 | ||
119 | getrlimit(RLIMIT_FSIZE, &r); | |
120 | r.rlim_cur = limit; | |
121 | setrlimit(RLIMIT_FSIZE, &r); | |
122 | #endif | |
123 | } | |
124 | ||
125 | #else | |
126 | void | |
127 | set_file_limit(unsigned long) { } | |
128 | #endif | |
15bfe2ae | 129 | |
130 | void | |
131 | verify_demangle(const char* mangled, const char* wanted) | |
132 | { | |
133 | int status = 0; | |
134 | const char* s = abi::__cxa_demangle(mangled, 0, 0, &status); | |
135 | if (!s) | |
136 | { | |
137 | switch (status) | |
138 | { | |
139 | case 0: | |
140 | s = "error code = 0: success"; | |
141 | break; | |
142 | case -1: | |
143 | s = "error code = -1: memory allocation failure"; | |
144 | break; | |
145 | case -2: | |
146 | s = "error code = -2: invalid mangled name"; | |
147 | break; | |
148 | case -3: | |
149 | s = "error code = -3: invalid arguments"; | |
150 | break; | |
151 | default: | |
152 | s = "error code unknown - who knows what happened"; | |
153 | } | |
154 | } | |
155 | ||
156 | std::string w(wanted); | |
157 | if (w != s) | |
dfafcdbf | 158 | std::__throw_runtime_error(s); |
15bfe2ae | 159 | } |
160 | ||
a50341be | 161 | void |
162 | run_tests_wrapped_locale(const char* name, const func_callback& l) | |
163 | { | |
164 | using namespace std; | |
a50341be | 165 | |
166 | // Set the global locale. | |
e590fca1 | 167 | locale loc_name = locale(name); |
3eb7dfb2 | 168 | locale orig = locale::global(loc_name); |
acfd087d | 169 | |
a50341be | 170 | const char* res = setlocale(LC_ALL, name); |
e4bb1925 | 171 | if (res) |
a50341be | 172 | { |
173 | string preLC_ALL = res; | |
7372455c | 174 | const func_callback::test_type* tests = l.tests(); |
175 | for (int i = 0; i < l.size(); ++i) | |
176 | (*tests[i])(); | |
9c371452 | 177 | string postLC_ALL= setlocale(LC_ALL, 0); |
a50341be | 178 | VERIFY( preLC_ALL == postLC_ALL ); |
179 | } | |
180 | else | |
dfafcdbf | 181 | { |
182 | string s("LC_ALL for "); | |
183 | s += name; | |
184 | __throw_runtime_error(s.c_str()); | |
185 | } | |
a50341be | 186 | } |
187 | ||
188 | void | |
189 | run_tests_wrapped_env(const char* name, const char* env, | |
190 | const func_callback& l) | |
191 | { | |
192 | using namespace std; | |
a50341be | 193 | |
5a64d8cf | 194 | #ifdef _GLIBCXX_HAVE_SETENV |
a50341be | 195 | // Set the global locale. |
e590fca1 | 196 | locale loc_name = locale(name); |
3eb7dfb2 | 197 | locale orig = locale::global(loc_name); |
198 | ||
a50341be | 199 | // Set environment variable env to value in name. |
200 | const char* oldENV = getenv(env); | |
201 | if (!setenv(env, name, 1)) | |
202 | { | |
7372455c | 203 | const func_callback::test_type* tests = l.tests(); |
204 | for (int i = 0; i < l.size(); ++i) | |
205 | (*tests[i])(); | |
a50341be | 206 | setenv(env, oldENV ? oldENV : "", 1); |
207 | } | |
208 | else | |
dfafcdbf | 209 | { |
210 | string s(env); | |
211 | s += string(" to "); | |
212 | s += string(name); | |
213 | __throw_runtime_error(s.c_str()); | |
214 | } | |
a50341be | 215 | #endif |
216 | } | |
acba97b8 | 217 | |
b65cbad5 | 218 | object_counter::size_type object_counter::count = 0; |
a50341be | 219 | unsigned int copy_constructor::count_ = 0; |
220 | unsigned int copy_constructor::throw_on_ = 0; | |
221 | unsigned int assignment_operator::count_ = 0; | |
222 | unsigned int assignment_operator::throw_on_ = 0; | |
223 | unsigned int destructor::_M_count = 0; | |
224 | int copy_tracker::next_id_ = 0; | |
007b777a | 225 | |
226 | #ifdef _GLIBCXX_SYSV_SEM | |
227 | // This union is not declared in system headers. Instead, it must | |
228 | // be defined by user programs. | |
229 | union semun | |
230 | { | |
231 | int val; | |
232 | struct semid_ds *buf; | |
233 | unsigned short *array; | |
234 | }; | |
235 | #endif | |
236 | ||
dfafcdbf | 237 | semaphore::semaphore() |
238 | { | |
007b777a | 239 | #ifdef _GLIBCXX_SYSV_SEM |
7b96e840 | 240 | // Remember the PID for the process that created the semaphore set |
007b777a | 241 | // so that only one process will destroy the set. |
242 | pid_ = getpid(); | |
243 | ||
244 | // GLIBC does not define SEM_R and SEM_A. | |
245 | #ifndef SEM_R | |
246 | #define SEM_R 0400 | |
247 | #endif | |
248 | ||
249 | #ifndef SEM_A | |
250 | #define SEM_A 0200 | |
251 | #endif | |
252 | ||
253 | // Get a semaphore set with one semaphore. | |
e1efcac2 | 254 | sem_set_ = semget(IPC_PRIVATE, 1, SEM_R | SEM_A); |
007b777a | 255 | if (sem_set_ == -1) |
dfafcdbf | 256 | std::__throw_runtime_error("could not obtain semaphore set"); |
007b777a | 257 | |
258 | // Initialize the semaphore. | |
259 | union semun val; | |
260 | val.val = 0; | |
e1efcac2 | 261 | if (semctl(sem_set_, 0, SETVAL, val) == -1) |
dfafcdbf | 262 | std::__throw_runtime_error("could not initialize semaphore"); |
007b777a | 263 | #else |
264 | // There are no semaphores on this system. We have no way to mark | |
265 | // a test as "unsupported" at runtime, so we just exit, pretending | |
266 | // that the test passed. | |
e1efcac2 | 267 | exit(0); |
007b777a | 268 | #endif |
269 | } | |
270 | ||
dfafcdbf | 271 | semaphore::~semaphore() |
272 | { | |
007b777a | 273 | #ifdef _GLIBCXX_SYSV_SEM |
274 | union semun val; | |
263d7294 | 275 | val.val = 0; // Avoid uninitialized variable warning. |
007b777a | 276 | // Destroy the semaphore set only in the process that created it. |
e1efcac2 | 277 | if (pid_ == getpid()) |
278 | semctl(sem_set_, 0, IPC_RMID, val); | |
007b777a | 279 | #endif |
280 | } | |
281 | ||
282 | void | |
dfafcdbf | 283 | semaphore::signal() |
284 | { | |
007b777a | 285 | #ifdef _GLIBCXX_SYSV_SEM |
dfafcdbf | 286 | struct sembuf op[1] = |
287 | { | |
288 | { 0, 1, 0 } | |
289 | }; | |
e1efcac2 | 290 | if (semop(sem_set_, op, 1) == -1) |
dfafcdbf | 291 | std::__throw_runtime_error("could not signal semaphore"); |
007b777a | 292 | #endif |
293 | } | |
294 | ||
295 | void | |
dfafcdbf | 296 | semaphore::wait() |
297 | { | |
007b777a | 298 | #ifdef _GLIBCXX_SYSV_SEM |
dfafcdbf | 299 | struct sembuf op[1] = |
300 | { | |
301 | { 0, -1, SEM_UNDO } | |
302 | }; | |
e1efcac2 | 303 | if (semop(sem_set_, op, 1) == -1) |
dfafcdbf | 304 | std::__throw_runtime_error("could not wait for semaphore"); |
007b777a | 305 | #endif |
306 | } | |
18ea8583 | 307 | |
308 | // For use in 22_locale/time_get and time_put. | |
40180232 | 309 | std::tm |
ac1a1ad8 | 310 | test_tm(int sec, int min, int hour, int mday, int mon, |
311 | int year, int wday, int yday, int isdst) | |
18ea8583 | 312 | { |
40180232 | 313 | static std::tm tmp; |
ac1a1ad8 | 314 | tmp.tm_sec = sec; |
315 | tmp.tm_min = min; | |
316 | tmp.tm_hour = hour; | |
317 | tmp.tm_mday = mday; | |
318 | tmp.tm_mon = mon; | |
319 | tmp.tm_year = year; | |
320 | tmp.tm_wday = wday; | |
321 | tmp.tm_yday = yday; | |
322 | tmp.tm_isdst = isdst; | |
18ea8583 | 323 | return tmp; |
324 | } | |
e6581036 | 325 | } // namespace __gnu_test |