VirtualBox

source: vbox/trunk/include/VBox/GuestHost/HGCMMockUtils.h@ 97782

Last change on this file since 97782 was 97274, checked in by vboxsync, 2 years ago

Validation Kit/HGCM: Added initial GuestHost/HGCMMockUtils.h. See header for docs [build fix].

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1/* $Id */
2/** @file
3 * HGCMMockUtils.h: Utility functions for the HGCM Mocking framework.
4 *
5 * The utility functions are optional to the actual HGCM Mocking framework and
6 * can support testcases which require a more advanced setup.
7 *
8 * With this one can setup host and guest side threads, which in turn can simulate
9 * specific host (i.e. HGCM service) + guest (i.e. like in the Guest Addditions
10 * via VbglR3) scenarios.
11 *
12 * Glossary:
13 *
14 * Host thread:
15 * - The host thread is used as part of the actual HGCM service being tested and
16 * provides callbacks (@see TSTHGCMUTILSHOSTCALLBACKS) for the unit test.
17 * Guest thread:
18 * - The guest thread is used as part of the guest side and mimics
19 * VBoxClient / VBoxTray / VBoxService parts. (i.e. for VbglR3 calls).
20 * Task:
21 * - A task is the simplest unit of test execution and used between the guest
22 * and host mocking threads.
23 *
24 ** @todo Add TstHGCMSimpleHost / TstHGCMSimpleGuest wrappers along those lines:
25 * Callback.pfnOnClientConnected = tstOnHostClientConnected()
26 * TstHGCMSimpleHostInitAndStart(&Callback)
27 * Callback.pfnOnConnected = tstOnGuestConnected()
28 * TstHGCMSimpleClientInitAndStart(&Callback)
29 */
30
31/*
32 * Copyright (C) 2022 Oracle and/or its affiliates.
33 *
34 * This file is part of VirtualBox base platform packages, as
35 * available from https://www.virtualbox.org.
36 *
37 * This program is free software; you can redistribute it and/or
38 * modify it under the terms of the GNU General Public License
39 * as published by the Free Software Foundation, in version 3 of the
40 * License.
41 *
42 * This program is distributed in the hope that it will be useful, but
43 * WITHOUT ANY WARRANTY; without even the implied warranty of
44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45 * General Public License for more details.
46 *
47 * You should have received a copy of the GNU General Public License
48 * along with this program; if not, see <https://www.gnu.org/licenses>.
49 *
50 * The contents of this file may alternatively be used under the terms
51 * of the Common Development and Distribution License Version 1.0
52 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
53 * in the VirtualBox distribution, in which case the provisions of the
54 * CDDL are applicable instead of those of the GPL.
55 *
56 * You may elect to license modified versions of this file under the
57 * terms and conditions of either the GPL or the CDDL or both.
58 *
59 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
60 */
61
62#ifndef VBOX_INCLUDED_GuestHost_HGCMMockUtils_h
63#define VBOX_INCLUDED_GuestHost_HGCMMockUtils_h
64#ifndef RT_WITHOUT_PRAGMA_ONCE
65# pragma once
66#endif
67
68#include <iprt/err.h>
69#include <iprt/semaphore.h>
70#include <iprt/thread.h>
71#include <iprt/types.h>
72
73
74#include <VBox/GuestHost/HGCMMock.h>
75#include <VBox/VBoxGuestLib.h>
76
77
78#if defined(IN_RING3) /* Only R3 parts implemented so far. */
79
80/** Pointer to a HGCM Mock utils context. */
81typedef struct TSTHGCMUTILSCTX *PTSTHGCMUTILSCTX;
82
83/**
84 * Structure for keeping a HGCM Mock utils host service callback table.
85 */
86typedef struct TSTHGCMUTILSHOSTCALLBACKS
87{
88 DECLCALLBACKMEMBER(int, pfnOnClientConnected,(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKCLIENT pClient, void *pvUser));
89} TSTHGCMUTILSHOSTCALLBACKS;
90/** Pointer to a HGCM Mock utils host callbacks table. */
91typedef TSTHGCMUTILSHOSTCALLBACKS *PTSTHGCMUTILSHOSTCALLBACKS;
92
93/**
94 * Structure for keeping a generic HGCM Mock utils task.
95 *
96 * A task is a single test unit / entity.
97 */
98typedef struct TSTHGCMUTILSTASK
99{
100 /** Completion event. */
101 RTSEMEVENT hEvent;
102 /** Completion rc.
103 * Set to VERR_IPE_UNINITIALIZED_STATUS if not completed yet. */
104 int rcCompleted;
105 /** Expected completion rc. */
106 int rcExpected;
107 /** Pointer to opaque (testcase-specific) task parameters.
108 * Might be NULL if not needed / used. */
109 void *pvUser;
110} TSTHGCMUTILSTASK;
111/** Pointer to a HGCM Mock utils task. */
112typedef TSTHGCMUTILSTASK *PTSTHGCMUTILSTASK;
113
114/** Callback function for HGCM Mock utils threads. */
115typedef DECLCALLBACKTYPE(int, FNTSTHGCMUTILSTHREAD,(PTSTHGCMUTILSCTX pCtx, void *pvUser));
116/** Pointer to a HGCM Mock utils guest thread callback. */
117typedef FNTSTHGCMUTILSTHREAD *PFNTSTHGCMUTILSTHREAD;
118
119/**
120 * Structure for keeping a HGCM Mock utils context.
121 */
122typedef struct TSTHGCMUTILSCTX
123{
124 /** Pointer to the HGCM Mock service instance to use. */
125 PTSTHGCMMOCKSVC pSvc;
126 /** Currently we only support one task at a time. */
127 TSTHGCMUTILSTASK Task;
128 struct
129 {
130 RTTHREAD hThread;
131 volatile bool fShutdown;
132 PFNTSTHGCMUTILSTHREAD pfnThread;
133 void *pvUser;
134 } Guest;
135 struct
136 {
137 RTTHREAD hThread;
138 volatile bool fShutdown;
139 TSTHGCMUTILSHOSTCALLBACKS Callbacks;
140 void *pvUser;
141 } Host;
142} TSTHGCMUTILSCTX;
143
144
145/*********************************************************************************************************************************
146* Prototypes. *
147*********************************************************************************************************************************/
148/** @name Context handling.
149 * @{ */
150void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc);
151/** @} */
152
153/** @name Task handling.
154 * @{ */
155PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx);
156int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask);
157void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask);
158int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout);
159bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask);
160bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask);
161void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc);
162/** @} */
163
164/** @name Threading.
165 * @{ */
166int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser);
167int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx);
168int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser);
169int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx);
170/** @} */
171
172
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 */
182void 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 */
199PTSTHGCMUTILSTASK 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 */
211int 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 */
224void 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 */
236int 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 */
247bool 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 */
258bool 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 */
269void 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 */
291static 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 */
313int 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 */
332int 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 */
355static 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 */
392int 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 */
411int 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#endif /* !VBOX_INCLUDED_GuestHost_HGCMMockUtils_h */
428
Note: See TracBrowser for help on using the repository browser.

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