tstHandleTable.cpp revision 8429669b672301e12d6ddab8bc9ce0618d930d2e
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * IPRT Testcase - Handle Tables.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
010ad423d45c61ef874fa1602d46459a798b54d2vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
010ad423d45c61ef874fa1602d46459a798b54d2vboxsync * available from http://www.virtualbox.org. This file is free software;
010ad423d45c61ef874fa1602d46459a798b54d2vboxsync * you can redistribute it and/or modify it under the terms of the GNU
010ad423d45c61ef874fa1602d46459a798b54d2vboxsync * General Public License (GPL) as published by the Free Software
010ad423d45c61ef874fa1602d46459a798b54d2vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
010ad423d45c61ef874fa1602d46459a798b54d2vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
010ad423d45c61ef874fa1602d46459a798b54d2vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * The contents of this file may alternatively be used under the terms
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * of the Common Development and Distribution License Version 1.0
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * VirtualBox OSE distribution, in which case the provisions of the
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * CDDL are applicable instead of those of the GPL.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * You may elect to license modified versions of this file under the
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * terms and conditions of either the GPL or the CDDL or both.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * additional information or have any questions.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync/*******************************************************************************
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync* Header Files *
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync*******************************************************************************/
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync/*******************************************************************************
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync* Global Variables *
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync*******************************************************************************/
d0eec04539061d14a7e51f492aea90fa5394615fvboxsyncstatic unsigned g_cErrors;
d0eec04539061d14a7e51f492aea90fa5394615fvboxsyncstatic DECLCALLBACK(void) tstHandleTableTest1Delete(RTHANDLETABLE hHandleTable, uint32_t h, void *pvObj, void *pvCtx, void *pvUser)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsyncstatic DECLCALLBACK(int) tstHandleTableTest1Retain(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsyncstatic int tstHandleTableTest1(uint32_t uBase, uint32_t cMax, uint32_t cDelta, uint32_t cUnitsPerDot, bool fCallbacks, uint32_t fFlags)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync const char *pszWithCtx = fFlags & RTHANDLETABLE_FLAGS_CONTEXT ? "WithCtx" : "";
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: TESTING RTHandleTableCreateEx(, 0");
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync if (fFlags & RTHANDLETABLE_FLAGS_LOCKED) RTPrintf(" | LOCKED");
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync if (fFlags & RTHANDLETABLE_FLAGS_CONTEXT) RTPrintf(" | CONTEXT");
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync rc = RTHandleTableCreateEx(&hHT, fFlags, uBase, cMax,
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE - RTHandleTableCreateEx failed, %Rrc!\n", rc);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /* fill it */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: TESTING RTHandleTableAlloc%s..", pszWithCtx); RTStrmFlush(g_pStdOut);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync for (;; i++)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync rc = RTHandleTableAllocWithCtx(hHT, (void *)((uintptr_t)&i + (uintptr_t)i * 4), NULL, &h);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync rc = RTHandleTableAlloc(hHT, (void *)((uintptr_t)&i + (uintptr_t)i * 4), &h);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync if (h != i)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - h=%d, expected %d!\n", __LINE__, h, i);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, expected > 65534!\n", __LINE__, i);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, rc=%Rrc!\n", __LINE__, i, rc);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync uint32_t const c = i;
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: FAILURE (%d) - cRetainerCalls=%#x expected 0!\n", __LINE__, i, cRetainerCalls);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /* look up all the entries */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: TESTING RTHandleTableLookup%s..", pszWithCtx); RTStrmFlush(g_pStdOut);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync for (i = uBase; i < c; i++)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync void *pvExpect = (void *)((uintptr_t)&i + (uintptr_t)i * 4);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, RTHandleTableLookup%s failed!\n", __LINE__, i, pszWithCtx);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, pvObj=%p expected %p\n", __LINE__, i, pvObj, pvExpect);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: FAILURE (%d) - cRetainerCalls=%#x expected %#x!\n", __LINE__, cRetainerCalls, c - uBase);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /* remove all the entries (in order) */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: TESTING RTHandleTableFree%s..", pszWithCtx); RTStrmFlush(g_pStdOut);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync for (i = uBase; i < c; i++)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync void *pvExpect = (void *)((uintptr_t)&i + (uintptr_t)i * 4);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, RTHandleTableLookup%s failed!\n", __LINE__, i, pszWithCtx);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, pvObj=%p expected %p\n", __LINE__, i, pvObj, pvExpect);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, RTHandleTableLookup%s succeeded after free!\n", __LINE__, i, pszWithCtx);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: FAILURE (%d) - cRetainerCalls=%#x expected %#x!\n", __LINE__, cRetainerCalls, c - uBase);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /* do a mix of alloc, lookup and free where there is a constant of cDelta handles in the table. */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: TESTING Alloc,Lookup,Free mix [cDelta=%#x]..", cDelta); RTStrmFlush(g_pStdOut);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /* alloc */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync uint32_t hExpect = ((i - uBase) % (c - uBase)) + uBase;
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync rc = RTHandleTableAllocWithCtx(hHT, (void *)((uintptr_t)&i + (uintptr_t)hExpect * 4), NULL, &h);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync rc = RTHandleTableAlloc(hHT, (void *)((uintptr_t)&i + (uintptr_t)hExpect * 4), &h);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, RTHandleTableAlloc%s: rc=%Rrc!\n", __LINE__, i, pszWithCtx, rc);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync else if (h != hExpect)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, RTHandleTableAlloc%s: h=%u hExpect=%u! - abort sub-test\n", __LINE__, i, pszWithCtx, h, hExpect);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /* lookup */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync uint32_t hLookup = ((j - uBase) % (c - uBase)) + uBase;
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync void *pvExpect = (void *)((uintptr_t)&i + (uintptr_t)hLookup * 4);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync pvObj = RTHandleTableLookupWithCtx(hHT, hLookup, NULL);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, j=%d, RTHandleTableLookup%s(,%u,): pvObj=%p expected %p!\n",
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync __LINE__, i, j, pszWithCtx, hLookup, pvObj, pvExpect);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, j=%d, RTHandleTableLookupWithCtx: succeeded with bad context\n",
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync uint32_t hFree = ((i - uBase - cDelta) % (c - uBase)) + uBase;
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync void *pvExpect = (void *)((uintptr_t)&i + (uintptr_t)hFree * 4);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync pvObj = RTHandleTableFreeWithCtx(hHT, hFree, NULL);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, RTHandleTableFree%s: pvObj=%p expected %p!\n",
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("\ntstHandleTable: FAILURE (%d) - i=%d, RTHandleTableLookup/Free%s: succeeded after free\n",
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /* finally, destroy the table (note that there are 128 entries in it). */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: FAILURE (%d) - RTHandleTableDestroy failed, %Rrc!\n", __LINE__, rc);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /** The handle table. */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /** The thread handle. */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /** Thread index. */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync /** the max number of handles the thread should allocate. */
d0eec04539061d14a7e51f492aea90fa5394615fvboxsyncstatic DECLCALLBACK(int) tstHandleTableTest2Thread(RTTHREAD hThread, void *pvUser)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTHANDLETABLE const hHT = ((PTSTHTTEST2ARGS)pvUser)->hHT;
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync uint32_t const iThread = ((PTSTHTTEST2ARGS)pvUser)->iThread;
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync uint32_t const cMax = ((PTSTHTTEST2ARGS)pvUser)->cMax;
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync uint32_t *pah = (uint32_t *)RTMemAllocZ(sizeof(uint32_t) * cMax);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: FAILURE (%d) - failed to allocate %zu bytes\n", __LINE__, sizeof(uint32_t) * cMax);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * Allocate our quota.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync int rc = RTHandleTableAllocWithCtx(hHT, pvUser, hThread, &pah[i]);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: FAILURE (%d) - t=%d i=%d: RTHandleTableAllocWithCtx failed, rc=%Rrc\n",
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * Look them up.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync void *pvObj = RTHandleTableLookupWithCtx(hHT, pah[i], hThread);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: FAILURE (%d) - t=%d i=%d: RTHandleTableLookupWithCtx failed, pvObj=%p\n",
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * Free them all.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync void *pvObj = RTHandleTableFreeWithCtx(hHT, pah[i], hThread);
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: FAILURE (%d) - t=%d i=%d: RTHandleTableFreeWithCtx failed, pvObj=%p\n",
d0eec04539061d14a7e51f492aea90fa5394615fvboxsyncstatic int tstHandleTableTest2(uint32_t uBase, uint32_t cMax, uint32_t cThreads)
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync * Create the table.
d0eec04539061d14a7e51f492aea90fa5394615fvboxsync RTPrintf("tstHandleTable: TESTING %u threads: uBase=%u, cMax=%u\n", cThreads, uBase, cMax);
int rc = RTHandleTableCreateEx(&hHT, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT, uBase, cMax, NULL, NULL);
/// @todo there must be a race somewhere in the thread code, I keep hitting a duplicate insert id here...
rc = RTThreadCreate(&paThread[i].hThread, tstHandleTableTest2Thread, &paThread[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szName);
g_cErrors++;
cRunning = 0;
cRunning++;
} while (cRunning);
g_cErrors++;
RTR3Init(false, 0);
int ch;
switch (ch)
if (!cThreads)
if (!cMax)
if (!cThreads)
tstHandleTableTest1(uBase, cMax, 128, cMax / 32, false, RTHANDLETABLE_FLAGS_CONTEXT | RTHANDLETABLE_FLAGS_LOCKED);
tstHandleTableTest1(1, 65534, 63, 2048, false, RTHANDLETABLE_FLAGS_CONTEXT | RTHANDLETABLE_FLAGS_LOCKED);
tstHandleTableTest1(1, 1024, 256, 256, true, RTHANDLETABLE_FLAGS_CONTEXT | RTHANDLETABLE_FLAGS_LOCKED);
tstHandleTableTest1(0x7ffff000, 65534, 4, 2048, false, RTHANDLETABLE_FLAGS_CONTEXT | RTHANDLETABLE_FLAGS_LOCKED);
tstHandleTableTest1(0xeffff000, 65534, 4, 2048, false, RTHANDLETABLE_FLAGS_CONTEXT | RTHANDLETABLE_FLAGS_LOCKED);
tstHandleTableTest1(0, 4097, 4, 256, false, RTHANDLETABLE_FLAGS_CONTEXT | RTHANDLETABLE_FLAGS_LOCKED);
tstHandleTableTest1(0, 1024, 4, 128, false, RTHANDLETABLE_FLAGS_CONTEXT | RTHANDLETABLE_FLAGS_LOCKED);
if (!g_cErrors)
return !!g_cErrors;