VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstSemMutex.cpp@ 100108

Last change on this file since 100108 was 99775, checked in by vboxsync, 19 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 8.4 KB
Line 
1/* $Id: tstSemMutex.cpp 99775 2023-05-12 12:21:58Z vboxsync $ */
2/** @file
3 * IPRT Testcase - Simple Mutex Semaphore Smoke Test.
4 */
5
6/*
7 * Copyright (C) 2006-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#include <iprt/string.h>
43#include <iprt/thread.h>
44#include <iprt/stream.h>
45#include <iprt/time.h>
46#include <iprt/initterm.h>
47#include <iprt/asm.h>
48#include <iprt/assert.h>
49
50
51/*********************************************************************************************************************************
52* Global Variables *
53*********************************************************************************************************************************/
54static RTSEMMUTEX g_hMutex = NIL_RTSEMMUTEX;
55static bool volatile g_fTerminate;
56static bool g_fYield;
57static bool g_fQuiet;
58static uint32_t volatile g_cbConcurrent;
59static uint32_t volatile g_cErrors;
60
61
62static int PrintError(const char *pszFormat, ...)
63{
64 ASMAtomicIncU32(&g_cErrors);
65
66 RTPrintf("tstSemMutex: FAILURE - ");
67 va_list va;
68 va_start(va, pszFormat);
69 RTPrintfV(pszFormat, va);
70 va_end(va);
71
72 return 1;
73}
74
75
76static DECLCALLBACK(int) ThreadTest1(RTTHREAD ThreadSelf, void *pvUser)
77{
78 uint64_t *pu64 = (uint64_t *)pvUser;
79 for (;;)
80 {
81 int rc = RTSemMutexRequestNoResume(g_hMutex, RT_INDEFINITE_WAIT);
82 if (RT_FAILURE(rc))
83 {
84 PrintError("%x: RTSemMutexRequestNoResume failed with %Rrc\n", rc);
85 break;
86 }
87 if (ASMAtomicIncU32(&g_cbConcurrent) != 1)
88 {
89 PrintError("g_cbConcurrent=%d after request!\n", g_cbConcurrent);
90 break;
91 }
92
93 /*
94 * Check for fairness: The values of the threads should not differ too much
95 */
96 (*pu64)++;
97
98 /*
99 * Check for correctness: Give other threads a chance. If the implementation is
100 * correct, no other thread will be able to enter this lock now.
101 */
102 if (g_fYield)
103 RTThreadYield();
104 if (ASMAtomicDecU32(&g_cbConcurrent) != 0)
105 {
106 PrintError("g_cbConcurrent=%d before release!\n", g_cbConcurrent);
107 break;
108 }
109 rc = RTSemMutexRelease(g_hMutex);
110 if (RT_FAILURE(rc))
111 {
112 PrintError("%x: RTSemMutexRelease failed with %Rrc\n", rc);
113 break;
114 }
115 if (g_fTerminate)
116 break;
117 }
118 if (!g_fQuiet)
119 RTPrintf("tstSemMutex: Thread %08x exited with %lld\n", ThreadSelf, *pu64);
120 return VINF_SUCCESS;
121}
122
123
124static int Test1(unsigned cThreads, unsigned cSeconds, bool fYield, bool fQuiet)
125{
126 int rc;
127 unsigned i;
128 uint64_t g_au64[32];
129 RTTHREAD aThreads[RT_ELEMENTS(g_au64)];
130 AssertRelease(cThreads <= RT_ELEMENTS(g_au64));
131
132 /*
133 * Init globals.
134 */
135 g_fYield = fYield;
136 g_fQuiet = fQuiet;
137 g_fTerminate = false;
138
139 rc = RTSemMutexCreate(&g_hMutex);
140 if (RT_FAILURE(rc))
141 return PrintError("RTSemMutexCreate failed (rc=%Rrc)\n", rc);
142
143 /*
144 * Create the threads and let them block on the mutex.
145 */
146 rc = RTSemMutexRequest(g_hMutex, RT_INDEFINITE_WAIT);
147 if (RT_FAILURE(rc))
148 return PrintError("RTSemMutexRequest failed (rc=%Rrc)\n", rc);
149
150 for (i = 0; i < cThreads; i++)
151 {
152 g_au64[i] = 0;
153 rc = RTThreadCreate(&aThreads[i], ThreadTest1, &g_au64[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test");
154 if (RT_FAILURE(rc))
155 return PrintError("RTThreadCreate failed for thread %u (rc=%Rrc)\n", i, rc);
156 }
157
158 if (!fQuiet)
159 RTPrintf("tstSemMutex: %zu Threads created. Racing them for %u seconds (%s) ...\n",
160 cThreads, cSeconds, g_fYield ? "yielding" : "no yielding");
161
162 uint64_t u64StartTS = RTTimeNanoTS();
163 rc = RTSemMutexRelease(g_hMutex);
164 if (RT_FAILURE(rc))
165 PrintError("RTSemMutexRelease failed (rc=%Rrc)\n", rc);
166 RTThreadSleep(cSeconds * 1000);
167 ASMAtomicXchgBool(&g_fTerminate, true);
168 uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS;
169
170 for (i = 0; i < cThreads; i++)
171 {
172 rc = RTThreadWait(aThreads[i], 5000, NULL);
173 if (RT_FAILURE(rc))
174 PrintError("RTThreadWait failed for thread %u (rc=%Rrc)\n", i, rc);
175 }
176
177 rc = RTSemMutexDestroy(g_hMutex);
178 if (RT_FAILURE(rc))
179 PrintError("RTSemMutexDestroy failed - %Rrc\n", rc);
180 g_hMutex = NIL_RTSEMMUTEX;
181 if (g_cErrors)
182 RTThreadSleep(100);
183
184 /*
185 * Collect and display the results.
186 */
187 uint64_t Total = g_au64[0];
188 for (i = 1; i < cThreads; i++)
189 Total += g_au64[i];
190
191 uint64_t Normal = Total / cThreads;
192 uint64_t MaxDeviation = 0;
193 for (i = 0; i < cThreads; i++)
194 {
195 uint64_t Delta = RT_ABS((int64_t)(g_au64[i] - Normal));
196 if (Delta > Normal / 2)
197 RTPrintf("tstSemMutex: Warning! Thread %d deviates by more than 50%% - %llu (it) vs. %llu (avg)\n",
198 i, g_au64[i], Normal);
199 if (Delta > MaxDeviation)
200 MaxDeviation = Delta;
201
202 }
203
204 RTPrintf("tstSemMutex: Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n",
205 cThreads,
206 Total,
207 Total / cSeconds,
208 ElapsedNS / Total,
209 MaxDeviation * 100 / Normal
210 );
211 return 0;
212}
213
214
215int main(int argc, char **argv)
216{
217 int rc = RTR3InitExe(argc, &argv, 0);
218 if (RT_FAILURE(rc))
219 {
220 RTPrintf("tstSemMutex: RTR3InitExe failed (rc=%Rrc)\n", rc);
221 return 1;
222 }
223 RTPrintf("tstSemMutex: TESTING...\n");
224
225 if (argc == 1)
226 {
227 /* threads, seconds, yield, quiet */
228 Test1( 1, 1, true, false);
229 Test1( 2, 1, true, false);
230 Test1( 10, 1, true, false);
231 Test1( 10, 10, false, false);
232
233 RTPrintf("tstSemMutex: benchmarking...\n");
234 for (unsigned cThreads = 1; cThreads < 32; cThreads++)
235 Test1(cThreads, 2, false, true);
236
237 /** @todo add a testcase where some stuff times out. */
238 }
239 else
240 {
241 /* threads, seconds, yield, quiet */
242 RTPrintf("tstSemMutex: benchmarking...\n");
243 Test1( 1, 3, false, true);
244 Test1( 1, 3, false, true);
245 Test1( 1, 3, false, true);
246 Test1( 2, 3, false, true);
247 Test1( 2, 3, false, true);
248 Test1( 2, 3, false, true);
249 Test1( 3, 3, false, true);
250 Test1( 3, 3, false, true);
251 Test1( 3, 3, false, true);
252 }
253
254 if (!g_cErrors)
255 RTPrintf("tstSemMutex: SUCCESS\n");
256 else
257 RTPrintf("tstSemMutex: FAILURE - %u errors\n", g_cErrors);
258 return g_cErrors != 0;
259}
260
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