VirtualBox

source: vbox/trunk/include/VBox/GuestHost/HGCMMock.h@ 94228

最後變更 在這個檔案從94228是 94228,由 vboxsync 提交於 3 年 前

Validation Kit/HGCM: Split out the HGCM testing (mocking) framework into an own header, added documentation, more code for generalizing this [build fix].

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 25.6 KB
 
1/* $Id: HGCMMock.h 94228 2022-03-14 19:19:18Z vboxsync $ */
2/** @file
3 * HGCMMock.h: Mocking framework for testing HGCM-based host services +
4 * Vbgl code on the host side.
5 *
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).
10 */
11
12/*
13 * Copyright (C) 2022 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.alldomusa.eu.org. This file is free software;
17 * you can redistribute it and/or modify it under the terms of the GNU
18 * General Public License (GPL) as published by the Free Software
19 * Foundation, in version 2 as it comes in the "COPYING" file of the
20 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22 *
23 * The contents of this file may alternatively be used under the terms
24 * of the Common Development and Distribution License Version 1.0
25 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
26 * VirtualBox OSE distribution, in which case the provisions of the
27 * CDDL are applicable instead of those of the GPL.
28 *
29 * You may elect to license modified versions of this file under the
30 * terms and conditions of either the GPL or the CDDL or both.
31 */
32
33#ifndef VBOX_INCLUDED_GuestHost_HGCMMock_h
34#define VBOX_INCLUDED_GuestHost_HGCMMock_h
35#ifndef RT_WITHOUT_PRAGMA_ONCE
36# pragma once
37#endif
38
39#include <iprt/types.h>
40
41#include <iprt/asm.h>
42#include <iprt/assert.h>
43#include <iprt/list.h>
44#include <iprt/mem.h>
45#include <iprt/rand.h>
46#include <iprt/semaphore.h>
47#include <iprt/test.h>
48#include <iprt/time.h>
49#include <iprt/thread.h>
50#include <iprt/utf16.h>
51
52#include <VBox/err.h>
53#include <VBox/VBoxGuestLib.h>
54#include <VBox/hgcmsvc.h>
55
56
57/*********************************************************************************************************************************
58* Definitions. *
59*********************************************************************************************************************************/
60
61#if defined(IN_RING3) /* Only R3 parts implemented so far. */
62
63extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable);
64
65# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL
66
67/** Simple call handle structure for the guest call completion callback. */
68typedef struct VBOXHGCMCALLHANDLE_TYPEDEF
69{
70 /** Where to store the result code on call completion. */
71 int32_t rc;
72} VBOXHGCMCALLHANDLE_TYPEDEF;
73
74/**
75 * Enumeration for a HGCM mock function type.
76 */
77typedef enum TSTHGCMMOCKFNTYPE
78{
79 TSTHGCMMOCKFNTYPE_NONE = 0,
80 TSTHGCMMOCKFNTYPE_CONNECT,
81 TSTHGCMMOCKFNTYPE_DISCONNECT,
82 TSTHGCMMOCKFNTYPE_CALL,
83 TSTHGCMMOCKFNTYPE_HOST_CALL
84} TSTHGCMMOCKFNTYPE;
85
86/** Pointer to a mock HGCM service. */
87typedef struct TSTHGCMMOCKSVC *PTSTHGCMMOCKSVC;
88
89/**
90 * Structure for mocking a server-side HGCM client.
91 */
92typedef struct TSTHGCMMOCKCLIENT
93{
94 /** Pointer to to mock service instance this client belongs to. */
95 PTSTHGCMMOCKSVC pSvc;
96 /** Assigned HGCM client ID. */
97 uint32_t idClient;
98 /** Opaque pointer to service-specific client data.
99 * Can be NULL if not being used. */
100 void *pvClient;
101 /** Size (in bytes) of \a pvClient. */
102 size_t cbClient;
103 /** The client's current HGCM call handle. */
104 VBOXHGCMCALLHANDLE_TYPEDEF hCall;
105 /** Whether the current client call has an asynchronous
106 * call pending or not. */
107 bool fAsyncExec;
108 /** Event semaphore to signal call completion. */
109 RTSEMEVENT hEvent;
110} TSTHGCMMOCKCLIENT;
111/** Pointer to a mock HGCM client. */
112typedef TSTHGCMMOCKCLIENT *PTSTHGCMMOCKCLIENT;
113
114/**
115 * Structure for keeping HGCM mock function parameters.
116 */
117typedef struct TSTHGCMMOCKFN
118{
119 /** List node for storing this struct into a queue. */
120 RTLISTNODE Node;
121 /** Function type. */
122 TSTHGCMMOCKFNTYPE enmType;
123 /** Pointer to associated client. */
124 PTSTHGCMMOCKCLIENT pClient;
125 /** Union keeping function-specific parameters,
126 * depending on \a enmType. */
127 union
128 {
129 struct
130 {
131 int32_t iFunc;
132 uint32_t cParms;
133 PVBOXHGCMSVCPARM pParms;
134 VBOXHGCMCALLHANDLE hCall;
135 } Call;
136 struct
137 {
138 int32_t iFunc;
139 uint32_t cParms;
140 PVBOXHGCMSVCPARM pParms;
141 } HostCall;
142 } u;
143} TSTHGCMMOCKFN;
144/** Pointer to a HGCM mock function parameters structure. */
145typedef TSTHGCMMOCKFN *PTSTHGCMMOCKFN;
146
147/**
148 * Structure for keeping a HGCM mock service instance.
149 */
150typedef struct TSTHGCMMOCKSVC
151{
152 /** HGCM helper table to use. */
153 VBOXHGCMSVCHELPERS fnHelpers;
154 /** HGCM service function table to use. */
155 VBOXHGCMSVCFNTABLE fnTable;
156 /** Next HGCM client ID to assign.
157 * 0 is considered as being invalid. */
158 HGCMCLIENTID uNextClientId;
159 /** Size (in bytes) of opaque pvClient area to reserve
160 * for a connected client. */
161 size_t cbClient;
162 /** Array of connected HGCM mock clients.
163 * Currently limited to 4 clients maximum. */
164 TSTHGCMMOCKCLIENT aHgcmClient[4];
165 /** Thread handle for the service's main loop. */
166 RTTHREAD hThread;
167 /** Event semaphore for signalling a message
168 * queue change. */
169 RTSEMEVENT hEventQueue;
170 /** Event semaphore for waiting on events, such
171 * as clients connecting. */
172 RTSEMEVENT hEventWait;
173 /** Number of current host calls being served.
174 * Currently limited to one call at a time. */
175 uint8_t cHostCallers;
176 /** Result code of last returned host call. */
177 int rcHostCall;
178 /** Event semaphore for host calls. */
179 RTSEMEVENT hEventHostCall;
180 /** List (queue) of function calls to process. */
181 RTLISTANCHOR lstCall;
182 /** Shutdown indicator flag. */
183 volatile bool fShutdown;
184} TSTHGCMMOCKSVC;
185
186/** Static HGCM service to mock. */
187static TSTHGCMMOCKSVC s_tstHgcmSvc;
188
189/*********************************************************************************************************************************
190* Prototypes. *
191*********************************************************************************************************************************/
192PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void);
193PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout);
194PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc);
195int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient);
196int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc);
197int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc);
198int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc);
199
200int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
201
202VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient);
203VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient);
204VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo);
205
206
207
208/*********************************************************************************************************************************
209* Internal functions *
210*********************************************************************************************************************************/
211
212/**
213 * Initializes a HGCM mock client.
214 *
215 * @return VBox status code.
216 * @param pClient Client instance to initialize.
217 * @param idClient HGCM client ID to assign.
218 * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate.
219 */
220static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient)
221{
222 RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT));
223
224 pClient->idClient = idClient;
225 if (cbClient)
226 {
227 pClient->pvClient = RTMemAllocZ(cbClient);
228 AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY);
229 pClient->cbClient = cbClient;
230 }
231
232 return RTSemEventCreate(&pClient->hEvent);
233}
234
235/**
236 * Destroys a HGCM mock client.
237 *
238 * @return VBox status code.
239 * @param pClient Client instance to destroy.
240 */
241static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient)
242{
243 int rc = RTSemEventDestroy(pClient->hEvent);
244 if (RT_SUCCESS(rc))
245 {
246 if (pClient->pvClient)
247 {
248 Assert(pClient->cbClient);
249 RTMemFree(pClient->pvClient);
250 pClient->pvClient = NULL;
251 pClient->cbClient = 0;
252 }
253
254 pClient->hEvent = NIL_RTSEMEVENT;
255 }
256
257 return rc;
258}
259
260/* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */
261static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient)
262{
263 RT_NOREF(pvService);
264
265 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
266 AssertPtrReturn(pFn, VERR_NO_MEMORY);
267
268 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId];
269
270 int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->cbClient);
271 if (RT_FAILURE(rc))
272 return rc;
273
274 pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT;
275 pFn->pClient = pClient;
276
277 RTListAppend(&pSvc->lstCall, &pFn->Node);
278 pFn = NULL; /* Thread takes ownership now. */
279
280 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
281 AssertRCReturn(rc2, rc2);
282 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
283 AssertRCReturn(rc2, rc2);
284
285 ASMAtomicIncU32(&pSvc->uNextClientId);
286
287 *pidClient = pClient->idClient;
288
289 return VINF_SUCCESS;
290}
291
292/* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */
293static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient)
294{
295 RT_NOREF(pvService);
296
297 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
298
299 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
300 AssertPtrReturn(pFn, VERR_NO_MEMORY);
301
302 pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT;
303 pFn->pClient = pClient;
304
305 RTListAppend(&pSvc->lstCall, &pFn->Node);
306 pFn = NULL; /* Thread takes ownership now. */
307
308 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
309 AssertRCReturn(rc2, rc2);
310
311 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
312 AssertRCReturn(rc2, rc2);
313
314 return tstHgcmMockClientDestroy(pClient);
315}
316
317/* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */
318static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient,
319 int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
320{
321 RT_NOREF(pvService, pvClient);
322
323 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
324
325 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
326 AssertPtrReturn(pFn, VERR_NO_MEMORY);
327
328 const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM);
329
330 pFn->enmType = TSTHGCMMOCKFNTYPE_CALL;
331 pFn->pClient = pClient;
332
333 pFn->u.Call.hCall = callHandle;
334 pFn->u.Call.iFunc = function;
335 pFn->u.Call.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms);
336 AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY);
337 pFn->u.Call.cParms = cParms;
338
339 RTListAppend(&pSvc->lstCall, &pFn->Node);
340
341 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
342 AssertRCReturn(rc2, rc2);
343
344 rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT);
345 AssertRCReturn(rc2, rc2);
346
347 memcpy(paParms, pFn->u.Call.pParms, cbParms);
348
349 return VINF_SUCCESS; /** @todo Return host call rc */
350}
351
352/* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */
353/** Note: Public for also being able to test host calls via testcases. */
354int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
355{
356 RT_NOREF(pvService);
357 AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */
358
359 pSvc->cHostCallers++;
360
361 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
362 AssertPtrReturn(pFn, VERR_INVALID_POINTER);
363
364 pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL;
365 pFn->u.HostCall.iFunc = function;
366 if (cParms)
367 {
368 pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM));
369 AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY);
370 pFn->u.HostCall.cParms = cParms;
371 }
372
373 RTListAppend(&pSvc->lstCall, &pFn->Node);
374 pFn = NULL; /* Thread takes ownership now. */
375
376 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
377 AssertRC(rc2);
378
379 rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT);
380 AssertRCReturn(rc2, rc2);
381
382 Assert(pSvc->cHostCallers);
383 pSvc->cHostCallers--;
384
385 return pSvc->rcHostCall;
386}
387
388/**
389 * Call completion callback for guest calls.
390 *
391 * @return VBox status code.
392 * @param callHandle Call handle to complete.
393 * @param rc Return code to return to the caller.
394 */
395static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
396{
397 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
398
399 size_t i = 0;
400 for (; RT_ELEMENTS(pSvc->aHgcmClient); i++)
401 {
402 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i];
403 if (&pClient->hCall == callHandle) /* Slow, but works for now. */
404 {
405 if (rc == VINF_HGCM_ASYNC_EXECUTE)
406 {
407 Assert(pClient->fAsyncExec == false);
408 }
409 else /* Complete call + notify client. */
410 {
411 callHandle->rc = rc;
412
413 int rc2 = RTSemEventSignal(pClient->hEvent);
414 AssertRCReturn(rc2, rc2);
415 }
416
417 return VINF_SUCCESS;
418 }
419 }
420
421 return VERR_NOT_FOUND;
422}
423
424/**
425 * Main thread of HGCM mock service.
426 *
427 * @return VBox status code.
428 * @param hThread Thread handle.
429 * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC.
430 */
431static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser)
432{
433 RT_NOREF(hThread);
434 PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser;
435
436 pSvc->uNextClientId = 0;
437
438 pSvc->fnTable.cbSize = sizeof(pSvc->fnTable);
439 pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION;
440
441 RT_ZERO(pSvc->fnHelpers);
442 pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete;
443 pSvc->fnTable.pHelpers = &pSvc->fnHelpers;
444
445 int rc = VBoxHGCMSvcLoad(&pSvc->fnTable);
446 if (RT_SUCCESS(rc))
447 {
448 RTThreadUserSignal(hThread);
449
450 for (;;)
451 {
452 rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */);
453 if (ASMAtomicReadBool(&pSvc->fShutdown))
454 {
455 rc = VINF_SUCCESS;
456 break;
457 }
458 if (rc == VERR_TIMEOUT)
459 continue;
460
461 PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node);
462 if (pFn)
463 {
464 switch (pFn->enmType)
465 {
466 case TSTHGCMMOCKFNTYPE_CONNECT:
467 {
468 rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService,
469 pFn->pClient->idClient, pFn->pClient->pvClient,
470 VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */);
471
472 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
473 AssertRC(rc2);
474 break;
475 }
476
477 case TSTHGCMMOCKFNTYPE_DISCONNECT:
478 {
479 rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService,
480 pFn->pClient->idClient, pFn->pClient->pvClient);
481
482 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
483 AssertRC(rc2);
484 break;
485 }
486
487 case TSTHGCMMOCKFNTYPE_CALL:
488 {
489 pSvc->fnTable.pfnCall(NULL, pFn->u.Call.hCall, pFn->pClient->idClient, pFn->pClient->pvClient,
490 pFn->u.Call.iFunc, pFn->u.Call.cParms, pFn->u.Call.pParms, RTTimeMilliTS());
491
492 /* Note: Call will be completed in the call completion callback. */
493 break;
494 }
495
496 case TSTHGCMMOCKFNTYPE_HOST_CALL:
497 {
498 pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(NULL, pFn->u.HostCall.iFunc, pFn->u.HostCall.cParms, pFn->u.HostCall.pParms);
499
500 int rc2 = RTSemEventSignal(pSvc->hEventHostCall);
501 AssertRC(rc2);
502 break;
503 }
504
505 default:
506 AssertFailed();
507 break;
508 }
509 RTListNodeRemove(&pFn->Node);
510 RTMemFree(pFn);
511 }
512 }
513 }
514
515 return rc;
516}
517
518
519/*********************************************************************************************************************************
520* Public functions *
521*********************************************************************************************************************************/
522
523/**
524 * Returns the pointer to the HGCM mock service instance.
525 *
526 * @return Pointer to HGCM mock service instance.
527 */
528PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void)
529{
530 return &s_tstHgcmSvc;
531}
532
533/**
534 * Waits for a HGCM mock client to connect, extended version.
535 *
536 * @return VBox status code.
537 * @param pSvc HGCM mock service instance.
538 * @param msTimeout Timeout (in ms) to wait for connection.
539 */
540PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout)
541{
542 int rc = RTSemEventWait(pSvc->hEventWait, msTimeout);
543 if (RT_SUCCESS(rc))
544 {
545 Assert(pSvc->uNextClientId);
546 return &pSvc->aHgcmClient[pSvc->uNextClientId - 1];
547 }
548 return NULL;
549}
550
551/**
552 * Waits for a HGCM mock client to connect.
553 *
554 * @return VBox status code.
555 * @param pSvc HGCM mock service instance.
556 */
557PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc)
558{
559 return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC);
560}
561
562/**
563 * Creates a HGCM mock service instance.
564 *
565 * @return VBox status code.
566 * @param pSvc HGCM mock service instance to create.
567 * @param cbClient Size (in bytes) of service-specific client data to
568 * allocate for a HGCM mock client.
569 */
570int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient)
571{
572 AssertReturn(cbClient, VERR_INVALID_PARAMETER);
573
574 RT_ZERO(pSvc->aHgcmClient);
575 pSvc->fShutdown = false;
576 int rc = RTSemEventCreate(&pSvc->hEventQueue);
577 if (RT_SUCCESS(rc))
578 {
579 rc = RTSemEventCreate(&pSvc->hEventHostCall);
580 if (RT_SUCCESS(rc))
581 {
582 rc = RTSemEventCreate(&pSvc->hEventWait);
583 if (RT_SUCCESS(rc))
584 {
585 RTListInit(&pSvc->lstCall);
586
587 pSvc->cbClient = cbClient;
588 }
589 }
590 }
591
592 return rc;
593}
594
595/**
596 * Destroys a HGCM mock service instance.
597 *
598 * @return VBox status code.
599 * @param pSvc HGCM mock service instance to destroy.
600 */
601int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc)
602{
603 int rc = RTSemEventDestroy(pSvc->hEventQueue);
604 if (RT_SUCCESS(rc))
605 {
606 rc = RTSemEventDestroy(pSvc->hEventHostCall);
607 if (RT_SUCCESS(rc))
608 RTSemEventDestroy(pSvc->hEventWait);
609 }
610 return rc;
611}
612
613/**
614 * Starts a HGCM mock service instance.
615 *
616 * @return VBox status code.
617 * @param pSvc HGCM mock service instance to start.
618 */
619int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc)
620{
621 int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
622 "MockSvc");
623 if (RT_SUCCESS(rc))
624 rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC);
625
626 return rc;
627}
628
629/**
630 * Stops a HGCM mock service instance.
631 *
632 * @return VBox status code.
633 * @param pSvc HGCM mock service instance to stop.
634 */
635int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc)
636{
637 ASMAtomicWriteBool(&pSvc->fShutdown, true);
638
639 int rcThread;
640 int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread);
641 if (RT_SUCCESS(rc))
642 rc = rcThread;
643 if (RT_SUCCESS(rc))
644 {
645 pSvc->hThread = NIL_RTTHREAD;
646 }
647
648 return rc;
649}
650
651
652/*********************************************************************************************************************************
653* VbglR3 stubs *
654*********************************************************************************************************************************/
655
656/**
657 * Connects to an HGCM mock service.
658 *
659 * @returns VBox status code
660 * @param pszServiceName Name of the host service.
661 * @param pidClient Where to put the client ID on success. The client ID
662 * must be passed to all the other calls to the service.
663 */
664VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient)
665{
666 RT_NOREF(pszServiceName);
667
668 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
669
670 return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient);
671}
672
673/**
674 * Disconnect from an HGCM mock service.
675 *
676 * @returns VBox status code.
677 * @param idClient The client id returned by VbglR3HGCMConnect().
678 */
679VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient)
680{
681 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
682
683 return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient);
684}
685
686/**
687 * Makes a fully prepared HGCM call to an HGCM mock service.
688 *
689 * @returns VBox status code.
690 * @param pInfo Fully prepared HGCM call info.
691 * @param cbInfo Size of the info. This may sometimes be larger than
692 * what the parameter count indicates because of
693 * parameter changes between versions and such.
694 */
695VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo)
696{
697 RT_NOREF(cbInfo);
698
699 AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo));
700 AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo));
701 Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo);
702
703 HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
704 PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM));
705
706 uint16_t i = 0;
707 for (; i < pInfo->cParms; i++)
708 {
709 switch (offSrcParms->type)
710 {
711 case VMMDevHGCMParmType_32bit:
712 {
713 paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT;
714 paDstParms[i].u.uint32 = offSrcParms->u.value32;
715 break;
716 }
717
718 case VMMDevHGCMParmType_64bit:
719 {
720 paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT;
721 paDstParms[i].u.uint64 = offSrcParms->u.value64;
722 break;
723 }
724
725 case VMMDevHGCMParmType_LinAddr:
726 {
727 paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR;
728 paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr;
729 paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb;
730 break;
731 }
732
733 default:
734 AssertFailed();
735 break;
736 }
737
738 offSrcParms++;
739 }
740
741 PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();
742
743 int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall,
744 pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient,
745 pInfo->u32Function, pInfo->cParms, paDstParms);
746 if (RT_SUCCESS(rc2))
747 {
748 offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
749
750 for (i = 0; i < pInfo->cParms; i++)
751 {
752 paDstParms[i].type = offSrcParms->type;
753 switch (paDstParms[i].type)
754 {
755 case VMMDevHGCMParmType_32bit:
756 offSrcParms->u.value32 = paDstParms[i].u.uint32;
757 break;
758
759 case VMMDevHGCMParmType_64bit:
760 offSrcParms->u.value64 = paDstParms[i].u.uint64;
761 break;
762
763 case VMMDevHGCMParmType_LinAddr:
764 {
765 offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size;
766 break;
767 }
768
769 default:
770 AssertFailed();
771 break;
772 }
773
774 offSrcParms++;
775 }
776 }
777
778 RTMemFree(paDstParms);
779
780 if (RT_SUCCESS(rc2))
781 rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc;
782
783 return rc2;
784}
785
786#endif /* IN_RING3 */
787
788#endif /* !VBOX_INCLUDED_GuestHost_HGCMMock_h */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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