VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTSemEvent.cpp@ 92778

最後變更 在這個檔案從92778是 92778,由 vboxsync 提交於 3 年 前

IPRT/testcase: Added tstRTSemEvent, though currently disabled because of missing windows and whatnot code. bugref:10138

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 15.9 KB
 
1/* $Id: tstRTSemEvent.cpp 92778 2021-12-07 01:26:15Z vboxsync $ */
2/** @file
3 * IPRT Testcase - Multiple Release Event Semaphores.
4 */
5
6/*
7 * Copyright (C) 2009-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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
33#include <iprt/asm.h>
34#include <iprt/assert.h>
35#include <iprt/errcore.h>
36#include <iprt/rand.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include <iprt/test.h>
40#include <iprt/thread.h>
41#include <iprt/time.h>
42
43
44/*********************************************************************************************************************************
45* Global Variables *
46*********************************************************************************************************************************/
47/** The test handle. */
48static RTTEST g_hTest;
49/** Use to stop test loops. */
50static volatile bool g_fStop = false;
51
52
53
54/*********************************************************************************************************************************
55* Benchmark #1: Two thread pinging each other on two event sempahores. *
56*********************************************************************************************************************************/
57/** Pair of event semphores for the first benchmark test. */
58static RTSEMEVENT g_ahEvtBench1[2];
59static uint64_t g_cBench1Iterations;
60static uint64_t g_uTimeoutBench1;
61static uint64_t g_fWaitBench1;
62
63
64static DECLCALLBACK(int) bench1Thread(RTTHREAD hThreadSelf, void *pvUser)
65{
66 uintptr_t const idxThread = (uintptr_t)pvUser;
67 RT_NOREF(hThreadSelf);
68
69 uint64_t cIterations = 0;
70 for (;; cIterations++)
71 {
72 int rc = RTSemEventWaitEx(g_ahEvtBench1[idxThread], g_fWaitBench1, g_uTimeoutBench1);
73 if (RT_SUCCESS(rc))
74 RTTEST_CHECK_RC(g_hTest, RTSemEventSignal(g_ahEvtBench1[(idxThread + 1) & 1]), VINF_SUCCESS);
75 else if ( rc == VERR_TIMEOUT
76 && g_uTimeoutBench1 == 0
77 && (g_fWaitBench1 & RTSEMWAIT_FLAGS_RELATIVE) )
78 { /* likely */ }
79 else
80 RTTestFailed(g_hTest, "rc=%Rrc g_fWaitBench1=%#x g_uTimeoutBench1=%#RX64 (now=%#RX64)",
81 rc, g_fWaitBench1, g_uTimeoutBench1, RTTimeSystemNanoTS());
82 if (g_fStop)
83 {
84 RTTEST_CHECK_RC(g_hTest, RTSemEventSignal(g_ahEvtBench1[(idxThread + 1) & 1]), VINF_SUCCESS);
85 break;
86 }
87 }
88
89 if (idxThread == 0)
90 g_cBench1Iterations = cIterations;
91 return VINF_SUCCESS;
92}
93
94
95static void bench1(const char *pszTest, uint32_t fFlags, uint64_t uTimeout)
96{
97 RTTestISub(pszTest);
98
99 /*
100 * Create the two threads and make the wait on one another's sempahore.
101 */
102 g_fStop = false;
103 g_uTimeoutBench1 = uTimeout;
104 g_fWaitBench1 = fFlags;
105
106 RTTESTI_CHECK_RC_RETV(RTSemEventCreate(&g_ahEvtBench1[0]), VINF_SUCCESS);
107 RTTESTI_CHECK_RC_RETV(RTSemEventCreate(&g_ahEvtBench1[1]), VINF_SUCCESS);
108
109 RTTHREAD hThread1;
110 RTTESTI_CHECK_RC_RETV(RTThreadCreate(&hThread1, bench1Thread, (void *)0, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "bench1t1"), VINF_SUCCESS);
111 RTTHREAD hThread2;
112 RTTESTI_CHECK_RC_RETV(RTThreadCreate(&hThread2, bench1Thread, (void *)1, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "bench1t2"), VINF_SUCCESS);
113 RTThreadSleep(256);
114
115 /*
116 * Kick off the first thread and wait for 5 seconds before stopping them
117 * and seeing how many iterations they managed to perform.
118 */
119 uint64_t const nsStart = RTTimeNanoTS();
120 RTTESTI_CHECK_RC(RTSemEventSignal(g_ahEvtBench1[0]), VINF_SUCCESS);
121 RTThreadSleep(RT_MS_5SEC);
122
123 ASMAtomicWriteBool(&g_fStop, true);
124 uint64_t const cNsElapsed = RTTimeNanoTS() - nsStart;
125
126 RTTESTI_CHECK_RC(RTSemEventSignal(g_ahEvtBench1[0]), VINF_SUCCESS); /* paranoia */
127 RTTESTI_CHECK_RC(RTThreadWait(hThread1, RT_MS_5SEC, NULL), VINF_SUCCESS);
128 RTTESTI_CHECK_RC(RTSemEventSignal(g_ahEvtBench1[1]), VINF_SUCCESS);
129 RTTESTI_CHECK_RC(RTThreadWait(hThread2, RT_MS_5SEC, NULL), VINF_SUCCESS);
130
131 RTTESTI_CHECK_RC(RTSemEventDestroy(g_ahEvtBench1[0]), VINF_SUCCESS);
132 RTTESTI_CHECK_RC(RTSemEventDestroy(g_ahEvtBench1[1]), VINF_SUCCESS);
133
134 /*
135 * Report the result.
136 */
137 RTTestValue(g_hTest, "Throughput", g_cBench1Iterations * RT_NS_1SEC / cNsElapsed, RTTESTUNIT_OCCURRENCES_PER_SEC);
138 RTTestValue(g_hTest, "Roundtrip", cNsElapsed / g_cBench1Iterations, RTTESTUNIT_NS_PER_OCCURRENCE);
139
140}
141
142
143/*********************************************************************************************************************************
144* Test #1: Simple setup checking wakup order of two waiting thread. *
145*********************************************************************************************************************************/
146
147static DECLCALLBACK(int) test1Thread(RTTHREAD hThreadSelf, void *pvUser)
148{
149 RTSEMEVENT hSem = *(PRTSEMEVENT)pvUser;
150 RTTEST_CHECK_RC(g_hTest, RTThreadUserSignal(hThreadSelf), VINF_SUCCESS);
151 RTTEST_CHECK_RC(g_hTest, RTSemEventWait(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS);
152 return VINF_SUCCESS;
153}
154
155
156static void test1(void)
157{
158 RTTestISub("Three threads");
159
160 /*
161 * Create the threads and let them block on the event semaphore one
162 * after the other.
163 */
164 RTSEMEVENT hSem;
165 RTTESTI_CHECK_RC_RETV(RTSemEventCreate(&hSem), VINF_SUCCESS);
166
167 RTTHREAD hThread1;
168 RTTESTI_CHECK_RC_RETV(RTThreadCreate(&hThread1, test1Thread, &hSem, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test1t1"), VINF_SUCCESS);
169 RTTESTI_CHECK_RC_RETV(RTThreadUserWait(hThread1, RT_MS_30SEC), VINF_SUCCESS);
170 RTThreadSleep(256);
171
172 RTTHREAD hThread2;
173 RTTESTI_CHECK_RC_RETV(RTThreadCreate(&hThread2, test1Thread, &hSem, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test1t2"), VINF_SUCCESS);
174 RTTESTI_CHECK_RC_RETV(RTThreadUserWait(hThread2, RT_MS_30SEC), VINF_SUCCESS);
175 RTThreadSleep(256);
176
177 /* Signal once, hopefully waking up thread1: */
178 RTTESTI_CHECK_RC(RTSemEventSignal(hSem), VINF_SUCCESS);
179 RTTESTI_CHECK_RC(RTThreadWait(hThread1, 5000, NULL), VINF_SUCCESS);
180
181 /* Signal once more, hopefully waking up thread2: */
182 RTTESTI_CHECK_RC(RTSemEventSignal(hSem), VINF_SUCCESS);
183 RTTESTI_CHECK_RC(RTThreadWait(hThread2, 5000, NULL), VINF_SUCCESS);
184
185 RTTESTI_CHECK_RC(RTSemEventDestroy(hSem), VINF_SUCCESS);
186}
187
188
189/*********************************************************************************************************************************
190* Basic tests *
191*********************************************************************************************************************************/
192
193
194static void testBasicsWaitTimeout(RTSEMEVENT hSem, unsigned i)
195{
196 RTTESTI_CHECK_RC_RETV(RTSemEventWait(hSem, 0), VERR_TIMEOUT);
197#if 0
198 RTTESTI_CHECK_RC_RETV(RTSemEventWaitNoResume(hSem, 0), VERR_TIMEOUT);
199#else
200 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE,
201 0), VERR_TIMEOUT);
202 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
203 RTTimeSystemNanoTS() + 1000*i), VERR_TIMEOUT);
204 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
205 RTTimeNanoTS() + 1000*i), VERR_TIMEOUT);
206 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_RELATIVE,
207 0), VERR_TIMEOUT);
208#endif
209}
210
211
212static void testBasics(void)
213{
214 RTTestISub("Basics");
215
216 RTSEMEVENT hSem;
217 RTTESTI_CHECK_RC_RETV(RTSemEventCreate(&hSem), VINF_SUCCESS);
218
219 /* The semaphore is created in a non-signalled state. */
220 testBasicsWaitTimeout(hSem, 0);
221 testBasicsWaitTimeout(hSem, 1);
222 if (RTTestIErrorCount())
223 return;
224
225 /* When signalling the semaphore, only the next waiter call shall
226 success, all subsequent ones should timeout as above. */
227 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
228 RTTESTI_CHECK_RC_RETV(RTSemEventWait(hSem, 0), VINF_SUCCESS);
229 testBasicsWaitTimeout(hSem, 0);
230 if (RTTestIErrorCount())
231 return;
232
233 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
234 RTTESTI_CHECK_RC_RETV(RTSemEventWait(hSem, 2), VINF_SUCCESS);
235 testBasicsWaitTimeout(hSem, 2);
236
237 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
238 RTTESTI_CHECK_RC_RETV(RTSemEventWait(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS);
239 testBasicsWaitTimeout(hSem, 1);
240
241 if (RTTestIErrorCount())
242 return;
243
244 /* Now do all the event wait ex variations: */
245 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
246 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE,
247 0),
248 VINF_SUCCESS);
249 testBasicsWaitTimeout(hSem, 1);
250
251 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
252 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0), VINF_SUCCESS);
253 testBasicsWaitTimeout(hSem, 1);
254
255 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
256 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0), VINF_SUCCESS);
257 testBasicsWaitTimeout(hSem, 1);
258
259 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
260 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
261 RTTimeSystemNanoTS() + RT_NS_1US), VINF_SUCCESS);
262 testBasicsWaitTimeout(hSem, 1);
263
264 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
265 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
266 RTTimeNanoTS() + RT_NS_1US), VINF_SUCCESS);
267 testBasicsWaitTimeout(hSem, 0);
268
269 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
270 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
271 RTTimeNanoTS() + RT_NS_1HOUR), VINF_SUCCESS);
272 testBasicsWaitTimeout(hSem, 0);
273
274 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
275 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
276 0), VINF_SUCCESS);
277 testBasicsWaitTimeout(hSem, 1);
278
279 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
280 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
281 _1G), VINF_SUCCESS);
282 testBasicsWaitTimeout(hSem, 1);
283
284 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
285 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
286 UINT64_MAX), VINF_SUCCESS);
287
288 testBasicsWaitTimeout(hSem, 10);
289
290 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
291 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
292 RTTimeSystemMilliTS() + RT_MS_1SEC), VINF_SUCCESS);
293 testBasicsWaitTimeout(hSem, 1);
294
295 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
296 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
297 RTTimeMilliTS() + RT_MS_1SEC), VINF_SUCCESS);
298 testBasicsWaitTimeout(hSem, 1);
299
300 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
301 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
302 0), VINF_SUCCESS);
303 testBasicsWaitTimeout(hSem, 0);
304
305 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
306 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
307 _1M), VINF_SUCCESS);
308 testBasicsWaitTimeout(hSem, 1);
309
310 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
311 RTTESTI_CHECK_RC_RETV(RTSemEventWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
312 UINT64_MAX), VINF_SUCCESS);
313 testBasicsWaitTimeout(hSem, 1);
314
315 /* Destroy it. */
316 RTTESTI_CHECK_RC_RETV(RTSemEventDestroy(hSem), VINF_SUCCESS);
317 RTTESTI_CHECK_RC_RETV(RTSemEventDestroy(NIL_RTSEMEVENT), VINF_SUCCESS);
318
319 /* Whether it is signalled or not used shouldn't matter. */
320 RTTESTI_CHECK_RC_RETV(RTSemEventCreate(&hSem), VINF_SUCCESS);
321 RTTESTI_CHECK_RC_RETV(RTSemEventSignal(hSem), VINF_SUCCESS);
322 RTTESTI_CHECK_RC_RETV(RTSemEventDestroy(hSem), VINF_SUCCESS);
323
324 RTTESTI_CHECK_RC_RETV(RTSemEventCreate(&hSem), VINF_SUCCESS);
325 RTTESTI_CHECK_RC_RETV(RTSemEventDestroy(hSem), VINF_SUCCESS);
326
327 RTTestISubDone();
328}
329
330
331int main(int argc, char **argv)
332{
333 RT_NOREF_PV(argc); RT_NOREF_PV(argv);
334
335 RTEXITCODE rcExit = RTTestInitAndCreate("tstRTSemEvent", &g_hTest);
336 if (rcExit != RTEXITCODE_SUCCESS)
337 return rcExit;
338
339 testBasics();
340 if (!RTTestErrorCount(g_hTest))
341 {
342 test1();
343 }
344 if (!RTTestErrorCount(g_hTest))
345 {
346 bench1("Benchmark: Ping Pong, spin", RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_RELATIVE,
347 0);
348 bench1("Benchmark: Ping Pong, indefinite", RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE,
349 0);
350 bench1("Benchmark: Ping Pong, absolute", RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
351 RTTimeSystemNanoTS() + RT_NS_1HOUR);
352 bench1("Benchmark: Ping Pong, relative", RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE,
353 RT_NS_1HOUR);
354 bench1("Benchmark: Ping Pong, relative, resume", RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE,
355 RT_NS_1HOUR);
356 }
357
358 return RTTestSummaryAndDestroy(g_hTest);
359}
360
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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