VirtualBox

Changeset 98576 in vbox for trunk/include


Ignore:
Timestamp:
Feb 15, 2023 1:48:41 AM (2 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
155862
Message:

HGCMMock*.h: Split out the code into .cpp files.

Location:
trunk/include/VBox/GuestHost
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/GuestHost/HGCMMock.h

    r98574 r98576  
    1 /* $Id$ */
    21/** @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.
    53 *
    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.
    1010 */
    1111
     
    4747#endif
    4848
    49 #include <iprt/types.h>
     49#ifdef IN_RING3
    5050
    51 #include <iprt/asm.h>
    52 #include <iprt/assert.h>
    5351#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>
    6352#include <VBox/VBoxGuestLib.h>
    6453#include <VBox/hgcmsvc.h>
    6554
    66 
    67 /*********************************************************************************************************************************
    68 *  Definitions.                                                                                                                  *
    69 *********************************************************************************************************************************/
    70 
    71 #if defined(IN_RING3) /* Only R3 parts implemented so far. */
    72 
    73 RT_C_DECLS_BEGIN
    74 
    75 DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable);
    76 
    77 RT_C_DECLS_END
    78 
    79 # define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL
    8055
    8156/** Simple call handle structure for the guest call completion callback. */
     
    194169} TSTHGCMMOCKSVC;
    195170
    196 /** Static HGCM service to mock. */
    197 static TSTHGCMMOCKSVC g_tstHgcmSvc;
    198171
    199 
    200 /*********************************************************************************************************************************
    201 *  Prototypes.                                                                                                                   *
    202 *********************************************************************************************************************************/
    203172PTSTHGCMMOCKSVC    TstHgcmMockSvcInst(void);
    204173PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout);
     
    211180int                TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    212181
     182RT_C_DECLS_BEGIN
     183DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable);
     184RT_C_DECLS_END
     185
     186# undef VBGLR3DECL
     187# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL
    213188VBGLR3DECL(int)    VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient);
    214189VBGLR3DECL(int)    VbglR3HGCMDisconnect(HGCMCLIENTID idClient);
     
    217192
    218193
    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 a
    364      *         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 code
    673  * @param   pszServiceName  Name of the host service.
    674  * @param   pidClient       Where to put the client ID on success. The client ID
    675  *                          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 than
    718  *                          what the parameter count indicates because of
    719  *                          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 
    812194#endif /* IN_RING3 */
    813195
  • trunk/include/VBox/GuestHost/HGCMMockUtils.h

    r98103 r98576  
    1 /* $Id */
    21/** @file
    3  * HGCMMockUtils.h: Utility functions for the HGCM Mocking framework.
     2 * TstHGCMMockUtils.h - Utility functions for the HGCM Mocking framework.
    43 *
    54 * The utility functions are optional to the actual HGCM Mocking framework and
     
    6665#endif
    6766
    68 #include <iprt/err.h>
    69 #include <iprt/semaphore.h>
    70 #include <iprt/thread.h>
    71 #include <iprt/types.h>
    72 
    73 
    7467#include <VBox/GuestHost/HGCMMock.h>
    75 #include <VBox/VBoxGuestLib.h>
    76 
    77 
    78 #if defined(IN_RING3) /* Only R3 parts implemented so far. */
    7968
    8069/** Pointer to a HGCM Mock utils context. */
     
    143132
    144133
    145 /*********************************************************************************************************************************
    146 *  Prototypes.                                                                                                                   *
    147 *********************************************************************************************************************************/
    148134/** @name Context handling.
    149135 * @{ */
     
    171157
    172158
    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 
    427159#endif /* !VBOX_INCLUDED_GuestHost_HGCMMockUtils_h */
    428160
Note: See TracChangeset for help on using the changeset viewer.

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