VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTSemRW.cpp@ 102335

Last change on this file since 102335 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 21.1 KB
Line 
1/* $Id: tstRTSemRW.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT Testcase - Reader/Writer Semaphore.
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/semaphore.h>
42
43#include <iprt/asm.h>
44#include <iprt/assert.h>
45#include <iprt/err.h>
46#include <iprt/initterm.h>
47#include <iprt/lockvalidator.h>
48#include <iprt/mp.h>
49#include <iprt/rand.h>
50#include <iprt/string.h>
51#include <iprt/stream.h>
52#include <iprt/test.h>
53#include <iprt/time.h>
54#include <iprt/thread.h>
55
56
57/*********************************************************************************************************************************
58* Global Variables *
59*********************************************************************************************************************************/
60static RTTEST g_hTest;
61static RTSEMRW g_hSemRW = NIL_RTSEMRW;
62static bool volatile g_fTerminate;
63static bool g_fYield;
64static bool g_fQuiet;
65static unsigned g_uWritePercent;
66static uint32_t volatile g_cConcurrentWriters;
67static uint32_t volatile g_cConcurrentReaders;
68
69
70static DECLCALLBACK(int) Test4Thread(RTTHREAD ThreadSelf, void *pvUser)
71{
72 /* Use randomization to get a little more variation of the sync pattern.
73 We use a pseudo random generator here so that we don't end up testing
74 the speed of the /dev/urandom implementation, but rather the read-write
75 semaphores. */
76 int rc;
77 RTRAND hRand;
78 RTTEST_CHECK_RC_OK_RET(g_hTest, rc = RTRandAdvCreateParkMiller(&hRand), rc);
79 RTTEST_CHECK_RC_OK_RET(g_hTest, rc = RTRandAdvSeed(hRand, (uintptr_t)ThreadSelf), rc);
80 unsigned c100 = RTRandAdvU32Ex(hRand, 0, 99);
81
82 uint64_t *pcItr = (uint64_t *)pvUser;
83 bool fWrite;
84 for (;;)
85 {
86 unsigned readrec = RTRandAdvU32Ex(hRand, 0, 3);
87 unsigned writerec = RTRandAdvU32Ex(hRand, 0, 3);
88 /* Don't overdo recursion testing. */
89 if (readrec > 1)
90 readrec--;
91 if (writerec > 1)
92 writerec--;
93
94 fWrite = (c100 < g_uWritePercent);
95 if (fWrite)
96 {
97 for (unsigned i = 0; i <= writerec; i++)
98 {
99 rc = RTSemRWRequestWriteNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
100 if (RT_FAILURE(rc))
101 {
102 RTTestFailed(g_hTest, "Write recursion %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
103 break;
104 }
105 }
106 if (RT_FAILURE(rc))
107 break;
108 if (ASMAtomicIncU32(&g_cConcurrentWriters) != 1)
109 {
110 RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s after write locking it",
111 g_cConcurrentWriters, RTThreadSelfName());
112 break;
113 }
114 if (g_cConcurrentReaders != 0)
115 {
116 RTTestFailed(g_hTest, "g_cConcurrentReaders=%u on %s after write locking it",
117 g_cConcurrentReaders, RTThreadSelfName());
118 break;
119 }
120 }
121 else
122 {
123 rc = RTSemRWRequestReadNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
124 if (RT_FAILURE(rc))
125 {
126 RTTestFailed(g_hTest, "Read locking on %s failed with rc=%Rrc", RTThreadSelfName(), rc);
127 break;
128 }
129 ASMAtomicIncU32(&g_cConcurrentReaders);
130 if (g_cConcurrentWriters != 0)
131 {
132 RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s after read locking it",
133 g_cConcurrentWriters, RTThreadSelfName());
134 break;
135 }
136 }
137 for (unsigned i = 0; i < readrec; i++)
138 {
139 rc = RTSemRWRequestReadNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
140 if (RT_FAILURE(rc))
141 {
142 RTTestFailed(g_hTest, "Read recursion %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
143 break;
144 }
145 }
146 if (RT_FAILURE(rc))
147 break;
148
149 /*
150 * Check for fairness: The values of the threads should not differ too much
151 */
152 (*pcItr)++;
153
154 /*
155 * Check for correctness: Give other threads a chance. If the implementation is
156 * correct, no other thread will be able to enter this lock now.
157 */
158 if (g_fYield)
159 RTThreadYield();
160
161 for (unsigned i = 0; i < readrec; i++)
162 {
163 rc = RTSemRWReleaseRead(g_hSemRW);
164 if (RT_FAILURE(rc))
165 {
166 RTTestFailed(g_hTest, "Read release %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
167 break;
168 }
169 }
170 if (RT_FAILURE(rc))
171 break;
172
173 if (fWrite)
174 {
175 if (ASMAtomicDecU32(&g_cConcurrentWriters) != 0)
176 {
177 RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s before write release",
178 g_cConcurrentWriters, RTThreadSelfName());
179 break;
180 }
181 if (g_cConcurrentReaders != 0)
182 {
183 RTTestFailed(g_hTest, "g_cConcurrentReaders=%u on %s before write release",
184 g_cConcurrentReaders, RTThreadSelfName());
185 break;
186 }
187 for (unsigned i = 0; i <= writerec; i++)
188 {
189 rc = RTSemRWReleaseWrite(g_hSemRW);
190 if (RT_FAILURE(rc))
191 {
192 RTTestFailed(g_hTest, "Write release %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
193 break;
194 }
195 }
196 }
197 else
198 {
199 if (g_cConcurrentWriters != 0)
200 {
201 RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s before read release",
202 g_cConcurrentWriters, RTThreadSelfName());
203 break;
204 }
205 ASMAtomicDecU32(&g_cConcurrentReaders);
206 rc = RTSemRWReleaseRead(g_hSemRW);
207 if (RT_FAILURE(rc))
208 {
209 RTTestFailed(g_hTest, "Read release on %s failed with rc=%Rrc", RTThreadSelfName(), rc);
210 break;
211 }
212 }
213
214 if (g_fTerminate)
215 break;
216
217 c100++;
218 c100 %= 100;
219 }
220 if (!g_fQuiet)
221 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Thread %s exited with %lld\n", RTThreadSelfName(), *pcItr);
222 RTRandAdvDestroy(hRand);
223 return VINF_SUCCESS;
224}
225
226
227static void Test4(unsigned cThreads, unsigned cSeconds, unsigned uWritePercent, bool fYield, bool fQuiet)
228{
229 unsigned i;
230 uint64_t acIterations[32];
231 RTTHREAD aThreads[RT_ELEMENTS(acIterations)];
232 AssertRelease(cThreads <= RT_ELEMENTS(acIterations));
233
234 RTTestSubF(g_hTest, "Test4 - %u threads, %u sec, %u%% writes, %syielding",
235 cThreads, cSeconds, uWritePercent, fYield ? "" : "non-");
236
237 /*
238 * Init globals.
239 */
240 g_fYield = fYield;
241 g_fQuiet = fQuiet;
242 g_fTerminate = false;
243 g_uWritePercent = uWritePercent;
244 g_cConcurrentWriters = 0;
245 g_cConcurrentReaders = 0;
246
247 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&g_hSemRW), VINF_SUCCESS);
248
249 /*
250 * Create the threads and let them block on the semrw.
251 */
252 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWRequestWrite(g_hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS);
253
254 for (i = 0; i < cThreads; i++)
255 {
256 acIterations[i] = 0;
257 RTTEST_CHECK_RC_RETV(g_hTest, RTThreadCreateF(&aThreads[i], Test4Thread, &acIterations[i], 0,
258 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
259 "test-%u", i), VINF_SUCCESS);
260 }
261
262 /*
263 * Do the test run.
264 */
265 uint32_t cErrorsBefore = RTTestErrorCount(g_hTest);
266 uint64_t u64StartTS = RTTimeNanoTS();
267 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_hSemRW), VINF_SUCCESS);
268 RTThreadSleep(cSeconds * 1000);
269 ASMAtomicWriteBool(&g_fTerminate, true);
270 uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS;
271
272 /*
273 * Clean up the threads and semaphore.
274 */
275 for (i = 0; i < cThreads; i++)
276 RTTEST_CHECK_RC(g_hTest, RTThreadWait(aThreads[i], 5000, NULL), VINF_SUCCESS);
277
278 RTTEST_CHECK_MSG(g_hTest, g_cConcurrentWriters == 0, (g_hTest, "g_cConcurrentWriters=%u at end of test\n", g_cConcurrentWriters));
279 RTTEST_CHECK_MSG(g_hTest, g_cConcurrentReaders == 0, (g_hTest, "g_cConcurrentReaders=%u at end of test\n", g_cConcurrentReaders));
280
281 RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(g_hSemRW), VINF_SUCCESS);
282 g_hSemRW = NIL_RTSEMRW;
283
284 if (RTTestErrorCount(g_hTest) != cErrorsBefore)
285 RTThreadSleep(100);
286
287 /*
288 * Collect and display the results.
289 */
290 uint64_t cItrTotal = acIterations[0];
291 for (i = 1; i < cThreads; i++)
292 cItrTotal += acIterations[i];
293
294 uint64_t cItrNormal = cItrTotal / cThreads;
295 uint64_t cItrMinOK = cItrNormal / 20; /* 5% */
296 uint64_t cItrMaxDeviation = 0;
297 for (i = 0; i < cThreads; i++)
298 {
299 uint64_t cItrDelta = RT_ABS((int64_t)(acIterations[i] - cItrNormal));
300 if (acIterations[i] < cItrMinOK)
301 RTTestFailed(g_hTest, "Thread %u did less than 5%% of the iterations - %llu (it) vs. %llu (5%%) - %llu%%\n",
302 i, acIterations[i], cItrMinOK, cItrDelta * 100 / cItrNormal);
303 else if (cItrDelta > cItrNormal / 2)
304 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
305 "Warning! Thread %u deviates by more than 50%% - %llu (it) vs. %llu (avg) - %llu%%\n",
306 i, acIterations[i], cItrNormal, cItrDelta * 100 / cItrNormal);
307 if (cItrDelta > cItrMaxDeviation)
308 cItrMaxDeviation = cItrDelta;
309
310 }
311
312 //RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
313 // "Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n",
314 // cThreads,
315 // cItrTotal,
316 // cItrTotal / cSeconds,
317 // ElapsedNS / cItrTotal,
318 // cItrMaxDeviation * 100 / cItrNormal
319 // );
320 //
321 RTTestValue(g_hTest, "Thruput", cItrTotal * UINT32_C(1000000000) / ElapsedNS, RTTESTUNIT_CALLS_PER_SEC);
322 RTTestValue(g_hTest, "Max diviation", cItrMaxDeviation * 100 / cItrNormal, RTTESTUNIT_PCT);
323}
324
325
326static DECLCALLBACK(int) Test2Thread(RTTHREAD hThreadSelf, void *pvUser)
327{
328 RTSEMRW hSemRW = (RTSEMRW)pvUser;
329 RT_NOREF_PV(hThreadSelf);
330
331 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead(hSemRW, 0), VERR_TIMEOUT);
332 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hSemRW, 0), VERR_TIMEOUT);
333
334 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead(hSemRW, 1), VERR_TIMEOUT);
335 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hSemRW, 1), VERR_TIMEOUT);
336
337 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead(hSemRW, 50), VERR_TIMEOUT);
338 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hSemRW, 50), VERR_TIMEOUT);
339
340 return VINF_SUCCESS;
341}
342
343
344static void Test3(void)
345{
346 RTTestSub(g_hTest, "Negative");
347 bool fSavedAssertQuiet = RTAssertSetQuiet(true);
348 bool fSavedAssertMayPanic = RTAssertSetMayPanic(false);
349 bool fSavedLckValEnabled = RTLockValidatorSetEnabled(false);
350
351 RTSEMRW hSemRW;
352 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&hSemRW), VINF_SUCCESS);
353
354 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hSemRW), VERR_NOT_OWNER);
355 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VERR_NOT_OWNER);
356
357 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS);
358 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hSemRW), VERR_NOT_OWNER);
359
360 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS);
361 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VERR_WRONG_ORDER); /* cannot release the final write before the reads. */
362 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hSemRW), VINF_SUCCESS);
363 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS);
364
365 RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(hSemRW), VINF_SUCCESS);
366
367 RTLockValidatorSetEnabled(fSavedLckValEnabled);
368 RTAssertSetMayPanic(fSavedAssertMayPanic);
369 RTAssertSetQuiet(fSavedAssertQuiet);
370}
371
372static void Test2(void)
373{
374 RTTestSub(g_hTest, "Timeout");
375
376 RTSEMRW hSemRW = NIL_RTSEMRW;
377 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&hSemRW), VINF_SUCCESS);
378
379 /* Lock it for writing and let the thread do the remainder of the test. */
380 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWRequestWrite(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS);
381
382 RTTHREAD hThread;
383 RTTEST_CHECK_RC_RETV(g_hTest, RTThreadCreate(&hThread, Test2Thread, hSemRW, 0,
384 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test2"),
385 VINF_SUCCESS);
386 RTTEST_CHECK_RC(g_hTest, RTThreadWait(hThread, 15000, NULL), VINF_SUCCESS);
387 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS);
388
389 RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(hSemRW), VINF_SUCCESS);
390}
391
392
393static bool Test1(void)
394{
395 RTTestSub(g_hTest, "Basics");
396
397 RTSEMRW hSemRW = NIL_RTSEMRW;
398 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWCreate(&hSemRW), VINF_SUCCESS, false);
399 RTTEST_CHECK_RET(g_hTest, hSemRW != NIL_RTSEMRW, false);
400
401 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS, false);
402 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseRead(hSemRW), VINF_SUCCESS, false);
403
404 for (unsigned cMs = 0; cMs < 50; cMs++)
405 {
406 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hSemRW, cMs), VINF_SUCCESS, false);
407 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hSemRW, cMs), VINF_SUCCESS, false);
408 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseRead(hSemRW), VINF_SUCCESS, false);
409 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseRead(hSemRW), VINF_SUCCESS, false);
410 }
411
412 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS, false);
413 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS, false);
414
415 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS, false);
416 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS, false);
417 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseRead(hSemRW), VINF_SUCCESS, false);
418 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS, false);
419
420 for (unsigned cMs = 0; cMs < 50; cMs++)
421 {
422 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hSemRW, cMs), VINF_SUCCESS, false);
423 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriteRecursion(hSemRW) == 1, false);
424 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriterReadRecursion(hSemRW) == 0, false);
425 RTTEST_CHECK_RET(g_hTest, RTSemRWIsWriteOwner(hSemRW) == true, false);
426
427 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hSemRW, cMs), VINF_SUCCESS, false);
428 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriteRecursion(hSemRW) == 2, false);
429 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriterReadRecursion(hSemRW) == 0, false);
430 RTTEST_CHECK_RET(g_hTest, RTSemRWIsWriteOwner(hSemRW) == true, false);
431
432 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hSemRW, cMs), VINF_SUCCESS, false);
433 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriteRecursion(hSemRW) == 2, false);
434 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriterReadRecursion(hSemRW) == 1, false);
435 RTTEST_CHECK_RET(g_hTest, RTSemRWIsWriteOwner(hSemRW) == true, false);
436
437 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hSemRW, cMs), VINF_SUCCESS, false);
438 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriteRecursion(hSemRW) == 3, false);
439 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriterReadRecursion(hSemRW) == 1, false);
440 RTTEST_CHECK_RET(g_hTest, RTSemRWIsWriteOwner(hSemRW) == true, false);
441
442 /* midway */
443
444 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS, false);
445 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriteRecursion(hSemRW) == 2, false);
446 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriterReadRecursion(hSemRW) == 1, false);
447 RTTEST_CHECK_RET(g_hTest, RTSemRWIsWriteOwner(hSemRW) == true, false);
448
449 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseRead(hSemRW), VINF_SUCCESS, false);
450 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriteRecursion(hSemRW) == 2, false);
451 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriterReadRecursion(hSemRW) == 0, false);
452 RTTEST_CHECK_RET(g_hTest, RTSemRWIsWriteOwner(hSemRW) == true, false);
453
454 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS, false);
455 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriteRecursion(hSemRW) == 1, false);
456 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriterReadRecursion(hSemRW) == 0, false);
457 RTTEST_CHECK_RET(g_hTest, RTSemRWIsWriteOwner(hSemRW) == true, false);
458
459 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS, false);
460 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriteRecursion(hSemRW) == 0, false);
461 RTTEST_CHECK_RET(g_hTest, RTSemRWGetWriterReadRecursion(hSemRW) == 0, false);
462 RTTEST_CHECK_RET(g_hTest, RTSemRWIsWriteOwner(hSemRW) == false, false);
463 }
464
465 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWDestroy(hSemRW), VINF_SUCCESS, false);
466 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWDestroy(NIL_RTSEMRW), VINF_SUCCESS, false);
467
468 return true;
469}
470
471int main(int argc, char **argv)
472{
473 RT_NOREF_PV(argv);
474 int rc = RTTestInitAndCreate("tstRTSemRW", &g_hTest);
475 if (rc)
476 return 1;
477 RTTestBanner(g_hTest);
478
479 if (Test1())
480 {
481 RTCPUID cCores = RTMpGetOnlineCoreCount();
482 if (argc == 1)
483 {
484 Test2();
485 Test3();
486
487 /* threads, seconds, writePercent, yield, quiet */
488 Test4( 1, 1, 0, true, false);
489 Test4( 1, 1, 1, true, false);
490 Test4( 1, 1, 5, true, false);
491 Test4( 2, 1, 3, true, false);
492 Test4( 10, 1, 5, true, false);
493 Test4( 10, 10, 10, false, false);
494
495 if (cCores > 1)
496 {
497 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "benchmarking (%u CPU cores)...\n", cCores);
498 for (unsigned cThreads = 1; cThreads < 32; cThreads++)
499 Test4(cThreads, 2, 1, false, true);
500 }
501 else
502 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "skipping benchmarking (only %u CPU core available)\n", cCores);
503
504 /** @todo add a testcase where some stuff times out. */
505 }
506 else
507 {
508 if (cCores > 1)
509 {
510 /* threads, seconds, writePercent, yield, quiet */
511 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "benchmarking...\n");
512 Test4( 1, 3, 1, false, true);
513 Test4( 1, 3, 1, false, true);
514 Test4( 1, 3, 1, false, true);
515 Test4( 2, 3, 1, false, true);
516 Test4( 2, 3, 1, false, true);
517 Test4( 2, 3, 1, false, true);
518 Test4( 3, 3, 1, false, true);
519 Test4( 3, 3, 1, false, true);
520 Test4( 3, 3, 1, false, true);
521 }
522 else
523 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "skipping benchmarking (only %u CPU core available)\n", cCores);
524 }
525 }
526
527 return RTTestSummaryAndDestroy(g_hTest);
528}
529
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette