VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTLockValidator.cpp@ 25621

Last change on this file since 25621 was 25621, checked in by vboxsync, 15 years ago

tstRTLockValidator: Added some recursion just to make sure it works.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.6 KB
Line 
1/* $Id: tstRTLockValidator.cpp 25621 2010-01-02 22:27:41Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTLockValidator.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/lockvalidator.h>
36
37#include <iprt/asm.h> /* for return addresses */
38#include <iprt/critsect.h>
39#include <iprt/err.h>
40#include <iprt/semaphore.h>
41#include <iprt/test.h>
42#include <iprt/thread.h>
43#include <iprt/time.h>
44
45
46/*******************************************************************************
47* Global Variables *
48*******************************************************************************/
49/** The testcase handle. */
50static RTTEST g_hTest;
51/** Flip this in the debugger to get some peace to single step wild code. */
52bool volatile g_fDoNotSpin = false;
53
54static uint32_t g_cThreads;
55static uint32_t volatile g_iDeadlockThread;
56static RTTHREAD g_ahThreads[32];
57static RTCRITSECT g_aCritSects[32];
58static RTSEMRW g_ahSemRWs[32];
59
60/** When to stop testing. */
61static uint64_t g_NanoTSStop;
62/** The number of deadlocks. */
63static uint32_t volatile g_cDeadlocks;
64/** The number of loops. */
65static uint32_t volatile g_cLoops;
66
67
68/**
69 * Spin until someone else has taken ownership of the critical section.
70 *
71 * @returns true on success, false on abort.
72 * @param pCritSect The critical section.
73 */
74static bool testWaitForCritSectToBeOwned(PRTCRITSECT pCritSect)
75{
76 unsigned iLoop = 0;
77 while (!RTCritSectIsOwned(pCritSect))
78 {
79 if (!RTCritSectIsInitialized(pCritSect))
80 return false;
81 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
82 iLoop++;
83 }
84 return true;
85}
86
87
88/**
89 * Spin until someone else has taken ownership (any kind) of the read-write
90 * semaphore.
91 *
92 * @returns true on success, false on abort.
93 * @param hSemRW The read-write semaphore.
94 */
95static bool testWaitForSemRWToBeOwned(RTSEMRW hSemRW)
96{
97 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
98 unsigned iLoop = 0;
99 for (;;)
100 {
101 if (RTSemRWGetWriteRecursion(hSemRW) > 0)
102 return true;
103 if (RTSemRWGetReadCount(hSemRW) > 0)
104 return true;
105 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
106 iLoop++;
107 }
108 return true;
109}
110
111
112/**
113 * Waits for a thread to enter a sleeping state.
114 *
115 * @returns true on success, false on abort.
116 * @param hThread The thread.
117 * @param enmDesiredState The desired thread sleep state.
118 * @param pvLock The lock it should be sleeping on.
119 */
120static bool testWaitForThreadToSleep(RTTHREAD hThread, RTTHREADSTATE enmDesiredState, void *pvLock)
121{
122 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
123 for (unsigned iLoop = 0; ; iLoop++)
124 {
125 RTTHREADSTATE enmState = RTThreadGetState(hThread);
126 if (RTTHREAD_IS_SLEEPING(enmState))
127 {
128 if ( enmState == enmDesiredState
129 && ( !pvLock
130 || pvLock == RTLockValidatorQueryBlocking(hThread)))
131 return true;
132 }
133 else if (enmState != RTTHREADSTATE_RUNNING)
134 return false;
135 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
136 }
137}
138
139
140/**
141 * Waits for all the other threads to enter sleeping states.
142 *
143 * @returns VINF_SUCCESS on success, VERR_INTERNAL_ERROR on failure.
144 * @param enmDesiredState The desired thread sleep state.
145 * @param cWaitOn The distance to the lock they'll be waiting on,
146 * the lock type is derived from the desired state.
147 * UINT32_MAX means no special lock.
148 */
149static int testWaitForAllOtherThreadsToSleep(RTTHREADSTATE enmDesiredState, uint32_t cWaitOn)
150{
151 RTTHREAD hThreadSelf = RTThreadSelf();
152 for (uint32_t i = 0; i < g_cThreads; i++)
153 {
154 RTTHREAD hThread = g_ahThreads[i];
155 if ( hThread != NIL_RTTHREAD
156 && hThread != hThreadSelf)
157 {
158 void *pvLock = NULL;
159 if (cWaitOn != UINT32_MAX)
160 {
161 uint32_t j = (i + cWaitOn) % g_cThreads;
162 switch (enmDesiredState)
163 {
164 case RTTHREADSTATE_CRITSECT: pvLock = &g_aCritSects[j]; break;
165 case RTTHREADSTATE_RW_WRITE:
166 case RTTHREADSTATE_RW_READ: pvLock = g_ahSemRWs[j]; break;
167 default: break;
168 }
169 }
170 bool fRet = testWaitForThreadToSleep(hThread, enmDesiredState, pvLock);
171 if (!fRet)
172 return VERR_INTERNAL_ERROR;
173 }
174 }
175 return VINF_SUCCESS;
176}
177
178
179/**
180 * Worker that starts the threads.
181 *
182 * @returns Same as RTThreadCreate.
183 * @param cThreads The number of threads to start.
184 * @param pfnThread Thread function.
185 */
186static int testStartThreads(uint32_t cThreads, PFNRTTHREAD pfnThread)
187{
188 uint32_t i;
189 for (i = 0; i < RT_ELEMENTS(g_ahThreads); i++)
190 g_ahThreads[i] = NIL_RTTHREAD;
191
192 for (i = 0; i < cThreads; i++)
193 RTTEST_CHECK_RC_OK_RET(g_hTest,
194 RTThreadCreateF(&g_ahThreads[i], pfnThread, (void *)(uintptr_t)i, 0,
195 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "thread-%02u", i),
196 rcCheck);
197 return VINF_SUCCESS;
198}
199
200
201/**
202 * Worker that waits for the threads to complete.
203 *
204 * @param cMillies How long to wait for each.
205 * @param fStopOnError Whether to stop on error and heed the thread
206 * return status.
207 */
208static void testWaitForThreads(uint32_t cMillies, bool fStopOnError)
209{
210 uint32_t i = RT_ELEMENTS(g_ahThreads);
211 while (i-- > 0)
212 if (g_ahThreads[i] != NIL_RTTHREAD)
213 {
214 int rcThread;
215 int rc2;
216 RTTEST_CHECK_RC_OK(g_hTest, rc2 = RTThreadWait(g_ahThreads[i], cMillies, &rcThread));
217 if (RT_SUCCESS(rc2))
218 g_ahThreads[i] = NIL_RTTHREAD;
219 if (fStopOnError && (RT_FAILURE(rc2) || RT_FAILURE(rcThread)))
220 return;
221 }
222}
223
224
225static DECLCALLBACK(int) test1Thread(RTTHREAD ThreadSelf, void *pvUser)
226{
227 uintptr_t i = (uintptr_t)pvUser;
228 PRTCRITSECT pMine = &g_aCritSects[i];
229 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
230
231 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
232 if (i & 1)
233 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
234 if (testWaitForCritSectToBeOwned(pNext))
235 {
236 int rc;
237 if (i != g_iDeadlockThread)
238 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
239 else
240 {
241 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
242 if (RT_SUCCESS(rc))
243 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VERR_SEM_LV_DEADLOCK);
244 }
245 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
246 if (RT_SUCCESS(rc))
247 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
248 }
249 if (i & 1)
250 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
251 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
252 return VINF_SUCCESS;
253}
254
255
256static DECLCALLBACK(int) test2Thread(RTTHREAD ThreadSelf, void *pvUser)
257{
258 uintptr_t i = (uintptr_t)pvUser;
259 RTSEMRW hMine = g_ahSemRWs[i];
260 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
261 int rc;
262
263 if (i & 1)
264 {
265 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
266 if ((i & 3) == 3)
267 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
268 }
269 else
270 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
271 if (testWaitForSemRWToBeOwned(hNext))
272 {
273 if (i != g_iDeadlockThread)
274 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
275 else
276 {
277 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_RW_WRITE, 1));
278 if (RT_SUCCESS(rc))
279 {
280 if (g_cThreads > 1)
281 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
282 else
283 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_ILLEGAL_UPGRADE);
284 }
285 }
286 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
287 if (RT_SUCCESS(rc))
288 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
289 }
290 if (i & 1)
291 {
292 if ((i & 3) == 3)
293 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
294 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
295 }
296 else
297 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
298 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
299 return VINF_SUCCESS;
300}
301
302
303static DECLCALLBACK(int) test3Thread(RTTHREAD ThreadSelf, void *pvUser)
304{
305 uintptr_t i = (uintptr_t)pvUser;
306 RTSEMRW hMine = g_ahSemRWs[i];
307 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
308 int rc;
309
310 if (i & 1)
311 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
312 else
313 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
314 if (testWaitForSemRWToBeOwned(hNext))
315 {
316 do
317 {
318 rc = RTSemRWRequestWrite(hNext, 60*1000);
319 if (rc != VINF_SUCCESS && rc != VERR_SEM_LV_DEADLOCK && rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
320 {
321 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc);
322 break;
323 }
324 if (RT_SUCCESS(rc))
325 {
326 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
327 if (RT_FAILURE(rc))
328 break;
329 }
330 else
331 ASMAtomicIncU32(&g_cDeadlocks);
332 ASMAtomicIncU32(&g_cLoops);
333 } while (RTTimeNanoTS() < g_NanoTSStop);
334 }
335 if (i & 1)
336 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
337 else
338 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
339 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
340 return VINF_SUCCESS;
341}
342
343
344static DECLCALLBACK(int) test4Thread(RTTHREAD ThreadSelf, void *pvUser)
345{
346 uintptr_t i = (uintptr_t)pvUser;
347 RTSEMRW hMine = g_ahSemRWs[i];
348 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
349
350 do
351 {
352 int rc1 = (i & 1 ? RTSemRWRequestWrite : RTSemRWRequestRead)(hMine, 60*1000); /* ugly ;-) */
353 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
354 if (rc1 != VINF_SUCCESS && rc1 != VERR_SEM_LV_DEADLOCK && rc1 != VERR_SEM_LV_ILLEGAL_UPGRADE)
355 {
356 RTTestFailed(g_hTest, "#%u: RTSemRWRequest%s(hMine,) -> %Rrc\n", i, i & 1 ? "Write" : "read", rc1);
357 break;
358 }
359 if (RT_SUCCESS(rc1))
360 {
361 for (unsigned iInner = 0; iInner < 4; iInner++)
362 {
363 int rc2 = RTSemRWRequestWrite(hNext, 60*1000);
364 if (rc2 != VINF_SUCCESS && rc2 != VERR_SEM_LV_DEADLOCK && rc2 != VERR_SEM_LV_ILLEGAL_UPGRADE)
365 {
366 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc2);
367 break;
368 }
369 if (RT_SUCCESS(rc2))
370 {
371 RTTEST_CHECK_RC(g_hTest, rc2 = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
372 if (RT_FAILURE(rc2))
373 break;
374 }
375 else
376 ASMAtomicIncU32(&g_cDeadlocks);
377 ASMAtomicIncU32(&g_cLoops);
378 }
379
380 RTTEST_CHECK_RC(g_hTest, rc1 = (i & 1 ? RTSemRWReleaseWrite : RTSemRWReleaseRead)(hMine), VINF_SUCCESS);
381 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
382 if (RT_FAILURE(rc1))
383 break;
384 }
385 else
386 ASMAtomicIncU32(&g_cDeadlocks);
387 ASMAtomicIncU32(&g_cLoops);
388 } while (RTTimeNanoTS() < g_NanoTSStop);
389
390 return VINF_SUCCESS;
391}
392
393
394static void testIt(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs, PFNRTTHREAD pfnThread, const char *pszName)
395{
396 if (cSecs)
397 RTTestSubF(g_hTest, "%s, %u threads, %u secs", pszName, cThreads, cSecs * cPasses);
398 else
399 RTTestSubF(g_hTest, "%s, %u threads, %u passes", pszName, cThreads, cPasses);
400
401 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_ahThreads) >= cThreads);
402 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_aCritSects) >= cThreads);
403
404 g_cThreads = cThreads;
405 g_iDeadlockThread = cThreads - 1;
406
407 for (uint32_t i = 0; i < cThreads; i++)
408 {
409 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInit(&g_aCritSects[i]), VINF_SUCCESS);
410 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&g_ahSemRWs[i]), VINF_SUCCESS);
411 }
412
413 uint32_t cLoops = 0;
414 uint32_t cDeadlocks = 0;
415 uint32_t cErrors = RTTestErrorCount(g_hTest);
416 for (uint32_t iPass = 0; iPass < cPasses && RTTestErrorCount(g_hTest) == cErrors; iPass++)
417 {
418#if 0 /** @todo figure why this ain't working for either of the two tests! */
419 g_iDeadlockThread = (cThreads - 1 + iPass) % cThreads;
420#endif
421 g_cLoops = 0;
422 g_cDeadlocks = 0;
423 g_NanoTSStop = cSecs ? RTTimeNanoTS() + cSecs * UINT64_C(1000000000) : 0;
424
425 int rc = testStartThreads(cThreads, pfnThread);
426 if (RT_SUCCESS(rc))
427 testWaitForThreads(30*1000 + cSecs*1000, true);
428
429 RTTEST_CHECK(g_hTest, !cSecs || g_cLoops > 0);
430 cLoops += g_cLoops;
431 RTTEST_CHECK(g_hTest, !cSecs || g_cDeadlocks > 0);
432 cDeadlocks += g_cDeadlocks;
433 }
434
435 for (uint32_t i = 0; i < cThreads; i++)
436 {
437 RTTEST_CHECK_RC(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
438 RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(g_ahSemRWs[i]), VINF_SUCCESS);
439 }
440 testWaitForThreads(10*1000, false);
441
442 if (cSecs)
443 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "cLoops=%u cDeadlocks=%u (%u%%)\n",
444 cLoops, cDeadlocks, cLoops ? cDeadlocks * 100 / cLoops : 0);
445}
446
447
448static void test1(uint32_t cThreads, uint32_t cPasses)
449{
450 testIt(cThreads, cPasses, 0, test1Thread, "critsect");
451}
452
453
454static void test2(uint32_t cThreads, uint32_t cPasses)
455{
456 testIt(cThreads, cPasses, 0, test2Thread, "read-write");
457}
458
459
460static void test3(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs)
461{
462 testIt(cThreads, cPasses, cSecs, test3Thread, "read-write race");
463}
464
465
466static void test4(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs)
467{
468 testIt(cThreads, cPasses, cSecs, test4Thread, "read-write race v2");
469}
470
471
472static bool testIsLockValidationCompiledIn(void)
473{
474 RTCRITSECT CritSect;
475 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectInit(&CritSect), false);
476 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectEnter(&CritSect), false);
477 bool fRet = CritSect.pValidatorRec
478 && CritSect.pValidatorRec->hThread == RTThreadSelf();
479 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectLeave(&CritSect), false);
480 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectDelete(&CritSect), false);
481
482 RTSEMRW hSemRW;
483 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWCreate(&hSemRW), false);
484 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRequestRead(hSemRW, 50), false);
485 int rc = RTSemRWRequestWrite(hSemRW, 1);
486 if (rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
487 fRet = false;
488 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
489 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWReleaseRead(hSemRW), false);
490 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), false);
491
492 return fRet;
493}
494
495int main()
496{
497 /*
498 * Init.
499 */
500 int rc = RTTestInitAndCreate("tstRTLockValidator", &g_hTest);
501 if (rc)
502 return rc;
503 RTTestBanner(g_hTest);
504
505 RTLockValidatorSetEnabled(true);
506 RTLockValidatorSetMayPanic(false);
507 RTLockValidatorSetQuiet(true);
508 if (!testIsLockValidationCompiledIn())
509 return RTTestErrorCount(g_hTest) > 0
510 ? RTTestSummaryAndDestroy(g_hTest)
511 : RTTestSkipAndDestroy(g_hTest, "deadlock detection is not compiled in");
512 RTLockValidatorSetQuiet(false);
513
514 /*
515 * Some initial tests with verbose output.
516 */
517 test1(3, 1);
518
519 test2(1, 1);
520 test2(3, 1);
521
522 /*
523 * More thorough testing without noisy output.
524 */
525 RTLockValidatorSetQuiet(true);
526
527 test1( 2, 1024);
528 test1( 3, 1024);
529 test1( 7, 896);
530 test1(10, 768);
531 test1(15, 512);
532 test1(30, 384);
533
534 test2( 1, 100);
535 test2( 2, 1024);
536 test2( 3, 1024);
537 test2( 7, 896);
538 test2(10, 768);
539 test2(15, 512);
540 test2(30, 384);
541
542 test3( 2, 1, 2);
543 test3(10, 1, 2);
544
545 test4( 2, 1, 2);
546 test4( 6, 1, 2);
547 test4(10, 1, 10);
548 test4(30, 1, 10);
549
550 return RTTestSummaryAndDestroy(g_hTest);
551}
552
Note: See TracBrowser for help on using the repository browser.

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