VirtualBox

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

Last change on this file since 94130 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 8.1 KB
Line 
1/* $Id: tstSemMutex.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT Testcase - Simple Mutex Semaphore Smoke Test.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/semaphore.h>
32#include <iprt/string.h>
33#include <iprt/thread.h>
34#include <iprt/stream.h>
35#include <iprt/time.h>
36#include <iprt/initterm.h>
37#include <iprt/asm.h>
38#include <iprt/assert.h>
39
40
41/*********************************************************************************************************************************
42* Global Variables *
43*********************************************************************************************************************************/
44static RTSEMMUTEX g_hMutex = NIL_RTSEMMUTEX;
45static bool volatile g_fTerminate;
46static bool g_fYield;
47static bool g_fQuiet;
48static uint32_t volatile g_cbConcurrent;
49static uint32_t volatile g_cErrors;
50
51
52int PrintError(const char *pszFormat, ...)
53{
54 ASMAtomicIncU32(&g_cErrors);
55
56 RTPrintf("tstSemMutex: FAILURE - ");
57 va_list va;
58 va_start(va, pszFormat);
59 RTPrintfV(pszFormat, va);
60 va_end(va);
61
62 return 1;
63}
64
65
66static DECLCALLBACK(int) ThreadTest1(RTTHREAD ThreadSelf, void *pvUser)
67{
68 uint64_t *pu64 = (uint64_t *)pvUser;
69 for (;;)
70 {
71 int rc = RTSemMutexRequestNoResume(g_hMutex, RT_INDEFINITE_WAIT);
72 if (RT_FAILURE(rc))
73 {
74 PrintError("%x: RTSemMutexRequestNoResume failed with %Rrc\n", rc);
75 break;
76 }
77 if (ASMAtomicIncU32(&g_cbConcurrent) != 1)
78 {
79 PrintError("g_cbConcurrent=%d after request!\n", g_cbConcurrent);
80 break;
81 }
82
83 /*
84 * Check for fairness: The values of the threads should not differ too much
85 */
86 (*pu64)++;
87
88 /*
89 * Check for correctness: Give other threads a chance. If the implementation is
90 * correct, no other thread will be able to enter this lock now.
91 */
92 if (g_fYield)
93 RTThreadYield();
94 if (ASMAtomicDecU32(&g_cbConcurrent) != 0)
95 {
96 PrintError("g_cbConcurrent=%d before release!\n", g_cbConcurrent);
97 break;
98 }
99 rc = RTSemMutexRelease(g_hMutex);
100 if (RT_FAILURE(rc))
101 {
102 PrintError("%x: RTSemMutexRelease failed with %Rrc\n", rc);
103 break;
104 }
105 if (g_fTerminate)
106 break;
107 }
108 if (!g_fQuiet)
109 RTPrintf("tstSemMutex: Thread %08x exited with %lld\n", ThreadSelf, *pu64);
110 return VINF_SUCCESS;
111}
112
113
114static int Test1(unsigned cThreads, unsigned cSeconds, bool fYield, bool fQuiet)
115{
116 int rc;
117 unsigned i;
118 uint64_t g_au64[32];
119 RTTHREAD aThreads[RT_ELEMENTS(g_au64)];
120 AssertRelease(cThreads <= RT_ELEMENTS(g_au64));
121
122 /*
123 * Init globals.
124 */
125 g_fYield = fYield;
126 g_fQuiet = fQuiet;
127 g_fTerminate = false;
128
129 rc = RTSemMutexCreate(&g_hMutex);
130 if (RT_FAILURE(rc))
131 return PrintError("RTSemMutexCreate failed (rc=%Rrc)\n", rc);
132
133 /*
134 * Create the threads and let them block on the mutex.
135 */
136 rc = RTSemMutexRequest(g_hMutex, RT_INDEFINITE_WAIT);
137 if (RT_FAILURE(rc))
138 return PrintError("RTSemMutexRequest failed (rc=%Rrc)\n", rc);
139
140 for (i = 0; i < cThreads; i++)
141 {
142 g_au64[i] = 0;
143 rc = RTThreadCreate(&aThreads[i], ThreadTest1, &g_au64[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test");
144 if (RT_FAILURE(rc))
145 return PrintError("RTThreadCreate failed for thread %u (rc=%Rrc)\n", i, rc);
146 }
147
148 if (!fQuiet)
149 RTPrintf("tstSemMutex: %zu Threads created. Racing them for %u seconds (%s) ...\n",
150 cThreads, cSeconds, g_fYield ? "yielding" : "no yielding");
151
152 uint64_t u64StartTS = RTTimeNanoTS();
153 rc = RTSemMutexRelease(g_hMutex);
154 if (RT_FAILURE(rc))
155 PrintError("RTSemMutexRelease failed (rc=%Rrc)\n", rc);
156 RTThreadSleep(cSeconds * 1000);
157 ASMAtomicXchgBool(&g_fTerminate, true);
158 uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS;
159
160 for (i = 0; i < cThreads; i++)
161 {
162 rc = RTThreadWait(aThreads[i], 5000, NULL);
163 if (RT_FAILURE(rc))
164 PrintError("RTThreadWait failed for thread %u (rc=%Rrc)\n", i, rc);
165 }
166
167 rc = RTSemMutexDestroy(g_hMutex);
168 if (RT_FAILURE(rc))
169 PrintError("RTSemMutexDestroy failed - %Rrc\n", rc);
170 g_hMutex = NIL_RTSEMMUTEX;
171 if (g_cErrors)
172 RTThreadSleep(100);
173
174 /*
175 * Collect and display the results.
176 */
177 uint64_t Total = g_au64[0];
178 for (i = 1; i < cThreads; i++)
179 Total += g_au64[i];
180
181 uint64_t Normal = Total / cThreads;
182 uint64_t MaxDeviation = 0;
183 for (i = 0; i < cThreads; i++)
184 {
185 uint64_t Delta = RT_ABS((int64_t)(g_au64[i] - Normal));
186 if (Delta > Normal / 2)
187 RTPrintf("tstSemMutex: Warning! Thread %d deviates by more than 50%% - %llu (it) vs. %llu (avg)\n",
188 i, g_au64[i], Normal);
189 if (Delta > MaxDeviation)
190 MaxDeviation = Delta;
191
192 }
193
194 RTPrintf("tstSemMutex: Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n",
195 cThreads,
196 Total,
197 Total / cSeconds,
198 ElapsedNS / Total,
199 MaxDeviation * 100 / Normal
200 );
201 return 0;
202}
203
204
205int main(int argc, char **argv)
206{
207 int rc = RTR3InitExe(argc, &argv, 0);
208 if (RT_FAILURE(rc))
209 {
210 RTPrintf("tstSemMutex: RTR3InitExe failed (rc=%Rrc)\n", rc);
211 return 1;
212 }
213 RTPrintf("tstSemMutex: TESTING...\n");
214
215 if (argc == 1)
216 {
217 /* threads, seconds, yield, quiet */
218 Test1( 1, 1, true, false);
219 Test1( 2, 1, true, false);
220 Test1( 10, 1, true, false);
221 Test1( 10, 10, false, false);
222
223 RTPrintf("tstSemMutex: benchmarking...\n");
224 for (unsigned cThreads = 1; cThreads < 32; cThreads++)
225 Test1(cThreads, 2, false, true);
226
227 /** @todo add a testcase where some stuff times out. */
228 }
229 else
230 {
231 /* threads, seconds, yield, quiet */
232 RTPrintf("tstSemMutex: benchmarking...\n");
233 Test1( 1, 3, false, true);
234 Test1( 1, 3, false, true);
235 Test1( 1, 3, false, true);
236 Test1( 2, 3, false, true);
237 Test1( 2, 3, false, true);
238 Test1( 2, 3, false, true);
239 Test1( 3, 3, false, true);
240 Test1( 3, 3, false, true);
241 Test1( 3, 3, false, true);
242 }
243
244 if (!g_cErrors)
245 RTPrintf("tstSemMutex: SUCCESS\n");
246 else
247 RTPrintf("tstSemMutex: FAILURE - %u errors\n", g_cErrors);
248 return g_cErrors != 0;
249}
250
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