/* $Id: tstVMREQ.cpp 105352 2024-07-16 11:21:19Z vboxsync $ */ /** @file * VMM Testcase. */ /* * Copyright (C) 2006-2023 Oracle and/or its affiliates. * * This file is part of VirtualBox base platform packages, as * available from https://www.virtualbox.org. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, in version 3 of the * License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * SPDX-License-Identifier: GPL-3.0-only */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ #define TESTCASE "tstVMREQ" /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ RTTEST g_hTest; /** * Testings va_list passing in VMSetRuntimeError. */ static DECLCALLBACK(void) MyAtRuntimeError(PUVM pUVM, void *pvUser, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va) { NOREF(pUVM); if (strcmp((const char *)pvUser, "user argument")) RTTestFailed(g_hTest, "pvUser=%p:{%s}!\n", pvUser, (const char *)pvUser); if (fFlags) RTTestFailed(g_hTest, "fFlags=%#x!\n", fFlags); if (strcmp(pszErrorId, "enum")) RTTestFailed(g_hTest, "pszErrorId=%p:{%s}!\n", pszErrorId, pszErrorId); if (strcmp(pszFormat, "some %s string")) RTTestFailed(g_hTest, "pszFormat=%p:{%s}!\n", pszFormat, pszFormat); char szBuf[1024]; RTStrPrintfV(szBuf, sizeof(szBuf), pszFormat, va); if (strcmp(szBuf, "some error string")) RTTestFailed(g_hTest, "RTStrPrintfV -> '%s'!\n", szBuf); } /** * The function PassVA and PassVA2 calls. */ static DECLCALLBACK(int) PassVACallback(PUVM pUVM, unsigned u4K, unsigned u1G, const char *pszFormat, va_list *pva) { NOREF(pUVM); if (u4K != _4K) RTTestFailed(g_hTest, "u4K=%#x!\n", u4K); if (u1G != _1G) RTTestFailed(g_hTest, "u1G=%#x!\n", u1G); if (strcmp(pszFormat, "hello %s")) RTTestFailed(g_hTest, "pszFormat=%p:{%s}!\n", pszFormat, pszFormat); char szBuf[1024]; RTStrPrintfV(szBuf, sizeof(szBuf), pszFormat, *pva); if (strcmp(szBuf, "hello world")) RTTestFailed(g_hTest, "RTStrPrintfV -> '%s'!\n", szBuf); return VINF_SUCCESS; } /** * Functions that tests passing a va_list * argument in a request, * similar to VMSetRuntimeError. */ static void PassVA2(PUVM pUVM, const char *pszFormat, va_list va) { #if 0 /** @todo test if this is a GCC problem only or also happens with AMD64+VCC80... */ void *pvVA = &va; #else va_list va2; va_copy(va2, va); void *pvVA = &va2; #endif int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)PassVACallback, 5, pUVM, _4K, _1G, pszFormat, pvVA); NOREF(rc); #if 1 va_end(va2); #endif } /** * Functions that tests passing a va_list * argument in a request, * similar to VMSetRuntimeError. */ static void PassVA(PUVM pUVM, const char *pszFormat, ...) { /* 1st test */ va_list va1; va_start(va1, pszFormat); int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)PassVACallback, 5, pUVM, _4K, _1G, pszFormat, &va1); va_end(va1); NOREF(rc); /* 2nd test */ va_list va2; va_start(va2, pszFormat); PassVA2(pUVM, pszFormat, va2); va_end(va2); } /** * Thread function which allocates and frees requests like wildfire. */ static DECLCALLBACK(int) Thread(RTTHREAD hThreadSelf, void *pvUser) { int rc = VINF_SUCCESS; PUVM pUVM = (PUVM)pvUser; NOREF(hThreadSelf); for (unsigned i = 0; i < 100000; i++) { PVMREQ apReq[17]; const unsigned cReqs = i % RT_ELEMENTS(apReq); unsigned iReq; for (iReq = 0; iReq < cReqs; iReq++) { rc = VMR3ReqAlloc(pUVM, &apReq[iReq], VMREQTYPE_INTERNAL, VMCPUID_ANY); if (RT_FAILURE(rc)) { RTTestFailed(g_hTest, "i=%d iReq=%d cReqs=%d rc=%Rrc (alloc)\n", i, iReq, cReqs, rc); return rc; } apReq[iReq]->iStatus = iReq + i; } for (iReq = 0; iReq < cReqs; iReq++) { if (apReq[iReq]->iStatus != (int)(iReq + i)) { RTTestFailed(g_hTest, "i=%d iReq=%d cReqs=%d: iStatus=%d != %d\n", i, iReq, cReqs, apReq[iReq]->iStatus, iReq + i); return VERR_GENERAL_FAILURE; } rc = VMR3ReqFree(apReq[iReq]); if (RT_FAILURE(rc)) { RTTestFailed(g_hTest, "i=%d iReq=%d cReqs=%d rc=%Rrc (free)\n", i, iReq, cReqs, rc); return rc; } } //if (!(i % 10000)) // RTPrintf(TESTCASE ": i=%d\n", i); } return VINF_SUCCESS; } /********************************************************************************************************************************* * The VMR3ReqCallWaitU test * *********************************************************************************************************************************/ static uintptr_t g_auArgs[32]; static uint32_t volatile g_cCalled = 0; #define CHECK_ARG(a_iArg, a_ArgValue) do { \ if ((uintptr_t)(a_ArgValue) != g_auArgs[a_iArg]) \ RTTestFailed(g_hTest, "%s/#%u: %#zx, expected %#zx!", \ __FUNCTION__, a_iArg, (uintptr_t)(a_ArgValue), g_auArgs[a_iArg]); \ } while (0) #define CHECK_ARG_EX(a_iArg, a_ArgValue, a_Type) do { \ if ((a_ArgValue) != (a_Type)g_auArgs[a_iArg]) \ RTTestFailed(g_hTest, "%s/#%u: %#zx, expected %#zx!", \ __FUNCTION__, a_iArg, (uintptr_t)(a_ArgValue), (uintptr_t)(a_Type)g_auArgs[a_iArg]); \ } while (0) static DECLCALLBACK(int) CallbackNoArgs(void) { g_cCalled++; return VINF_SUCCESS; } #define CALLBACKS_WITH_TYPE(a_Type, a_BaseName) \ static DECLCALLBACK(int) a_BaseName##_1Args(a_Type uArg0) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_2Args(a_Type uArg0, a_Type uArg1) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_3Args(a_Type uArg0, a_Type uArg1, a_Type uArg2) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_4Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_5Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_6Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_7Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_8Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6, a_Type uArg7) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ CHECK_ARG_EX(7, uArg7, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_9Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6, a_Type uArg7, a_Type uArg8) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ CHECK_ARG_EX(7, uArg7, a_Type); \ CHECK_ARG_EX(8, uArg8, a_Type); \ return VINF_SUCCESS; \ } /* The max is now 9. See @bugref{10725}. static DECLCALLBACK(int) a_BaseName##_10Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6, a_Type uArg7, a_Type uArg8, a_Type uArg9) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ CHECK_ARG_EX(7, uArg7, a_Type); \ CHECK_ARG_EX(8, uArg8, a_Type); \ CHECK_ARG_EX(9, uArg9, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_11Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6, a_Type uArg7, a_Type uArg8, a_Type uArg9, \ a_Type uArg10) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ CHECK_ARG_EX(7, uArg7, a_Type); \ CHECK_ARG_EX(8, uArg8, a_Type); \ CHECK_ARG_EX(9, uArg9, a_Type); \ CHECK_ARG_EX(10, uArg10, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_12Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6, a_Type uArg7, a_Type uArg8, a_Type uArg9, \ a_Type uArg10, a_Type uArg11) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ CHECK_ARG_EX(7, uArg7, a_Type); \ CHECK_ARG_EX(8, uArg8, a_Type); \ CHECK_ARG_EX(9, uArg9, a_Type); \ CHECK_ARG_EX(10, uArg10, a_Type); \ CHECK_ARG_EX(11, uArg11, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_13Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6, a_Type uArg7, a_Type uArg8, a_Type uArg9, \ a_Type uArg10, a_Type uArg11, a_Type uArg12) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ CHECK_ARG_EX(7, uArg7, a_Type); \ CHECK_ARG_EX(8, uArg8, a_Type); \ CHECK_ARG_EX(9, uArg9, a_Type); \ CHECK_ARG_EX(10, uArg10, a_Type); \ CHECK_ARG_EX(11, uArg11, a_Type); \ CHECK_ARG_EX(12, uArg12, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_14Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6, a_Type uArg7, a_Type uArg8, a_Type uArg9, \ a_Type uArg10, a_Type uArg11, a_Type uArg12, a_Type uArg13) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ CHECK_ARG_EX(7, uArg7, a_Type); \ CHECK_ARG_EX(8, uArg8, a_Type); \ CHECK_ARG_EX(9, uArg9, a_Type); \ CHECK_ARG_EX(10, uArg10, a_Type); \ CHECK_ARG_EX(11, uArg11, a_Type); \ CHECK_ARG_EX(12, uArg12, a_Type); \ CHECK_ARG_EX(13, uArg13, a_Type); \ return VINF_SUCCESS; \ } \ \ \ static DECLCALLBACK(int) a_BaseName##_15Args(a_Type uArg0, a_Type uArg1, a_Type uArg2, a_Type uArg3, a_Type uArg4, \ a_Type uArg5, a_Type uArg6, a_Type uArg7, a_Type uArg8, a_Type uArg9, \ a_Type uArg10, a_Type uArg11, a_Type uArg12, a_Type uArg13, a_Type uArg14) \ { \ g_cCalled++; \ CHECK_ARG_EX(0, uArg0, a_Type); \ CHECK_ARG_EX(1, uArg1, a_Type); \ CHECK_ARG_EX(2, uArg2, a_Type); \ CHECK_ARG_EX(3, uArg3, a_Type); \ CHECK_ARG_EX(4, uArg4, a_Type); \ CHECK_ARG_EX(5, uArg5, a_Type); \ CHECK_ARG_EX(6, uArg6, a_Type); \ CHECK_ARG_EX(7, uArg7, a_Type); \ CHECK_ARG_EX(8, uArg8, a_Type); \ CHECK_ARG_EX(9, uArg9, a_Type); \ CHECK_ARG_EX(10, uArg10, a_Type); \ CHECK_ARG_EX(11, uArg11, a_Type); \ CHECK_ARG_EX(12, uArg12, a_Type); \ CHECK_ARG_EX(13, uArg13, a_Type); \ CHECK_ARG_EX(14, uArg14, a_Type); \ return VINF_SUCCESS; \ } */ #if ARCH_BITS == 64 # define RAND_ARG_UINTPTR(a_Type, a_iArg) (g_auArgs[a_iArg] = RTRandU64()) #elif ARCH_BITS == 32 # define RAND_ARG_UINTPTR(a_Type, a_iArg) (g_auArgs[a_iArg] = RTRandU32()) #else # error "Unsupported ARCH_BITS value!" #endif #define RAND_ARG_UINT32(a_Type, a_iArg) (uint32_t)(g_auArgs[a_iArg] = RTRandU32()) #define RAND_ARG_UINT16(a_Type, a_iArg) (uint16_t)(g_auArgs[a_iArg] = (uint16_t)RTRandU32()) #define RAND_ARG_UINT8(a_Type, a_iArg) (uint8_t)( g_auArgs[a_iArg] = (uint8_t)RTRandU32()) #if 1 # define RAND_ARG_BOOL(a_Type, a_iArg) (bool)( g_auArgs[a_iArg] = (bool)(RTRandU32() & 1)) #else # define RAND_ARG_BOOL(a_Type, a_iArg) ((bool)(g_auArgs[a_iArg] = a_iArg % 2 ? true : false), a_iArg % 2 ? true : false) #endif CALLBACKS_WITH_TYPE(uintptr_t, CallbackUintPtr) CALLBACKS_WITH_TYPE(uint32_t, CallbackUint32) CALLBACKS_WITH_TYPE(uint16_t, CallbackUint16) CALLBACKS_WITH_TYPE(uint8_t, CallbackUint8) CALLBACKS_WITH_TYPE(bool, CallbackBool) static void doCallWaitTests(PUVM pUVM) { RTTestSub(g_hTest, "VMR3ReqCallWaitU"); uint32_t cCalled = g_cCalled = 0; /* * Basic check w/o params. */ int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)CallbackNoArgs, 0); RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); cCalled += 1; RTTEST_CHECK(g_hTest, g_cCalled == cCalled); /* * Macro for testing passing 1 thru 15 arguments of a single type. */ #define TEST_CALLBACKS_WITH_TYPES(a_Type, a_CallbackBaseName, a_fnRandArg) \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_1Args, 1, \ a_fnRandArg(a_Type, 0)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_2Args, 2, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_3Args, 3, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_4Args, 4, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_5Args, 5, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_6Args, 6, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_7Args, 7, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_8Args, 8, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6), a_fnRandArg(a_Type, 7)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_9Args, 9, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6), a_fnRandArg(a_Type, 7), \ a_fnRandArg(a_Type, 8)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ /* The max is now 9. See @bugref{10725}. rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_10Args, 10, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6), a_fnRandArg(a_Type, 7), \ a_fnRandArg(a_Type, 8), a_fnRandArg(a_Type, 9)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_11Args, 11, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6), a_fnRandArg(a_Type, 7), \ a_fnRandArg(a_Type, 8), a_fnRandArg(a_Type, 9), a_fnRandArg(a_Type, 10)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_12Args, 12, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6), a_fnRandArg(a_Type, 7), \ a_fnRandArg(a_Type, 8), a_fnRandArg(a_Type, 9), a_fnRandArg(a_Type, 10), a_fnRandArg(a_Type, 11)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_13Args, 13, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6), a_fnRandArg(a_Type, 7), \ a_fnRandArg(a_Type, 8), a_fnRandArg(a_Type, 9), a_fnRandArg(a_Type, 10), a_fnRandArg(a_Type, 11), \ a_fnRandArg(a_Type, 12)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_14Args, 14, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6), a_fnRandArg(a_Type, 7), \ a_fnRandArg(a_Type, 8), a_fnRandArg(a_Type, 9), a_fnRandArg(a_Type, 10), a_fnRandArg(a_Type, 11), \ a_fnRandArg(a_Type, 12), a_fnRandArg(a_Type, 13)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled); \ \ rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)a_CallbackBaseName##_15Args, 15, \ a_fnRandArg(a_Type, 0), a_fnRandArg(a_Type, 1), a_fnRandArg(a_Type, 2), a_fnRandArg(a_Type, 3), \ a_fnRandArg(a_Type, 4), a_fnRandArg(a_Type, 5), a_fnRandArg(a_Type, 6), a_fnRandArg(a_Type, 7), \ a_fnRandArg(a_Type, 8), a_fnRandArg(a_Type, 9), a_fnRandArg(a_Type, 10), a_fnRandArg(a_Type, 11), \ a_fnRandArg(a_Type, 12), a_fnRandArg(a_Type, 13), a_fnRandArg(a_Type, 14)); \ RTTEST_CHECK_RC(g_hTest, rc, VINF_SUCCESS); \ cCalled += 1; \ RTTEST_CHECK(g_hTest, g_cCalled == cCalled) */ /* * Test passing various types. */ TEST_CALLBACKS_WITH_TYPES(uintptr_t, CallbackUintPtr, RAND_ARG_UINTPTR); TEST_CALLBACKS_WITH_TYPES(uint32_t, CallbackUint32, RAND_ARG_UINT32); TEST_CALLBACKS_WITH_TYPES(uint16_t, CallbackUint16, RAND_ARG_UINT16); TEST_CALLBACKS_WITH_TYPES(uint8_t, CallbackUint8, RAND_ARG_UINT8); TEST_CALLBACKS_WITH_TYPES(bool, CallbackBool, RAND_ARG_BOOL); } /********************************************************************************************************************************* * VM construction stuff. * *********************************************************************************************************************************/ static DECLCALLBACK(int) tstVMREQConfigConstructor(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvUser) { RT_NOREF(pUVM, pVMM, pvUser); return CFGMR3ConstructDefaultTree(pVM); } /** * Entry point. */ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp) { RT_NOREF1(envp); RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_TRY_SUPLIB); RTTestCreate(TESTCASE, &g_hTest); RTTestSub(g_hTest, "Setup..."); /* * Create empty VM. */ PUVM pUVM; int rc = VMR3Create(1 /*cCpus*/, NULL, 0 /*fFlags*/, NULL, NULL, tstVMREQConfigConstructor, NULL, NULL, &pUVM); if (RT_SUCCESS(rc)) { /* * Do testing. */ RTTestSub(g_hTest, "Alloc+Free Benchmark"); uint64_t const u64StartTS = RTTimeNanoTS(); RTTHREAD Thread0; rc = RTThreadCreate(&Thread0, Thread, pUVM, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "REQ0"); if (RT_SUCCESS(rc)) { RTTHREAD Thread1; rc = RTThreadCreate(&Thread1, Thread, pUVM, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "REQ1"); if (RT_SUCCESS(rc)) { int rcThread1; rc = RTThreadWait(Thread1, RT_INDEFINITE_WAIT, &rcThread1); if (RT_FAILURE(rc)) RTTestFailed(g_hTest, "RTThreadWait(Thread1,,) failed, rc=%Rrc\n", rc); if (RT_FAILURE(rcThread1)) RTTestFailed(g_hTest, "rcThread1=%Rrc", rcThread1); } else RTTestFailed(g_hTest, "RTThreadCreate(&Thread1,,,,) failed, rc=%Rrc\n", rc); int rcThread0; rc = RTThreadWait(Thread0, RT_INDEFINITE_WAIT, &rcThread0); if (RT_FAILURE(rc)) RTTestFailed(g_hTest, "RTThreadWait(Thread1,,) failed, rc=%Rrc\n", rc); if (RT_FAILURE(rcThread0)) RTTestFailed(g_hTest, "rcThread0=%Rrc", rcThread0); } else RTTestFailed(g_hTest, "RTThreadCreate(&Thread0,,,,) failed, rc=%Rrc\n", rc); uint64_t const u64ElapsedTS = RTTimeNanoTS() - u64StartTS; RTTestValue(g_hTest, "runtime", u64ElapsedTS, RTTESTUNIT_NS); /* * Print stats. */ STAMR3Print(pUVM, "/VM/Req/*"); /* * Testing va_list fun. */ RTTestSub(g_hTest, "va_list argument test"); PassVA(pUVM, "hello %s", "world"); VMR3AtRuntimeErrorRegister(pUVM, MyAtRuntimeError, (void *)"user argument"); VMSetRuntimeError(VMR3GetVM(pUVM), 0 /*fFlags*/, "enum", "some %s string", "error"); /* * Do various VMR3ReqCallWait tests. */ doCallWaitTests(pUVM); /* * Cleanup. */ rc = VMR3PowerOff(pUVM); if (!RT_SUCCESS(rc)) RTTestFailed(g_hTest, "failed to power off vm! rc=%Rrc\n", rc); rc = VMR3Destroy(pUVM); if (!RT_SUCCESS(rc)) RTTestFailed(g_hTest, "failed to destroy vm! rc=%Rrc\n", rc); VMR3ReleaseUVM(pUVM); } else if (rc == VERR_SVM_NO_SVM || rc == VERR_VMX_NO_VMX) return RTTestSkipAndDestroy(g_hTest, "%Rrc", rc); else RTTestFailed(g_hTest, "fatal error: failed to create vm! rc=%Rrc\n", rc); /* * Summary and return. */ return RTTestSummaryAndDestroy(g_hTest); } #if !defined(VBOX_WITH_HARDENING) || !defined(RT_OS_WINDOWS) /** * Main entry point. */ int main(int argc, char **argv, char **envp) { return TrustedMain(argc, argv, envp); } #endif