Changeset 98576 in vbox for trunk/include
- Timestamp:
- Feb 15, 2023 1:48:41 AM (2 years ago)
- svn:sync-xref-src-repo-rev:
- 155862
- Location:
- trunk/include/VBox/GuestHost
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/GuestHost/HGCMMock.h
r98574 r98576 1 /* $Id$ */2 1 /** @file 3 * HGCMMock.h: Mocking framework for testing HGCM-based host services + 4 * Vbgl code on the host side. 2 * TstHGCMMock.h - Mocking framework for testing HGCM-based host services. 5 3 * 6 * Goal is to run host service + Vbgl code as unmodified as 7 * possible as part of testcases to gain test coverage which 8 * otherwise wouldn't possible for heavily user-centric features 9 * like Shared Clipboard or drag'n drop (DnD). 4 * The goal is to run host service + Vbgl code as unmodified as possible as 5 * part of testcases to gain test coverage which otherwise wouldn't possible 6 * for heavily user-centric features like Shared Clipboard or drag'n drop (DnD). 7 * 8 * Currently, though, it's only the service that runs unmodified, the 9 * testcases does custom Vbgl work. 10 10 */ 11 11 … … 47 47 #endif 48 48 49 #i nclude <iprt/types.h>49 #ifdef IN_RING3 50 50 51 #include <iprt/asm.h>52 #include <iprt/assert.h>53 51 #include <iprt/list.h> 54 #include <iprt/mem.h>55 #include <iprt/rand.h>56 #include <iprt/semaphore.h>57 #include <iprt/test.h>58 #include <iprt/time.h>59 #include <iprt/thread.h>60 #include <iprt/utf16.h>61 62 #include <VBox/err.h>63 52 #include <VBox/VBoxGuestLib.h> 64 53 #include <VBox/hgcmsvc.h> 65 54 66 67 /*********************************************************************************************************************************68 * Definitions. *69 *********************************************************************************************************************************/70 71 #if defined(IN_RING3) /* Only R3 parts implemented so far. */72 73 RT_C_DECLS_BEGIN74 75 DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable);76 77 RT_C_DECLS_END78 79 # define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL80 55 81 56 /** Simple call handle structure for the guest call completion callback. */ … … 194 169 } TSTHGCMMOCKSVC; 195 170 196 /** Static HGCM service to mock. */197 static TSTHGCMMOCKSVC g_tstHgcmSvc;198 171 199 200 /*********************************************************************************************************************************201 * Prototypes. *202 *********************************************************************************************************************************/203 172 PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void); 204 173 PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout); … … 211 180 int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 212 181 182 RT_C_DECLS_BEGIN 183 DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable); 184 RT_C_DECLS_END 185 186 # undef VBGLR3DECL 187 # define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL 213 188 VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient); 214 189 VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient); … … 217 192 218 193 219 /*********************************************************************************************************************************220 * Internal functions *221 *********************************************************************************************************************************/222 223 /**224 * Initializes a HGCM mock client.225 *226 * @return VBox status code.227 * @param pClient Client instance to initialize.228 * @param idClient HGCM client ID to assign.229 * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate.230 */231 static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient)232 {233 RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT));234 235 pClient->idClient = idClient;236 if (cbClient)237 {238 pClient->pvClient = RTMemAllocZ(cbClient);239 AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY);240 pClient->cbClient = cbClient;241 }242 243 return RTSemEventCreate(&pClient->hEvent);244 }245 246 /**247 * Destroys a HGCM mock client.248 *249 * @return VBox status code.250 * @param pClient Client instance to destroy.251 */252 static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient)253 {254 int rc = RTSemEventDestroy(pClient->hEvent);255 if (RT_SUCCESS(rc))256 {257 if (pClient->pvClient)258 {259 Assert(pClient->cbClient);260 RTMemFree(pClient->pvClient);261 pClient->pvClient = NULL;262 pClient->cbClient = 0;263 }264 265 pClient->hEvent = NIL_RTSEMEVENT;266 }267 268 return rc;269 }270 271 /* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */272 static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient)273 {274 RT_NOREF(pvService);275 276 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));277 AssertPtrReturn(pFn, VERR_NO_MEMORY);278 279 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId];280 281 int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->fnTable.cbClient);282 if (RT_FAILURE(rc))283 return rc;284 285 pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT;286 pFn->pClient = pClient;287 288 RTListAppend(&pSvc->lstCall, &pFn->Node);289 pFn = NULL; /* Thread takes ownership now. */290 291 int rc2 = RTSemEventSignal(pSvc->hEventQueue);292 AssertRCReturn(rc2, rc2);293 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);294 AssertRCReturn(rc2, rc2);295 296 ASMAtomicIncU32(&pSvc->uNextClientId);297 298 rc2 = RTSemEventSignal(pSvc->hEventConnect);299 AssertRCReturn(rc2, rc2);300 301 *pidClient = pClient->idClient;302 303 return VINF_SUCCESS;304 }305 306 /* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */307 static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient)308 {309 RT_NOREF(pvService);310 311 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];312 313 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));314 AssertPtrReturn(pFn, VERR_NO_MEMORY);315 316 pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT;317 pFn->pClient = pClient;318 319 RTListAppend(&pSvc->lstCall, &pFn->Node);320 pFn = NULL; /* Thread takes ownership now. */321 322 int rc2 = RTSemEventSignal(pSvc->hEventQueue);323 AssertRCReturn(rc2, rc2);324 325 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);326 AssertRCReturn(rc2, rc2);327 328 return tstHgcmMockClientDestroy(pClient);329 }330 331 /* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */332 static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient,333 int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])334 {335 RT_NOREF(pvService, pvClient);336 337 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];338 339 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));340 AssertPtrReturn(pFn, VERR_NO_MEMORY);341 342 const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM);343 344 pFn->enmType = TSTHGCMMOCKFNTYPE_CALL;345 pFn->pClient = pClient;346 347 pFn->u.Call.hCall = callHandle;348 pFn->u.Call.iFunc = function;349 PVBOXHGCMSVCPARM const paParmsCopy = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms);350 pFn->u.Call.pParms = paParmsCopy;351 AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY);352 pFn->u.Call.cParms = cParms;353 354 RTListAppend(&pSvc->lstCall, &pFn->Node);355 356 int rc2 = RTSemEventSignal(pSvc->hEventQueue);357 AssertRCReturn(rc2, rc2);358 359 rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT);360 AssertRCReturn(rc2, rc2);361 362 memcpy(paParms, paParmsCopy, cbParms);363 /** @todo paParmsCopy is leaked, right? Doesn't appear to be a364 * use-after-free here. (pFn is freeded though) */365 366 return VINF_SUCCESS; /** @todo Return host call rc */367 }368 369 /* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */370 /** Note: Public for also being able to test host calls via testcases. */371 int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])372 {373 RT_NOREF(pvService);374 AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */375 376 pSvc->cHostCallers++;377 378 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));379 AssertPtrReturn(pFn, VERR_INVALID_POINTER);380 381 pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL;382 pFn->u.HostCall.iFunc = function;383 if (cParms)384 {385 pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM));386 AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY);387 pFn->u.HostCall.cParms = cParms;388 }389 390 RTListAppend(&pSvc->lstCall, &pFn->Node);391 pFn = NULL; /* Thread takes ownership now. */392 393 int rc2 = RTSemEventSignal(pSvc->hEventQueue);394 AssertRC(rc2);395 396 rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT);397 AssertRCReturn(rc2, rc2);398 399 Assert(pSvc->cHostCallers);400 pSvc->cHostCallers--;401 402 return pSvc->rcHostCall;403 }404 405 /**406 * Call completion callback for guest calls.407 *408 * @return VBox status code.409 * @param callHandle Call handle to complete.410 * @param rc Return code to return to the caller.411 */412 static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)413 {414 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();415 416 size_t i = 0;417 for (; RT_ELEMENTS(pSvc->aHgcmClient); i++)418 {419 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i];420 if (&pClient->hCall == callHandle) /* Slow, but works for now. */421 {422 if (rc == VINF_HGCM_ASYNC_EXECUTE)423 {424 Assert(pClient->fAsyncExec == false);425 }426 else /* Complete call + notify client. */427 {428 callHandle->rc = rc;429 430 int rc2 = RTSemEventSignal(pClient->hEvent);431 AssertRCReturn(rc2, rc2);432 }433 434 return VINF_SUCCESS;435 }436 }437 438 return VERR_NOT_FOUND;439 }440 441 /**442 * Main thread of HGCM mock service.443 *444 * @return VBox status code.445 * @param hThread Thread handle.446 * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC.447 */448 static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser)449 {450 RT_NOREF(hThread);451 PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser;452 453 pSvc->uNextClientId = 0;454 455 pSvc->fnTable.cbSize = sizeof(pSvc->fnTable);456 pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION;457 458 RT_ZERO(pSvc->fnHelpers);459 pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete;460 pSvc->fnTable.pHelpers = &pSvc->fnHelpers;461 462 int rc = VBoxHGCMSvcLoad(&pSvc->fnTable);463 if (RT_SUCCESS(rc))464 {465 RTThreadUserSignal(hThread);466 467 for (;;)468 {469 rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */);470 if (ASMAtomicReadBool(&pSvc->fShutdown))471 {472 rc = VINF_SUCCESS;473 break;474 }475 if (rc == VERR_TIMEOUT)476 continue;477 478 PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node);479 if (pFn)480 {481 switch (pFn->enmType)482 {483 case TSTHGCMMOCKFNTYPE_CONNECT:484 {485 rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService,486 pFn->pClient->idClient, pFn->pClient->pvClient,487 VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */);488 489 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);490 AssertRC(rc2);491 break;492 }493 494 case TSTHGCMMOCKFNTYPE_DISCONNECT:495 {496 rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService,497 pFn->pClient->idClient, pFn->pClient->pvClient);498 499 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);500 AssertRC(rc2);501 break;502 }503 504 case TSTHGCMMOCKFNTYPE_CALL:505 {506 pSvc->fnTable.pfnCall(pSvc->fnTable.pvService, pFn->u.Call.hCall, pFn->pClient->idClient,507 pFn->pClient->pvClient, pFn->u.Call.iFunc, pFn->u.Call.cParms,508 pFn->u.Call.pParms, RTTimeNanoTS());509 510 /* Note: Call will be completed in the call completion callback. */511 break;512 }513 514 case TSTHGCMMOCKFNTYPE_HOST_CALL:515 {516 pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(pSvc->fnTable.pvService, pFn->u.HostCall.iFunc,517 pFn->u.HostCall.cParms, pFn->u.HostCall.pParms);518 519 int rc2 = RTSemEventSignal(pSvc->hEventHostCall);520 AssertRC(rc2);521 break;522 }523 524 default:525 AssertFailed();526 break;527 }528 RTListNodeRemove(&pFn->Node);529 RTMemFree(pFn);530 }531 }532 }533 534 return rc;535 }536 537 538 /*********************************************************************************************************************************539 * Public functions *540 *********************************************************************************************************************************/541 542 /**543 * Returns the pointer to the HGCM mock service instance.544 *545 * @return Pointer to HGCM mock service instance.546 */547 PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void)548 {549 return &g_tstHgcmSvc;550 }551 552 /**553 * Waits for a HGCM mock client to connect, extended version.554 *555 * @return Pointer to connected client, or NULL if ran into timeout.556 * @param pSvc HGCM mock service instance.557 * @param msTimeout Timeout (in ms) to wait for connection.558 */559 PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout)560 {561 int rc = RTSemEventWait(pSvc->hEventConnect, msTimeout);562 if (RT_SUCCESS(rc))563 {564 Assert(pSvc->uNextClientId);565 return &pSvc->aHgcmClient[pSvc->uNextClientId - 1];566 }567 return NULL;568 }569 570 /**571 * Waits for a HGCM mock client to connect.572 *573 * @return Pointer to connected client, or NULL if waiting for connection was aborted.574 * @param pSvc HGCM mock service instance.575 */576 PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc)577 {578 return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC);579 }580 581 /**582 * Creates a HGCM mock service instance.583 *584 * @return VBox status code.585 * @param pSvc HGCM mock service instance to create.586 */587 int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc)588 {589 RT_ZERO(pSvc->aHgcmClient);590 pSvc->fShutdown = false;591 int rc = RTSemEventCreate(&pSvc->hEventQueue);592 if (RT_SUCCESS(rc))593 {594 rc = RTSemEventCreate(&pSvc->hEventHostCall);595 if (RT_SUCCESS(rc))596 {597 rc = RTSemEventCreate(&pSvc->hEventConnect);598 if (RT_SUCCESS(rc))599 {600 RTListInit(&pSvc->lstCall);601 }602 }603 }604 605 return rc;606 }607 608 /**609 * Destroys a HGCM mock service instance.610 *611 * @return VBox status code.612 * @param pSvc HGCM mock service instance to destroy.613 */614 int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc)615 {616 int rc = RTSemEventDestroy(pSvc->hEventQueue);617 if (RT_SUCCESS(rc))618 {619 rc = RTSemEventDestroy(pSvc->hEventHostCall);620 if (RT_SUCCESS(rc))621 RTSemEventDestroy(pSvc->hEventConnect);622 }623 return rc;624 }625 626 /**627 * Starts a HGCM mock service instance.628 *629 * @return VBox status code.630 * @param pSvc HGCM mock service instance to start.631 */632 int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc)633 {634 int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,635 "MockSvc");636 if (RT_SUCCESS(rc))637 rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC);638 639 return rc;640 }641 642 /**643 * Stops a HGCM mock service instance.644 *645 * @return VBox status code.646 * @param pSvc HGCM mock service instance to stop.647 */648 int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc)649 {650 ASMAtomicWriteBool(&pSvc->fShutdown, true);651 652 int rcThread;653 int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread);654 if (RT_SUCCESS(rc))655 rc = rcThread;656 if (RT_SUCCESS(rc))657 {658 pSvc->hThread = NIL_RTTHREAD;659 }660 661 return rc;662 }663 664 665 /*********************************************************************************************************************************666 * VbglR3 stubs *667 *********************************************************************************************************************************/668 669 /**670 * Connects to an HGCM mock service.671 *672 * @returns VBox status code673 * @param pszServiceName Name of the host service.674 * @param pidClient Where to put the client ID on success. The client ID675 * must be passed to all the other calls to the service.676 */677 VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient)678 {679 RT_NOREF(pszServiceName);680 681 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();682 683 return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient);684 }685 686 /**687 * Disconnect from an HGCM mock service.688 *689 * @returns VBox status code.690 * @param idClient The client id returned by VbglR3HGCMConnect().691 */692 VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient)693 {694 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();695 696 return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient);697 }698 699 /**700 * Query the session ID of the mocked VM.701 *702 * @returns IPRT status code.703 * @param pu64IdSession Session id (out).704 */705 VBGLR3DECL(int) VbglR3GetSessionId(uint64_t *pu64IdSession)706 {707 if (pu64IdSession)708 *pu64IdSession = 42;709 return VINF_SUCCESS;710 }711 712 /**713 * Makes a fully prepared HGCM call to an HGCM mock service.714 *715 * @returns VBox status code.716 * @param pInfo Fully prepared HGCM call info.717 * @param cbInfo Size of the info. This may sometimes be larger than718 * what the parameter count indicates because of719 * parameter changes between versions and such.720 */721 VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo)722 {723 RT_NOREF(cbInfo);724 725 AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo));726 AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo));727 Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo);728 729 HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);730 PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM));731 732 uint16_t i = 0;733 for (; i < pInfo->cParms; i++)734 {735 switch (offSrcParms->type)736 {737 case VMMDevHGCMParmType_32bit:738 {739 paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT;740 paDstParms[i].u.uint32 = offSrcParms->u.value32;741 break;742 }743 744 case VMMDevHGCMParmType_64bit:745 {746 paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT;747 paDstParms[i].u.uint64 = offSrcParms->u.value64;748 break;749 }750 751 case VMMDevHGCMParmType_LinAddr:752 {753 paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR;754 paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr;755 paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb;756 break;757 }758 759 default:760 AssertFailed();761 break;762 }763 764 offSrcParms++;765 }766 767 PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();768 769 int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall,770 pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient,771 pInfo->u32Function, pInfo->cParms, paDstParms);772 if (RT_SUCCESS(rc2))773 {774 offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);775 776 for (i = 0; i < pInfo->cParms; i++)777 {778 paDstParms[i].type = offSrcParms->type;779 switch (paDstParms[i].type)780 {781 case VMMDevHGCMParmType_32bit:782 offSrcParms->u.value32 = paDstParms[i].u.uint32;783 break;784 785 case VMMDevHGCMParmType_64bit:786 offSrcParms->u.value64 = paDstParms[i].u.uint64;787 break;788 789 case VMMDevHGCMParmType_LinAddr:790 {791 offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size;792 break;793 }794 795 default:796 AssertFailed();797 break;798 }799 800 offSrcParms++;801 }802 }803 804 RTMemFree(paDstParms);805 806 if (RT_SUCCESS(rc2))807 rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc;808 809 return rc2;810 }811 812 194 #endif /* IN_RING3 */ 813 195 -
trunk/include/VBox/GuestHost/HGCMMockUtils.h
r98103 r98576 1 /* $Id */2 1 /** @file 3 * HGCMMockUtils.h:Utility functions for the HGCM Mocking framework.2 * TstHGCMMockUtils.h - Utility functions for the HGCM Mocking framework. 4 3 * 5 4 * The utility functions are optional to the actual HGCM Mocking framework and … … 66 65 #endif 67 66 68 #include <iprt/err.h>69 #include <iprt/semaphore.h>70 #include <iprt/thread.h>71 #include <iprt/types.h>72 73 74 67 #include <VBox/GuestHost/HGCMMock.h> 75 #include <VBox/VBoxGuestLib.h>76 77 78 #if defined(IN_RING3) /* Only R3 parts implemented so far. */79 68 80 69 /** Pointer to a HGCM Mock utils context. */ … … 143 132 144 133 145 /*********************************************************************************************************************************146 * Prototypes. *147 *********************************************************************************************************************************/148 134 /** @name Context handling. 149 135 * @{ */ … … 171 157 172 158 173 /*********************************************************************************************************************************174 * Context *175 ********************************************************************************************************************************/176 /**177 * Initializes a HGCM Mock utils context.178 *179 * @param pCtx Context to intiialize.180 * @param pSvc HGCM Mock service instance to use.181 */182 void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc)183 {184 RT_BZERO(pCtx, sizeof(TSTHGCMUTILSCTX));185 186 pCtx->pSvc = pSvc;187 }188 189 190 /*********************************************************************************************************************************191 * Tasks *192 ********************************************************************************************************************************/193 /**194 * Returns the current task of a HGCM Mock utils context.195 *196 * @returns Current task of a HGCM Mock utils context. NULL if no current task found.197 * @param pCtx HGCM Mock utils context.198 */199 PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx)200 {201 /* Currently we only support one task at a time. */202 return &pCtx->Task;203 }204 205 /**206 * Initializes a HGCM Mock utils task.207 *208 * @returns VBox status code.209 * @param pTask Task to initialize.210 */211 int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask)212 {213 pTask->pvUser = NULL;214 pTask->rcCompleted = pTask->rcExpected = VERR_IPE_UNINITIALIZED_STATUS;215 return RTSemEventCreate(&pTask->hEvent);216 }217 218 /**219 * Destroys a HGCM Mock utils task.220 *221 * @returns VBox status code.222 * @param pTask Task to destroy.223 */224 void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask)225 {226 RTSemEventDestroy(pTask->hEvent);227 }228 229 /**230 * Waits for a HGCM Mock utils task to complete.231 *232 * @returns VBox status code.233 * @param pTask Task to wait for.234 * @param msTimeout Timeout (in ms) to wait.235 */236 int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout)237 {238 return RTSemEventWait(pTask->hEvent, msTimeout);239 }240 241 /**242 * Returns if the HGCM Mock utils task has been completed successfully.243 *244 * @returns \c true if successful, \c false if not.245 * @param pTask Task to check.246 */247 bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask)248 {249 return pTask->rcCompleted == pTask->rcExpected;250 }251 252 /**253 * Returns if the HGCM Mock utils task has been completed (failed or succeeded).254 *255 * @returns \c true if completed, \c false if (still) running.256 * @param pTask Task to check.257 */258 bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask)259 {260 return pTask->rcCompleted != VERR_IPE_UNINITIALIZED_STATUS;261 }262 263 /**264 * Signals a HGCM Mock utils task to complete its operation.265 *266 * @param pTask Task to complete.267 * @param rc Task result to set for completion.268 */269 void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc)270 {271 AssertMsg(pTask->rcCompleted == VERR_IPE_UNINITIALIZED_STATUS, ("Task already completed\n"));272 pTask->rcCompleted = rc;273 int rc2 = RTSemEventSignal(pTask->hEvent);274 AssertRC(rc2);275 }276 277 278 /*********************************************************************************************************************************279 * Threading *280 ********************************************************************************************************************************/281 282 /**283 * Thread worker for the guest side thread.284 *285 * @returns VBox status code.286 * @param hThread Thread handle.287 * @param pvUser Pointer of type PTSTHGCMUTILSCTX.288 *289 * @note Runs in the guest thread.290 */291 static DECLCALLBACK(int) tstHGCMUtilsGuestThread(RTTHREAD hThread, void *pvUser)292 {293 RT_NOREF(hThread);294 PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser;295 AssertPtr(pCtx);296 297 RTThreadUserSignal(hThread);298 299 if (pCtx->Guest.pfnThread)300 return pCtx->Guest.pfnThread(pCtx, pCtx->Guest.pvUser);301 302 return VINF_SUCCESS;303 }304 305 /**306 * Starts the guest side thread.307 *308 * @returns VBox status code.309 * @param pCtx HGCM Mock utils context to start guest thread for.310 * @param pFnThread Pointer to custom thread worker function to call within the guest side thread.311 * @param pvUser User-supplied pointer to guest thread context data. Optional and can be NULL.312 */313 int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser)314 {315 pCtx->Guest.pfnThread = pFnThread;316 pCtx->Guest.pvUser = pvUser;317 318 int rc = RTThreadCreate(&pCtx->Guest.hThread, tstHGCMUtilsGuestThread, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,319 "tstShClGst");320 if (RT_SUCCESS(rc))321 rc = RTThreadUserWait(pCtx->Guest.hThread, RT_MS_30SEC);322 323 return rc;324 }325 326 /**327 * Stops the guest side thread.328 *329 * @returns VBox status code.330 * @param pCtx HGCM Mock utils context to stop guest thread for.331 */332 int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx)333 {334 ASMAtomicWriteBool(&pCtx->Guest.fShutdown, true);335 336 int rcThread;337 int rc = RTThreadWait(pCtx->Guest.hThread, RT_MS_30SEC, &rcThread);338 if (RT_SUCCESS(rc))339 rc = rcThread;340 if (RT_SUCCESS(rc))341 pCtx->Guest.hThread = NIL_RTTHREAD;342 343 return rc;344 }345 346 /**347 * Thread worker function for the host side HGCM service.348 *349 * @returns VBox status code.350 * @param hThread Thread handle.351 * @param pvUser Pointer of type PTSTHGCMUTILSCTX.352 *353 * @note Runs in the host service thread.354 */355 static DECLCALLBACK(int) tstHGCMUtilsHostThreadWorker(RTTHREAD hThread, void *pvUser)356 {357 RT_NOREF(hThread);358 PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser;359 AssertPtr(pCtx);360 361 int rc = VINF_SUCCESS;362 363 RTThreadUserSignal(hThread);364 365 PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();366 367 for (;;)368 {369 if (ASMAtomicReadBool(&pCtx->Host.fShutdown))370 break;371 372 /* Wait for a new (mock) HGCM client to connect. */373 PTSTHGCMMOCKCLIENT pMockClient = TstHgcmMockSvcWaitForConnectEx(pSvc, 100 /* ms */);374 if (pMockClient) /* Might be NULL when timed out. */375 {376 if (pCtx->Host.Callbacks.pfnOnClientConnected)377 /* ignore rc */ pCtx->Host.Callbacks.pfnOnClientConnected(pCtx, pMockClient, pCtx->Host.pvUser);378 }379 }380 381 return rc;382 }383 384 /**385 * Starts the host side thread.386 *387 * @returns VBox status code.388 * @param pCtx HGCM Mock utils context to start host thread for.389 * @param pCallbacks Pointer to host callback table to use.390 * @param pvUser User-supplied pointer to reach into the host thread callbacks.391 */392 int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser)393 {394 memcpy(&pCtx->Host.Callbacks, pCallbacks, sizeof(TSTHGCMUTILSHOSTCALLBACKS));395 pCtx->Host.pvUser = pvUser;396 397 int rc = RTThreadCreate(&pCtx->Host.hThread, tstHGCMUtilsHostThreadWorker, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,398 "tstShClHst");399 if (RT_SUCCESS(rc))400 rc = RTThreadUserWait(pCtx->Host.hThread, RT_MS_30SEC);401 402 return rc;403 }404 405 /**406 * Stops the host side thread.407 *408 * @returns VBox status code.409 * @param pCtx HGCM Mock utils context to stop host thread for.410 */411 int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx)412 {413 ASMAtomicWriteBool(&pCtx->Host.fShutdown, true);414 415 int rcThread;416 int rc = RTThreadWait(pCtx->Host.hThread, RT_MS_30SEC, &rcThread);417 if (RT_SUCCESS(rc))418 rc = rcThread;419 if (RT_SUCCESS(rc))420 pCtx->Host.hThread = NIL_RTTHREAD;421 422 return rc;423 }424 425 #endif /* IN_RING3 */426 427 159 #endif /* !VBOX_INCLUDED_GuestHost_HGCMMockUtils_h */ 428 160
Note:
See TracChangeset
for help on using the changeset viewer.