VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstIprtList.cpp@ 86715

Last change on this file since 86715 was 86626, checked in by vboxsync, 4 years ago

tstIprtList.cpp: Fixes to MtTestSafeRandomIndex. Use event semaphore to kick off all threads at once to increase contention. bugref:9841

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.4 KB
Line 
1/* $Id: tstIprtList.cpp 86626 2020-10-19 10:42:10Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTCList/RTCMTList.
4 */
5
6/*
7 * Copyright (C) 2011-2020 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/cpp/mtlist.h>
32
33#include <iprt/cpp/ministring.h>
34#include <iprt/test.h>
35#include <iprt/rand.h>
36#include <iprt/thread.h>
37#include <iprt/time.h>
38
39
40/*********************************************************************************************************************************
41* Global Variables *
42*********************************************************************************************************************************/
43/** Used for the string test. */
44static const char *g_apszTestStrings[] =
45{
46 "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
47 "Vestibulum non turpis vel metus pellentesque tincidunt at id massa.",
48 "Cras quis erat sed nulla ullamcorper molestie.",
49 "Mauris ac elit turpis, id pulvinar diam.",
50 "Nulla quis dolor dolor, in ultrices diam.",
51 "Vivamus ac quam non ipsum vehicula tempor ac ac arcu.",
52 "Aenean posuere lacus blandit erat semper eu iaculis ante eleifend.",
53 "Donec quis quam a lacus interdum sollicitudin quis eu est.",
54 "Morbi sed nisi a arcu commodo convallis.",
55 "Aenean molestie condimentum velit, non mattis magna ultricies quis.",
56 "Nulla id velit at mauris gravida mattis.",
57 "Phasellus viverra velit eu urna semper in porta arcu sollicitudin.",
58 "Pellentesque consequat turpis et tortor hendrerit id tempor ipsum lacinia.",
59 "Cras iaculis nulla quis risus pulvinar eget tempor lectus placerat.",
60 "Nullam in nulla sed sapien euismod euismod.",
61 "Morbi in tortor at magna sagittis fermentum ut eu nunc.",
62 "Nulla vitae ante sit amet dui molestie sagittis lacinia quis tellus.",
63 "Proin iaculis lorem ultricies metus bibendum tincidunt.",
64 "Sed gravida purus id risus sollicitudin ac porta orci vestibulum.",
65 "Duis quis purus non ligula consectetur cursus eu interdum erat.",
66 "Nullam non nunc in elit volutpat tempor in nec metus.",
67 "Aliquam id purus eget enim luctus molestie.",
68 "Sed id elit nec elit luctus scelerisque.",
69 "Suspendisse viverra leo non ligula congue ac luctus nisl vulputate.",
70 "Nulla dignissim lobortis nunc, eu tempus ipsum luctus sed.",
71 "Integer vel lacus lacus, quis condimentum felis.",
72 "Nulla ut lacus ac lacus gravida ultrices id sed ipsum.",
73 "Etiam non purus ut augue fermentum consequat.",
74 "Nam sit amet eros quis nibh blandit lacinia non posuere lectus.",
75 "Sed sit amet ipsum et dolor sagittis facilisis.",
76 "Ut congue nisi lacus, vel ultrices est.",
77 "Donec vel erat ut justo hendrerit sodales eu eget libero.",
78 "Integer a ipsum ac nunc eleifend congue convallis a urna.",
79 "Sed vel eros eu lectus imperdiet vehicula.",
80 "Vivamus eget turpis sed erat dapibus varius eget eu nulla.",
81 "Nam id nulla non elit eleifend commodo sed ac est.",
82 "Integer pulvinar dolor sodales velit pulvinar et facilisis eros scelerisque.",
83 "Ut mattis arcu ut libero imperdiet in rhoncus augue sodales.",
84 "Ut luctus turpis ligula, id dapibus felis.",
85 "Nullam sit amet sapien eget tellus hendrerit vestibulum eget in odio.",
86 "Phasellus non orci vitae mi placerat semper.",
87 "Quisque pharetra aliquet velit, quis tempor magna porttitor nec.",
88 "Praesent porta neque felis, vehicula facilisis odio.",
89 "Maecenas ultricies ipsum eu velit laoreet faucibus.",
90 "Mauris et nunc leo, et euismod quam.",
91 "Phasellus a felis et justo fringilla lacinia.",
92 "Vestibulum eget augue ante, ac viverra neque.",
93 "Mauris pellentesque ligula quis metus elementum venenatis.",
94 "Curabitur eu neque tellus, non porta sapien.",
95 "Ut mattis metus id enim aliquam laoreet et sed tortor.",
96 "Aenean quis nulla vitae nulla auctor lobortis a egestas turpis.",
97 "Praesent vitae ante a urna porta placerat non nec eros.",
98 "Donec quis neque eros, placerat adipiscing turpis.",
99 "Cras sit amet sapien risus, quis euismod arcu.",
100 "Integer volutpat massa eros, ac gravida mi.",
101 "Nunc vitae nunc sagittis diam vulputate suscipit.",
102 "Suspendisse quis mauris bibendum mauris aliquet pulvinar.",
103 "Donec volutpat vestibulum ligula, eget interdum tortor malesuada sit amet.",
104 "Mauris hendrerit dui non nibh varius sit amet fringilla orci pretium.",
105 "Phasellus a quam tellus, auctor lacinia sapien.",
106 "Sed dapibus leo vitae neque faucibus id porttitor sapien ultricies.",
107 "Maecenas euismod elit nec tortor sagittis pretium.",
108 "Ut tincidunt risus at erat fermentum sit amet molestie ante lacinia.",
109 "Nulla non leo nec lacus sollicitudin lobortis a a nisl.",
110 "Nunc vulputate erat vel libero elementum a interdum turpis malesuada.",
111 "Morbi id libero turpis, a lobortis dolor.",
112 "Donec vehicula imperdiet lorem, non pretium nulla tempus ut.",
113 "Morbi lacinia massa id nunc tempus in blandit risus blandit.",
114 "Sed feugiat orci id ipsum suscipit quis fringilla enim rutrum.",
115 "Mauris suscipit lobortis urna, vel dictum justo iaculis ac.",
116 "In rhoncus lectus tristique nunc blandit gravida placerat turpis rutrum.",
117 "Aliquam pellentesque ornare justo, sed hendrerit metus mattis a.",
118 "Nam aliquet lorem congue nisl blandit posuere.",
119 "Sed lobortis interdum ipsum, ac cursus erat lacinia in.",
120 "Maecenas vel tortor vel lorem facilisis interdum.",
121 "Aenean porttitor massa enim, eget dignissim est.",
122 "Nullam id libero lacus, mattis feugiat risus.",
123 "Fusce et dolor at eros ornare auctor malesuada vel ipsum.",
124 "Donec at massa sit amet lorem pellentesque interdum at ac lacus.",
125 "Praesent suscipit velit at justo suscipit eu vestibulum ligula interdum.",
126 "Aenean id justo nulla, vitae vulputate diam.",
127 "Fusce pellentesque leo quis orci pulvinar at pellentesque tellus dictum.",
128 "Ut facilisis purus at enim varius vulputate.",
129 "Donec malesuada bibendum sapien, sed pretium nisi cursus quis.",
130 "Mauris porttitor diam ut sapien pretium egestas.",
131 "Vestibulum ut justo eu libero semper convallis vitae et velit.",
132 "Quisque eleifend dapibus ligula, eu tincidunt massa rutrum at.",
133 "Sed euismod diam eget enim suscipit dictum.",
134 "Mauris fermentum orci eu nunc venenatis in sollicitudin tellus vestibulum.",
135 "Vivamus faucibus consequat turpis, lobortis vehicula lectus gravida eget.",
136 "Curabitur eu erat eu mi interdum scelerisque.",
137 "Morbi consequat molestie nulla, imperdiet elementum augue sagittis vel.",
138 "Sed ullamcorper velit suscipit arcu egestas quis commodo est hendrerit.",
139 "Proin vitae velit ut enim sollicitudin ultrices.",
140 "Curabitur posuere euismod lacus, sed volutpat erat adipiscing sit amet.",
141 "Cras sit amet sem lorem, in cursus augue.",
142 "Sed fermentum ultricies orci, quis hendrerit risus imperdiet et.",
143 "Proin nec arcu interdum ipsum molestie vestibulum.",
144 "Nulla quis quam non sem pretium scelerisque et eu velit.",
145 "Donec eu tellus nisl, ac vehicula tortor."
146};
147
148
149/**
150 * Does a list test.
151 *
152 * @param T1 The list type.
153 * @param T2 The input type
154 * @param pcszDesc The test description.
155 * @param paTestData Pointer to the array with the test input data.
156 * @param cTestItems The size of the input data.
157 */
158template<template <class, typename> class L, typename T1, typename T2, typename T3>
159static void test1(const char *pcszDesc, T3 paTestData[], size_t cTestItems)
160{
161 RTTestISubF("%s with size of %u (items=%u)", pcszDesc, sizeof(T1), cTestItems);
162
163 /*
164 * Construction
165 */
166
167 /* Create a test list */
168 L<T1, T2> testList;
169
170 const size_t defCap = L<T1, T2>::kDefaultCapacity;
171 RTTESTI_CHECK(testList.isEmpty());
172 RTTESTI_CHECK(testList.size() == 0);
173 RTTESTI_CHECK(testList.capacity() == defCap);
174
175 /*
176 * Adding
177 */
178
179 /* Add the second half of the test data */
180 size_t cAdded = 1;
181
182 /* Start adding the second half of our test list */
183 for (size_t i = cTestItems / 2; i < cTestItems; ++i, ++cAdded)
184 {
185 testList.append(paTestData[i]);
186 RTTESTI_CHECK_RETV(testList.size() == cAdded);
187 RTTESTI_CHECK(testList.at(0) == paTestData[cTestItems / 2]);
188 RTTESTI_CHECK(testList[0] == paTestData[cTestItems / 2]);
189 RTTESTI_CHECK(testList.first() == paTestData[cTestItems / 2]);
190 RTTESTI_CHECK(testList.at(cAdded - 1) == paTestData[i]);
191 RTTESTI_CHECK(testList[cAdded - 1] == paTestData[i]);
192 RTTESTI_CHECK(testList.last() == paTestData[i]);
193 }
194
195 /* Check that all is correctly appended. */
196 RTTESTI_CHECK_RETV(testList.size() == cTestItems / 2);
197 RTTESTI_CHECK_RETV(testList.isEmpty() == false);
198 for (size_t i = 0; i < testList.size(); ++i)
199 RTTESTI_CHECK(testList.at(i) == paTestData[cTestItems / 2 + i]);
200
201 /* Start prepending the first half of our test list. Iterate reverse to get
202 * the correct sorting back. */
203 for (size_t i = cTestItems / 2; i > 0; --i, ++cAdded)
204 {
205 testList.prepend(paTestData[i - 1]);
206 RTTESTI_CHECK_RETV(testList.size() == cAdded);
207 RTTESTI_CHECK(testList.at(0) == paTestData[i - 1]);
208 RTTESTI_CHECK(testList[0] == paTestData[i - 1]);
209 RTTESTI_CHECK(testList.first() == paTestData[i - 1]);
210 RTTESTI_CHECK(testList.at(cAdded - 1) == paTestData[cTestItems - 1]);
211 RTTESTI_CHECK(testList[cAdded - 1] == paTestData[cTestItems - 1]);
212 RTTESTI_CHECK(testList.last() == paTestData[cTestItems - 1]);
213 }
214
215 /* Check that all is correctly prepended. */
216 RTTESTI_CHECK_RETV(testList.size() == cTestItems);
217 RTTESTI_CHECK_RETV(testList.isEmpty() == false);
218 for (size_t i = 0; i < testList.size(); ++i)
219 RTTESTI_CHECK(testList.at(i) == paTestData[i]);
220
221 /*
222 * Contains
223 */
224 L<T1, T2> testList2;
225
226 /* Check full list. */
227 RTTESTI_CHECK( testList.contains(paTestData[0]));
228 RTTESTI_CHECK( testList.contains(paTestData[cTestItems / 2]));
229 RTTESTI_CHECK( testList.contains(paTestData[cTestItems - 1]));
230 RTTESTI_CHECK(!testList.contains(T1()));
231 /* Check empty list. */
232 RTTESTI_CHECK(!testList2.contains(paTestData[0]));
233 RTTESTI_CHECK(!testList2.contains(paTestData[cTestItems / 2]));
234 RTTESTI_CHECK(!testList2.contains(paTestData[cTestItems - 1]));
235 RTTESTI_CHECK(!testList2.contains(T1()));
236
237 /*
238 * Copy operator
239 */
240 L<T1, T2> testList3(testList);
241
242 /* Check that all is correctly appended. */
243 RTTESTI_CHECK_RETV(testList3.size() == cTestItems);
244 for (size_t i = 0; i < testList3.size(); ++i)
245 RTTESTI_CHECK(testList3.at(i) == paTestData[i]);
246
247 /*
248 * "=" operator
249 */
250 L<T1, T2> testList4;
251 testList4 = testList;
252
253 /* Check that all is correctly appended. */
254 RTTESTI_CHECK_RETV(testList4.size() == cTestItems);
255 for (size_t i = 0; i < testList4.size(); ++i)
256 RTTESTI_CHECK(testList4.at(i) == paTestData[i]);
257
258 /*
259 * Append list
260 */
261 testList3.append(testList4);
262
263 /* Check that all is correctly appended. */
264 RTTESTI_CHECK_RETV(testList3.size() == cTestItems * 2);
265 for (size_t i = 0; i < testList3.size(); ++i)
266 RTTESTI_CHECK(testList3.at(i) == paTestData[i % cTestItems]);
267
268 /*
269 * Prepend list
270 */
271 testList3.prepend(testList4);
272
273 /* Check that all is correctly appended. */
274 RTTESTI_CHECK_RETV(testList3.size() == cTestItems * 3);
275 for (size_t i = 0; i < testList3.size(); ++i)
276 RTTESTI_CHECK(testList3.at(i) == paTestData[i % cTestItems]);
277
278 /*
279 * "value" method
280 */
281 for (size_t i = 0; i < testList3.size(); ++i)
282 RTTESTI_CHECK(testList3.value(i) == paTestData[i % cTestItems]);
283 for (size_t i = 0; i < testList3.size(); ++i)
284 RTTESTI_CHECK(testList3.value(i, T1()) == paTestData[i % cTestItems]);
285 RTTESTI_CHECK(testList3.value(testList3.size() + 1) == T1()); /* Invalid index */
286 RTTESTI_CHECK(testList3.value(testList3.size() + 1, T1()) == T1()); /* Invalid index */
287
288 /*
289 * operator[] (reading)
290 */
291 for (size_t i = 0; i < testList.size(); ++i)
292 RTTESTI_CHECK(testList[i] == paTestData[i]);
293
294 /*
295 * operator[] (writing)
296 *
297 * Replace with inverted array.
298 */
299 for (size_t i = 0; i < cTestItems; ++i)
300 testList[i] = paTestData[cTestItems - i - 1];
301 RTTESTI_CHECK_RETV(testList.size() == cTestItems);
302 for (size_t i = 0; i < testList.size(); ++i)
303 RTTESTI_CHECK(testList[i] == paTestData[cTestItems - i - 1]);
304
305 /*
306 * Replace
307 *
308 * Replace with inverted array (Must be original array when finished).
309 */
310 for (size_t i = 0; i < cTestItems; ++i)
311 testList.replace(i, paTestData[i]);
312 RTTESTI_CHECK_RETV(testList.size() == cTestItems);
313 for (size_t i = 0; i < testList.size(); ++i)
314 RTTESTI_CHECK(testList[i] == paTestData[i]);
315
316 /*
317 * Removing
318 */
319
320 /* Remove Range */
321 testList3.removeRange(cTestItems, cTestItems * 2);
322 RTTESTI_CHECK_RETV(testList3.size() == cTestItems * 2);
323 for (size_t i = 0; i < testList3.size(); ++i)
324 RTTESTI_CHECK(testList3.at(i) == paTestData[i % cTestItems]);
325
326 /* Remove the first half (reverse) */
327 size_t cRemoved = 1;
328 for (size_t i = cTestItems / 2; i > 0; --i, ++cRemoved)
329 {
330 testList.removeAt(i - 1);
331 RTTESTI_CHECK_RETV(testList.size() == cTestItems - cRemoved);
332 }
333 RTTESTI_CHECK_RETV(testList.size() == cTestItems / 2);
334
335 /* Check that all is correctly removed and only the second part of the list
336 * is still there. */
337 for (size_t i = 0; i < testList.size(); ++i)
338 RTTESTI_CHECK(testList.at(i) == paTestData[cTestItems / 2 + i]);
339
340 /*
341 * setCapacity
342 */
343 testList.setCapacity(cTestItems * 5);
344 RTTESTI_CHECK(testList.capacity() == cTestItems * 5);
345 RTTESTI_CHECK_RETV(testList.size() == cTestItems / 2);
346
347 /* As the capacity just increased, we should still have all entries from
348 * the previous list. */
349 for (size_t i = 0; i < testList.size(); ++i)
350 RTTESTI_CHECK(testList.at(i) == paTestData[cTestItems / 2 + i]);
351
352 /* Decrease the capacity so it will be smaller than the count of items in
353 * the list. The list should be shrink automatically, but the remaining
354 * items should be still valid. */
355 testList.setCapacity(cTestItems / 4);
356 RTTESTI_CHECK_RETV(testList.size() == cTestItems / 4);
357 RTTESTI_CHECK(testList.capacity() == cTestItems / 4);
358 for (size_t i = 0; i < testList.size(); ++i)
359 RTTESTI_CHECK(testList.at(i) == paTestData[cTestItems / 2 + i]);
360
361 /* Clear all */
362 testList.clear();
363 RTTESTI_CHECK_RETV(testList.isEmpty());
364 RTTESTI_CHECK_RETV(testList.size() == 0);
365 RTTESTI_CHECK(testList.capacity() == defCap);
366
367
368 /* Copy empty lists. */
369 L<T1, T2> testList5(testList);
370 RTTESTI_CHECK_RETV(testList5.isEmpty());
371 RTTESTI_CHECK_RETV(testList5.size() == 0);
372 RTTESTI_CHECK(testList5.capacity() == 0);
373
374 testList5.append(paTestData[0]);
375 testList5 = testList;
376 RTTESTI_CHECK_RETV(testList5.isEmpty());
377 RTTESTI_CHECK_RETV(testList5.size() == 0);
378 RTTESTI_CHECK(testList5.capacity() == 0);
379
380 /*
381 * Negative testing.
382 */
383 bool fMayPanic = RTAssertMayPanic();
384 bool fQuiet = RTAssertAreQuiet();
385 RTAssertSetMayPanic(false);
386 RTAssertSetQuiet(true);
387
388 L<T1, T2> testList6;
389 for (size_t i = 0; i < cTestItems; ++i)
390 testList6.insert(i, paTestData[i]);
391 RTTESTI_CHECK(testList6.size() == cTestItems);
392
393 /* Insertion beyond the end of the array ends up at the end. */
394 size_t cBefore = testList6.size();
395 testList6.insert(cBefore + 3, paTestData[0]);
396 RTTESTI_CHECK(testList6.size() == cBefore + 1);
397 RTTESTI_CHECK(testList6.at(cBefore) == paTestData[0]);
398
399 cBefore = testList6.size();
400 L<T1, T2> testList7(testList6);
401 testList6.insert(testList6.size() + 42, testList7);
402 RTTESTI_CHECK(testList6.size() == cBefore + testList7.size());
403
404 /* Inserting, appending or prepending a list to itself is not supported. */
405 cBefore = testList6.size();
406 testList6.insert(3, testList6);
407 RTTESTI_CHECK(testList6.size() == cBefore);
408
409 cBefore = testList6.size();
410 testList6.append(testList6);
411 RTTESTI_CHECK(testList6.size() == cBefore);
412
413 cBefore = testList6.size();
414 testList6.prepend(testList6);
415 RTTESTI_CHECK(testList6.size() == cBefore);
416
417 /* Replace does nothing if the index is bad. */
418 cBefore = testList6.size();
419 testList6.replace(cBefore, testList6[6]);
420 RTTESTI_CHECK(testList6.size() == cBefore);
421
422 cBefore = testList6.size();
423 testList6.replace(cBefore + 64, testList6[6]);
424 RTTESTI_CHECK(testList6.size() == cBefore);
425
426 /* Indexing beyond the array returns the last element. */
427 cBefore = testList6.size();
428 RTTESTI_CHECK(testList6[cBefore] == testList6.last());
429 RTTESTI_CHECK(testList6[cBefore + 42] == testList6.last());
430
431 RTTESTI_CHECK(&testList6[cBefore] == &testList6[cBefore - 1]);
432 RTTESTI_CHECK(&testList6[cBefore + 42] == &testList6[cBefore - 1]);
433
434 /* removeAt does nothing if the index is bad. */
435 cBefore = testList6.size();
436 testList6.removeAt(cBefore);
437 RTTESTI_CHECK(testList6.size() == cBefore);
438
439 cBefore = testList6.size();
440 testList6.removeAt(cBefore + 42);
441 RTTESTI_CHECK(testList6.size() == cBefore);
442
443 L<T1, T2> testListEmpty1; RTTESTI_CHECK(!testListEmpty1.size());
444 testListEmpty1.removeFirst();
445 RTTESTI_CHECK(!testListEmpty1.size());
446
447 testListEmpty1.removeLast();
448 RTTESTI_CHECK(!testListEmpty1.size());
449
450 testListEmpty1.removeAt(128);
451 RTTESTI_CHECK(!testListEmpty1.size());
452
453 /* removeRange interprets indexes beyond the end as the end of array (asserted). */
454 testListEmpty1.removeRange(42, 128);
455 RTTESTI_CHECK(!testListEmpty1.size());
456
457 cBefore = testList6.size();
458 testList6.removeRange(cBefore, cBefore);
459 RTTESTI_CHECK(testList6.size() == cBefore);
460
461 cBefore = testList6.size();
462 testList6.removeRange(cBefore + 12, cBefore + 128);
463 RTTESTI_CHECK(testList6.size() == cBefore);
464
465 /* If end is less or equal to the start, nothing is done. */
466 testListEmpty1.removeRange(128, 0);
467 RTTESTI_CHECK(!testListEmpty1.size());
468
469 cBefore = testList6.size();
470 testList6.removeRange(cBefore, 0);
471 RTTESTI_CHECK(testList6.size() == cBefore);
472
473 cBefore = testList6.size();
474 testList6.removeRange(0, 0);
475 RTTESTI_CHECK(testList6.size() == cBefore);
476
477 cBefore = testList6.size();
478 testList6.removeRange(0, 0);
479 RTTESTI_CHECK(testList6.size() == cBefore);
480
481 RTAssertSetQuiet(fQuiet);
482 RTAssertSetMayPanic(fMayPanic);
483}
484
485/* define RTCList here to see what happens without MT support ;)
486 * (valgrind is the preferred tool to check). */
487#define MTTEST_LIST_TYPE RTCMTList
488#define MTTEST_TYPE uint32_t
489#define MTTEST_ITEMS 1000
490#define MTTEST_ITEMS_NOT_REMOVED 100
491
492static RTSEMEVENTMULTI g_hEvtMtTest = NIL_RTSEMEVENTMULTI;
493
494/**
495 * Thread for prepending items to a shared list.
496 *
497 * @param hSelf The thread handle.
498 * @param pvUser The provided user data.
499 */
500static DECLCALLBACK(int) MtTest1ThreadProc(RTTHREAD hSelf, void *pvUser)
501{
502 MTTEST_LIST_TYPE<MTTEST_TYPE> *pTestList = (MTTEST_LIST_TYPE<MTTEST_TYPE> *)pvUser;
503 RT_NOREF_PV(hSelf);
504 RTSemEventMultiWait(g_hEvtMtTest, RT_MS_1MIN);
505
506 /* Prepend new items at the start of the list. */
507 for (size_t i = 0; i < MTTEST_ITEMS; ++i)
508 pTestList->prepend(0x0);
509
510 return VINF_SUCCESS;
511}
512
513/**
514 * Thread for appending items to a shared list.
515 *
516 * @param hSelf The thread handle.
517 * @param pvUser The provided user data.
518 */
519static DECLCALLBACK(int) MtTest2ThreadProc(RTTHREAD hSelf, void *pvUser)
520{
521 MTTEST_LIST_TYPE<MTTEST_TYPE> *pTestList = (MTTEST_LIST_TYPE<MTTEST_TYPE> *)pvUser;
522 RT_NOREF_PV(hSelf);
523 RTSemEventMultiWait(g_hEvtMtTest, RT_MS_1MIN);
524
525 /* Append new items at the end of the list. */
526 for (size_t i = 0; i < MTTEST_ITEMS; ++i)
527 pTestList->append(0xFFFFFFFF);
528
529 return VINF_SUCCESS;
530}
531
532/** Returns an index that is safe from the removal thread. */
533static uint32_t MtTestSafeRandomIndex(MTTEST_LIST_TYPE<MTTEST_TYPE> *pTestList)
534{
535 uint32_t cItems = (uint32_t)pTestList->size();
536 if (cItems > MTTEST_ITEMS)
537 {
538 cItems -= MTTEST_ITEMS;
539 if (cItems < MTTEST_ITEMS_NOT_REMOVED)
540 cItems = MTTEST_ITEMS_NOT_REMOVED;
541 }
542 else if (cItems > MTTEST_ITEMS_NOT_REMOVED)
543 cItems = MTTEST_ITEMS_NOT_REMOVED;
544 else if (cItems <= 1)
545 return 0;
546 return RTRandU32Ex(0, cItems - 1);
547}
548
549/**
550 * Thread for inserting items to a shared list.
551 *
552 * @param hSelf The thread handle.
553 * @param pvUser The provided user data.
554 */
555static DECLCALLBACK(int) MtTest3ThreadProc(RTTHREAD hSelf, void *pvUser)
556{
557 MTTEST_LIST_TYPE<MTTEST_TYPE> *pTestList = (MTTEST_LIST_TYPE<MTTEST_TYPE> *)pvUser;
558 RT_NOREF_PV(hSelf);
559 RTSemEventMultiWait(g_hEvtMtTest, RT_MS_1MIN);
560
561 /* Insert new items in the middle of the list. */
562 for (size_t i = 0; i < MTTEST_ITEMS; ++i)
563 pTestList->insert(MtTestSafeRandomIndex(pTestList), 0xF0F0F0F0);
564
565 return VINF_SUCCESS;
566}
567
568/**
569 * Thread for reading items from a shared list.
570 *
571 * @param hSelf The thread handle.
572 * @param pvUser The provided user data.
573 */
574static DECLCALLBACK(int) MtTest4ThreadProc(RTTHREAD hSelf, void *pvUser)
575{
576 MTTEST_LIST_TYPE<MTTEST_TYPE> *pTestList = (MTTEST_LIST_TYPE<MTTEST_TYPE> *)pvUser;
577 RT_NOREF_PV(hSelf);
578 RTSemEventMultiWait(g_hEvtMtTest, RT_MS_1MIN);
579
580 MTTEST_TYPE a;
581 /* Try to read C items from random places. */
582 for (size_t i = 0; i < MTTEST_ITEMS; ++i)
583 {
584 /* Make sure there is at least one item in the list. */
585 while (pTestList->isEmpty())
586 RTThreadYield();
587 a = pTestList->at(MtTestSafeRandomIndex(pTestList));
588 }
589
590 return VINF_SUCCESS;
591}
592
593/**
594 * Thread for replacing items in a shared list.
595 *
596 * @param hSelf The thread handle.
597 * @param pvUser The provided user data.
598 */
599static DECLCALLBACK(int) MtTest5ThreadProc(RTTHREAD hSelf, void *pvUser)
600{
601 MTTEST_LIST_TYPE<MTTEST_TYPE> *pTestList = (MTTEST_LIST_TYPE<MTTEST_TYPE> *)pvUser;
602 RT_NOREF_PV(hSelf);
603 RTSemEventMultiWait(g_hEvtMtTest, RT_MS_1MIN);
604
605 /* Try to replace C items from random places. */
606 for (size_t i = 0; i < MTTEST_ITEMS; ++i)
607 {
608 /* Make sure there is at least one item in the list. */
609 while (pTestList->isEmpty())
610 RTThreadYield();
611 pTestList->replace(MtTestSafeRandomIndex(pTestList), 0xFF00FF00);
612 }
613
614 return VINF_SUCCESS;
615}
616
617/**
618 * Thread for erasing items from a shared list.
619 *
620 * @param hSelf The thread handle.
621 * @param pvUser The provided user data.
622 */
623static DECLCALLBACK(int) MtTest6ThreadProc(RTTHREAD hSelf, void *pvUser)
624{
625 MTTEST_LIST_TYPE<MTTEST_TYPE> *pTestList = (MTTEST_LIST_TYPE<MTTEST_TYPE> *)pvUser;
626 RT_NOREF_PV(hSelf);
627 RTSemEventMultiWait(g_hEvtMtTest, RT_MS_1MIN);
628
629 /* Try to delete items from random places. */
630 for (size_t i = 0; i < MTTEST_ITEMS; ++i)
631 {
632 /* Removal is racing thread 4 and 5, so, make sure we don't */
633 while (pTestList->size() <= MTTEST_ITEMS_NOT_REMOVED)
634 RTThreadYield();
635 pTestList->removeAt(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1));
636 }
637
638 return VINF_SUCCESS;
639}
640
641/**
642 * Does a multi-threading list test. Several list additions, reading, replacing
643 * and erasing are done simultaneous.
644 *
645 */
646static void test2()
647{
648 RTTestISubF("MT test with 6 threads (%u tests per thread).", MTTEST_ITEMS);
649
650 MTTEST_LIST_TYPE<MTTEST_TYPE> testList;
651 RTTHREAD ahThreads[6];
652 static struct CLANG11WEIRDNESS { PFNRTTHREAD pfn; } aThreads[6] =
653 {
654 {MtTest1ThreadProc}, {MtTest2ThreadProc}, {MtTest3ThreadProc}, {MtTest4ThreadProc}, {MtTest5ThreadProc}, {MtTest6ThreadProc}
655 };
656
657 RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&g_hEvtMtTest), VINF_SUCCESS);
658
659 for (unsigned i = 0; i < RT_ELEMENTS(ahThreads); i++)
660 {
661 RTTESTI_CHECK_RC_RETV(RTThreadCreateF(&ahThreads[i], aThreads[i].pfn, &testList, 0,
662 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest%u", i), VINF_SUCCESS);
663 }
664
665 RTTESTI_CHECK_RC(RTSemEventMultiSignal(g_hEvtMtTest), VINF_SUCCESS);
666 uint64_t tsMsDeadline = RTTimeMilliTS() + RT_MS_1MIN;
667 for (unsigned i = 0; i < RT_ELEMENTS(ahThreads); i++)
668 {
669 uint64_t tsNow = RTTimeMilliTS();
670 uint32_t cWait = tsNow > tsMsDeadline ? 5000 : tsMsDeadline - tsNow;
671 RTTESTI_CHECK_RC(RTThreadWait(ahThreads[i], cWait, NULL), VINF_SUCCESS);
672 }
673 RTTESTI_CHECK_RC(RTSemEventMultiDestroy(g_hEvtMtTest), VINF_SUCCESS);
674 g_hEvtMtTest = NIL_RTSEMEVENTMULTI;
675
676 RTTESTI_CHECK_RETV(testList.size() == MTTEST_ITEMS * 2);
677 for (size_t i = 0; i < testList.size(); ++i)
678 {
679 uint32_t a = testList.at(i);
680 RTTESTI_CHECK(a == 0x0 || a == 0xFFFFFFFF || a == 0xF0F0F0F0 || a == 0xFF00FF00);
681 }
682}
683
684int main()
685{
686 /* How many integer test items should be created. */
687 static const size_t s_cTestCount = 1000;
688
689 RTTEST hTest;
690 RTEXITCODE rcExit = RTTestInitAndCreate("tstIprtList", &hTest);
691 if (rcExit)
692 return rcExit;
693 RTTestBanner(hTest);
694
695 /*
696 * Native types.
697 */
698 uint8_t au8TestInts[s_cTestCount];
699 for (size_t i = 0; i < RT_ELEMENTS(au8TestInts); ++i)
700 au8TestInts[i] = (uint8_t)RTRandU32Ex(1, UINT8_MAX);
701 test1<RTCList, uint8_t, uint8_t, uint8_t>("ST: Native type", au8TestInts, RT_ELEMENTS(au8TestInts));
702 test1<RTCMTList, uint8_t, uint8_t, uint8_t>("MT: Native type", au8TestInts, RT_ELEMENTS(au8TestInts));
703
704 uint16_t au16TestInts[s_cTestCount];
705 for (size_t i = 0; i < RT_ELEMENTS(au16TestInts); ++i)
706 au16TestInts[i] = (uint16_t)RTRandU32Ex(1, UINT16_MAX);
707 test1<RTCList, uint16_t, uint16_t, uint16_t>("ST: Native type", au16TestInts, RT_ELEMENTS(au16TestInts));
708 test1<RTCMTList, uint16_t, uint16_t, uint16_t>("MT: Native type", au16TestInts, RT_ELEMENTS(au16TestInts));
709
710 uint32_t au32TestInts[s_cTestCount];
711 for (size_t i = 0; i < RT_ELEMENTS(au32TestInts); ++i)
712 au32TestInts[i] = RTRandU32Ex(1, UINT32_MAX);
713 test1<RTCList, uint32_t, uint32_t, uint32_t>("ST: Native type", au32TestInts, RT_ELEMENTS(au32TestInts));
714 test1<RTCMTList, uint32_t, uint32_t, uint32_t>("MT: Native type", au32TestInts, RT_ELEMENTS(au32TestInts));
715
716 /*
717 * Specialized type.
718 */
719 uint64_t au64TestInts[s_cTestCount];
720 for (size_t i = 0; i < RT_ELEMENTS(au64TestInts); ++i)
721 au64TestInts[i] = RTRandU64Ex(1, UINT64_MAX);
722 test1<RTCList, uint64_t, uint64_t, uint64_t>("ST: Specialized type", au64TestInts, RT_ELEMENTS(au64TestInts));
723 test1<RTCMTList, uint64_t, uint64_t, uint64_t>("MT: Specialized type", au64TestInts, RT_ELEMENTS(au64TestInts));
724
725 /*
726 * Big size type (translate to internal pointer list).
727 */
728 test1<RTCList, RTCString, RTCString *, const char *>("ST: Class type", g_apszTestStrings, RT_ELEMENTS(g_apszTestStrings));
729 test1<RTCMTList, RTCString, RTCString *, const char *>("MT: Class type", g_apszTestStrings, RT_ELEMENTS(g_apszTestStrings));
730
731 /*
732 * Multi-threading test.
733 */
734 test2();
735
736 /*
737 * Summary.
738 */
739 return RTTestSummaryAndDestroy(hTest);
740}
741
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