VirtualBox

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