VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/HGCMThread.cpp@ 107491

Last change on this file since 107491 was 107427, checked in by vboxsync, 2 weeks ago

HGCMThread.cpp: Fixed a warning found by Parfait. ​jiraref:VBP-1424

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.4 KB
Line 
1/* $Id: HGCMThread.cpp 107427 2025-01-06 16:59:33Z vboxsync $ */
2/** @file
3 * HGCMThread - Host-Guest Communication Manager Threads
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_HGCM
29#include "LoggingNew.h"
30
31#include "HGCMThread.h"
32
33#include <VBox/err.h>
34#include <VBox/vmm/stam.h>
35#include <VBox/vmm/vmmr3vtable.h>
36#include <iprt/semaphore.h>
37#include <iprt/thread.h>
38#include <iprt/string.h>
39
40#include <new> /* for std:nothrow */
41
42
43/* HGCM uses worker threads, which process messages from other threads.
44 * A message consists of the message header and message specific data.
45 * Message header is opaque for callers, but message data is defined
46 * and used by them.
47 *
48 * Messages are distinguished by message identifier and worker thread
49 * they are allocated for.
50 *
51 * Messages are allocated for a worker thread and belong to
52 * the thread. A worker thread holds the queue of messages.
53 *
54 * The calling thread creates a message, specifying which worker thread
55 * the message is created for, then, optionally, initializes message
56 * specific data and, also optionally, references the message.
57 *
58 * Message then is posted or sent to worker thread by inserting
59 * it to the worker thread message queue and referencing the message.
60 * Worker thread then again may fetch next message.
61 *
62 * Upon processing the message the worker thread dereferences it.
63 * Dereferencing also automatically deletes message from the thread
64 * queue and frees memory allocated for the message, if no more
65 * references left. If there are references, the message remains
66 * in the queue.
67 *
68 */
69
70/* Version of HGCM message header */
71#define HGCMMSG_VERSION (1)
72
73/* Thread is initializing. */
74#define HGCMMSG_TF_INITIALIZING (0x00000001)
75/* Thread must be terminated. */
76#define HGCMMSG_TF_TERMINATE (0x00000002)
77/* Thread has been terminated. */
78#define HGCMMSG_TF_TERMINATED (0x00000004)
79
80/** @todo consider use of RTReq */
81
82static DECLCALLBACK(int) hgcmWorkerThreadFunc(RTTHREAD ThreadSelf, void *pvUser);
83
84class HGCMThread : public HGCMReferencedObject
85{
86 private:
87 friend DECLCALLBACK(int) hgcmWorkerThreadFunc(RTTHREAD ThreadSelf, void *pvUser);
88
89 /* Worker thread function. */
90 PFNHGCMTHREAD m_pfnThread;
91
92 /* A user supplied thread parameter. */
93 void *m_pvUser;
94
95 /* The thread runtime handle. */
96 RTTHREAD m_hThread;
97
98 /** Event the thread waits for, signalled when a message to process is posted to
99 * the thread, automatically reset. */
100 RTSEMEVENT m_eventThread;
101
102 /* A caller thread waits for completion of a SENT message on this event. */
103 RTSEMEVENTMULTI m_eventSend;
104 int32_t volatile m_i32MessagesProcessed;
105
106 /* Critical section for accessing the thread data, mostly for message queues. */
107 RTCRITSECT m_critsect;
108
109 /* thread state/operation flags */
110 uint32_t m_fu32ThreadFlags;
111
112 /* Message queue variables. Messages are inserted at tail of message
113 * queue. They are consumed by worker thread sequentially. If a message was
114 * consumed, it is removed from message queue.
115 */
116
117 /* Head of message queue. */
118 HGCMMsgCore *m_pMsgInputQueueHead;
119 /* Message which another message will be inserted after. */
120 HGCMMsgCore *m_pMsgInputQueueTail;
121
122 /* Head of messages being processed queue. */
123 HGCMMsgCore *m_pMsgInProcessHead;
124 /* Message which another message will be inserted after. */
125 HGCMMsgCore *m_pMsgInProcessTail;
126
127 /* Head of free message structures list. */
128 HGCMMsgCore *m_pFreeHead;
129 /* Tail of free message structures list. */
130 HGCMMsgCore *m_pFreeTail;
131
132 /** @name Statistics
133 * @{ */
134 STAMCOUNTER m_StatPostMsgNoPending;
135 STAMCOUNTER m_StatPostMsgOnePending;
136 STAMCOUNTER m_StatPostMsgTwoPending;
137 STAMCOUNTER m_StatPostMsgThreePending;
138 STAMCOUNTER m_StatPostMsgManyPending;
139 /** @} */
140
141 inline int Enter(void);
142 inline void Leave(void);
143
144 HGCMMsgCore *FetchFreeListHead(void);
145
146 protected:
147 virtual ~HGCMThread(void);
148
149 public:
150
151 HGCMThread ();
152
153 int WaitForTermination (void);
154
155 int Initialize(const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser,
156 const char *pszStatsSubDir, PUVM pUVM, PCVMMR3VTABLE pVMM);
157
158 int MsgAlloc(HGCMMsgCore **pMsg, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage);
159 int MsgGet(HGCMMsgCore **ppMsg);
160 int MsgPost(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback, bool bWait);
161 int MsgComplete(HGCMMsgCore *pMsg, int32_t result);
162};
163
164
165/*
166 * HGCMMsgCore implementation.
167 */
168
169#define HGCM_MSG_F_PROCESSED (0x00000001)
170#define HGCM_MSG_F_WAIT (0x00000002)
171#define HGCM_MSG_F_IN_PROCESS (0x00000004)
172
173void HGCMMsgCore::InitializeCore(uint32_t u32MsgId, HGCMThread *pThread)
174{
175 m_u32Version = HGCMMSG_VERSION;
176 m_u32Msg = u32MsgId;
177 m_pfnCallback = NULL;
178 m_pNext = NULL;
179 m_pPrev = NULL;
180 m_fu32Flags = 0;
181 m_vrcSend = VINF_SUCCESS;
182 m_pThread = pThread;
183 pThread->Reference();
184}
185
186/* virtual */ HGCMMsgCore::~HGCMMsgCore()
187{
188 if (m_pThread)
189 {
190 m_pThread->Dereference();
191 m_pThread = NULL;
192 }
193}
194
195/*
196 * HGCMThread implementation.
197 */
198
199static DECLCALLBACK(int) hgcmWorkerThreadFunc(RTTHREAD hThreadSelf, void *pvUser)
200{
201 HGCMThread *pThread = (HGCMThread *)pvUser;
202
203 LogFlow(("MAIN::hgcmWorkerThreadFunc: starting HGCM thread %p\n", pThread));
204
205 AssertRelease(pThread);
206
207 pThread->m_hThread = hThreadSelf;
208 pThread->m_fu32ThreadFlags &= ~HGCMMSG_TF_INITIALIZING;
209 int vrc = RTThreadUserSignal(hThreadSelf);
210 AssertRC(vrc);
211
212 pThread->m_pfnThread(pThread, pThread->m_pvUser);
213
214 pThread->m_fu32ThreadFlags |= HGCMMSG_TF_TERMINATED;
215
216 LogFlow(("MAIN::hgcmWorkerThreadFunc: completed HGCM thread %p\n", pThread));
217
218 return vrc;
219}
220
221HGCMThread::HGCMThread()
222 :
223 HGCMReferencedObject(HGCMOBJ_THREAD),
224 m_pfnThread(NULL),
225 m_pvUser(NULL),
226 m_hThread(NIL_RTTHREAD),
227 m_eventThread(NIL_RTSEMEVENT),
228 m_eventSend(NIL_RTSEMEVENTMULTI),
229 m_i32MessagesProcessed(0),
230 m_fu32ThreadFlags(0),
231 m_pMsgInputQueueHead(NULL),
232 m_pMsgInputQueueTail(NULL),
233 m_pMsgInProcessHead(NULL),
234 m_pMsgInProcessTail(NULL),
235 m_pFreeHead(NULL),
236 m_pFreeTail(NULL)
237{
238 RT_ZERO(m_critsect);
239}
240
241HGCMThread::~HGCMThread()
242{
243 /*
244 * Free resources allocated for the thread.
245 */
246
247 Assert(m_fu32ThreadFlags & HGCMMSG_TF_TERMINATED);
248
249 if (RTCritSectIsInitialized(&m_critsect))
250 RTCritSectDelete(&m_critsect);
251
252 if (m_eventSend != NIL_RTSEMEVENTMULTI)
253 {
254 RTSemEventMultiDestroy(m_eventSend);
255 m_eventSend = NIL_RTSEMEVENTMULTI;
256 }
257
258 if (m_eventThread != NIL_RTSEMEVENT)
259 {
260 RTSemEventDestroy(m_eventThread);
261 m_eventThread = NIL_RTSEMEVENT;
262 }
263}
264
265int HGCMThread::WaitForTermination(void)
266{
267 int vrc = VINF_SUCCESS;
268 LogFlowFunc(("\n"));
269
270 if (m_hThread != NIL_RTTHREAD)
271 {
272 vrc = RTThreadWait(m_hThread, 5000, NULL);
273 m_hThread = NIL_RTTHREAD;
274 }
275
276 LogFlowFunc(("vrc = %Rrc\n", vrc));
277 return vrc;
278}
279
280int HGCMThread::Initialize(const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser,
281 const char *pszStatsSubDir, PUVM pUVM, PCVMMR3VTABLE pVMM)
282{
283 int vrc = RTSemEventCreate(&m_eventThread);
284
285 if (RT_SUCCESS(vrc))
286 {
287 vrc = RTSemEventMultiCreate(&m_eventSend);
288
289 if (RT_SUCCESS(vrc))
290 {
291 vrc = RTCritSectInit(&m_critsect);
292
293 if (RT_SUCCESS(vrc))
294 {
295 m_pfnThread = pfnThread;
296 m_pvUser = pvUser;
297
298 m_fu32ThreadFlags = HGCMMSG_TF_INITIALIZING;
299
300 RTTHREAD hThread;
301 vrc = RTThreadCreate(&hThread, hgcmWorkerThreadFunc, this, 0, /* default stack size; some services
302 may need quite a bit */
303 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
304 pszThreadName);
305
306 if (RT_SUCCESS(vrc))
307 {
308 /* Register statistics while the thread starts. */
309 if (pUVM)
310 {
311 pVMM->pfnSTAMR3RegisterFU(pUVM, &m_StatPostMsgNoPending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
312 STAMUNIT_COUNT, "Times a message was appended to an empty input queue.",
313 "/HGCM/%s/PostMsg0Pending", pszStatsSubDir);
314 pVMM->pfnSTAMR3RegisterFU(pUVM, &m_StatPostMsgOnePending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
315 STAMUNIT_COUNT,
316 "Times a message was appended to input queue with only one pending message.",
317 "/HGCM/%s/PostMsg1Pending", pszStatsSubDir);
318 pVMM->pfnSTAMR3RegisterFU(pUVM, &m_StatPostMsgTwoPending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
319 STAMUNIT_COUNT,
320 "Times a message was appended to input queue with two pending messages.",
321 "/HGCM/%s/PostMsg2Pending", pszStatsSubDir);
322 pVMM->pfnSTAMR3RegisterFU(pUVM, &m_StatPostMsgThreePending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
323 STAMUNIT_COUNT,
324 "Times a message was appended to input queue with three pending messages.",
325 "/HGCM/%s/PostMsg3Pending", pszStatsSubDir);
326 pVMM->pfnSTAMR3RegisterFU(pUVM, &m_StatPostMsgManyPending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
327 STAMUNIT_COUNT,
328 "Times a message was appended to input queue with >3 pending messages.",
329 "/HGCM/%s/PostMsgManyPending", pszStatsSubDir);
330 }
331
332 /* Wait until the thread is ready. */
333 vrc = RTThreadUserWait(hThread, 30000);
334 AssertRC(vrc);
335 Assert(!(m_fu32ThreadFlags & HGCMMSG_TF_INITIALIZING) || RT_FAILURE(vrc));
336 }
337 else
338 {
339 m_hThread = NIL_RTTHREAD;
340 Log(("hgcmThreadCreate: FAILURE: Can't start worker thread.\n"));
341 }
342 }
343 else
344 {
345 Log(("hgcmThreadCreate: FAILURE: Can't init a critical section for a hgcm worker thread.\n"));
346 RT_ZERO(m_critsect);
347 }
348 }
349 else
350 {
351 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a sent messages.\n"));
352 m_eventSend = NIL_RTSEMEVENTMULTI;
353 }
354 }
355 else
356 {
357 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a hgcm worker thread.\n"));
358 m_eventThread = NIL_RTSEMEVENT;
359 }
360
361 return vrc;
362}
363
364inline int HGCMThread::Enter(void)
365{
366 int vrc = RTCritSectEnter(&m_critsect);
367
368#ifdef LOG_ENABLED
369 if (RT_FAILURE(vrc))
370 Log(("HGCMThread::MsgPost: FAILURE: could not obtain worker thread mutex, vrc = %Rrc!!!\n", vrc));
371#endif
372
373 return vrc;
374}
375
376inline void HGCMThread::Leave(void)
377{
378 RTCritSectLeave(&m_critsect);
379}
380
381
382int HGCMThread::MsgAlloc(HGCMMsgCore **ppMsg, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
383{
384 /** @todo Implement this free list / cache thingy. */
385 HGCMMsgCore *pmsg = NULL;
386
387 bool fFromFreeList = false;
388
389 if (!pmsg)
390 {
391 /* We have to allocate a new memory block. */
392 pmsg = pfnNewMessage(u32MsgId);
393 if (pmsg != NULL)
394 pmsg->Reference(); /* (it's created with zero references) */
395 else
396 return VERR_NO_MEMORY;
397 }
398
399 /* Initialize just allocated message core */
400 pmsg->InitializeCore(u32MsgId, this);
401
402 /* and the message specific data. */
403 pmsg->Initialize();
404
405 LogFlow(("MAIN::hgcmMsgAlloc: allocated message %p\n", pmsg));
406
407 *ppMsg = pmsg;
408
409 if (fFromFreeList)
410 {
411 /* Message was referenced in the free list, now dereference it. */
412 pmsg->Dereference();
413 }
414
415 return VINF_SUCCESS;
416}
417
418int HGCMThread::MsgPost(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback, bool fWait)
419{
420 LogFlow(("HGCMThread::MsgPost: thread = %p, pMsg = %p, pfnCallback = %p\n", this, pMsg, pfnCallback));
421
422 int vrc = Enter();
423
424 if (RT_SUCCESS(vrc))
425 {
426 pMsg->m_pfnCallback = pfnCallback;
427
428 if (fWait)
429 pMsg->m_fu32Flags |= HGCM_MSG_F_WAIT;
430
431 /* Insert the message to the queue tail. */
432 pMsg->m_pNext = NULL;
433 HGCMMsgCore * const pPrev = m_pMsgInputQueueTail;
434 pMsg->m_pPrev = pPrev;
435
436 if (pPrev)
437 {
438 pPrev->m_pNext = pMsg;
439 if (!pPrev->m_pPrev)
440 STAM_REL_COUNTER_INC(&m_StatPostMsgOnePending);
441 else if (!pPrev->m_pPrev->m_pPrev)
442 STAM_REL_COUNTER_INC(&m_StatPostMsgTwoPending);
443 else if (!pPrev->m_pPrev->m_pPrev->m_pPrev)
444 STAM_REL_COUNTER_INC(&m_StatPostMsgThreePending);
445 else
446 STAM_REL_COUNTER_INC(&m_StatPostMsgManyPending);
447 }
448 else
449 {
450 m_pMsgInputQueueHead = pMsg;
451 STAM_REL_COUNTER_INC(&m_StatPostMsgNoPending);
452 }
453
454 m_pMsgInputQueueTail = pMsg;
455
456 Leave();
457
458 LogFlow(("HGCMThread::MsgPost: going to inform the thread %p about message, fWait = %d\n", this, fWait));
459
460 /* Inform the worker thread that there is a message. */
461 RTSemEventSignal(m_eventThread);
462
463 LogFlow(("HGCMThread::MsgPost: event signalled\n"));
464
465 if (fWait)
466 {
467 /* Immediately check if the message has been processed. */
468 while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
469 {
470 /* Poll infrequently to make sure no completed message has been missed. */
471 RTSemEventMultiWait(m_eventSend, 1000);
472
473 LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags));
474
475 if ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
476 RTThreadYield();
477 }
478
479 /* 'Our' message has been processed, so should reset the semaphore.
480 * There is still possible that another message has been processed
481 * and the semaphore has been signalled again.
482 * Reset only if there are no other messages completed.
483 */
484 int32_t c = ASMAtomicDecS32(&m_i32MessagesProcessed);
485 Assert(c >= 0);
486 if (c == 0)
487 RTSemEventMultiReset(m_eventSend);
488
489 vrc = pMsg->m_vrcSend;
490 }
491 }
492
493 LogFlow(("HGCMThread::MsgPost: vrc = %Rrc\n", vrc));
494 return vrc;
495}
496
497
498int HGCMThread::MsgGet(HGCMMsgCore **ppMsg)
499{
500 int vrc = VINF_SUCCESS;
501
502 LogFlow(("HGCMThread::MsgGet: thread = %p, ppMsg = %p\n", this, ppMsg));
503
504 for (;;)
505 {
506 if (m_fu32ThreadFlags & HGCMMSG_TF_TERMINATE)
507 {
508 vrc = VERR_INTERRUPTED;
509 break;
510 }
511
512 LogFlow(("MAIN::hgcmMsgGet: m_pMsgInputQueueHead = %p\n", m_pMsgInputQueueHead));
513
514 if (m_pMsgInputQueueHead)
515 {
516 /* Move the message to the m_pMsgInProcessHead list */
517 vrc = Enter();
518
519 if (RT_FAILURE(vrc))
520 {
521 break;
522 }
523
524 HGCMMsgCore *pMsg = m_pMsgInputQueueHead;
525
526 /* Remove the message from the head of Queue list. */
527 Assert(m_pMsgInputQueueHead->m_pPrev == NULL);
528
529 if (m_pMsgInputQueueHead->m_pNext)
530 {
531 m_pMsgInputQueueHead = m_pMsgInputQueueHead->m_pNext;
532 m_pMsgInputQueueHead->m_pPrev = NULL;
533 }
534 else
535 {
536 Assert(m_pMsgInputQueueHead == m_pMsgInputQueueTail);
537
538 m_pMsgInputQueueHead = NULL;
539 m_pMsgInputQueueTail = NULL;
540 }
541
542 /* Insert the message to the tail of the m_pMsgInProcessHead list. */
543 pMsg->m_pNext = NULL;
544 pMsg->m_pPrev = m_pMsgInProcessTail;
545
546 if (m_pMsgInProcessTail)
547 m_pMsgInProcessTail->m_pNext = pMsg;
548 else
549 m_pMsgInProcessHead = pMsg;
550
551 m_pMsgInProcessTail = pMsg;
552
553 pMsg->m_fu32Flags |= HGCM_MSG_F_IN_PROCESS;
554
555 Leave();
556
557 /* Return the message to the caller. */
558 *ppMsg = pMsg;
559
560 LogFlow(("MAIN::hgcmMsgGet: got message %p\n", *ppMsg));
561
562 break;
563 }
564
565 /* Wait for an event. */
566 RTSemEventWait(m_eventThread, RT_INDEFINITE_WAIT);
567 }
568
569 LogFlow(("HGCMThread::MsgGet: *ppMsg = %p, return vrc = %Rrc\n", *ppMsg, vrc));
570 return vrc;
571}
572
573int HGCMThread::MsgComplete(HGCMMsgCore *pMsg, int32_t vrcResult)
574{
575 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p, vrcResult = %Rrc (%d)\n", this, pMsg, vrcResult, vrcResult));
576
577 AssertRelease(pMsg->m_pThread == this);
578 AssertReleaseMsg((pMsg->m_fu32Flags & HGCM_MSG_F_IN_PROCESS) != 0, ("%p %x\n", pMsg, pMsg->m_fu32Flags));
579
580 int vrcRet = VINF_SUCCESS;
581 if (pMsg->m_pfnCallback)
582 {
583 /** @todo call callback with error code in MsgPost in case of errors */
584
585 vrcRet = pMsg->m_pfnCallback(vrcResult, pMsg);
586
587 LogFlow(("HGCMThread::MsgComplete: callback executed. pMsg = %p, thread = %p, rcRet = %Rrc\n", pMsg, this, vrcRet));
588 }
589
590 /* Message processing has been completed. */
591
592 int vrc = Enter();
593
594 if (RT_SUCCESS(vrc))
595 {
596 /* Remove the message from the InProcess queue. */
597
598 if (pMsg->m_pNext)
599 pMsg->m_pNext->m_pPrev = pMsg->m_pPrev;
600 else
601 m_pMsgInProcessTail = pMsg->m_pPrev;
602
603 if (pMsg->m_pPrev)
604 pMsg->m_pPrev->m_pNext = pMsg->m_pNext;
605 else
606 m_pMsgInProcessHead = pMsg->m_pNext;
607
608 pMsg->m_pNext = NULL;
609 pMsg->m_pPrev = NULL;
610
611 bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0);
612
613 if (fWaited)
614 {
615 ASMAtomicIncS32(&m_i32MessagesProcessed);
616
617 /* This should be done before setting the HGCM_MSG_F_PROCESSED flag. */
618 pMsg->m_vrcSend = vrcResult;
619 }
620
621 /* The message is now completed. */
622 pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS;
623 pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT;
624 pMsg->m_fu32Flags |= HGCM_MSG_F_PROCESSED;
625
626 pMsg->Dereference();
627
628 Leave();
629
630 if (fWaited)
631 {
632 /* Wake up all waiters. so they can decide if their message has been processed. */
633 RTSemEventMultiSignal(m_eventSend);
634 }
635 }
636
637 return vrcRet;
638}
639
640/*
641 * Thread API. Public interface.
642 */
643
644int hgcmThreadCreate(HGCMThread **ppThread, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser,
645 const char *pszStatsSubDir, PUVM pUVM, PCVMMR3VTABLE pVMM)
646{
647 LogFlow(("MAIN::hgcmThreadCreate\n"));
648 int vrc;
649
650 /* Allocate memory for a new thread object. */
651 HGCMThread *pThread = new (std::nothrow) HGCMThread();
652
653 if (pThread)
654 {
655 pThread->Reference(); /* (it's created with zero references) */
656
657 /* Initialize the object. */
658 vrc = pThread->Initialize(pszThreadName, pfnThread, pvUser, pszStatsSubDir, pUVM, pVMM);
659 if (RT_SUCCESS(vrc))
660 {
661 *ppThread = pThread;
662 LogFlow(("MAIN::hgcmThreadCreate: vrc = %Rrc\n", vrc));
663 return vrc;
664 }
665
666 Log(("hgcmThreadCreate: FAILURE: Initialize failed: vrc = %Rrc\n", vrc));
667
668 pThread->Dereference();
669 }
670 else
671 {
672 Log(("hgcmThreadCreate: FAILURE: Can't allocate memory for a hgcm worker thread.\n"));
673 vrc = VERR_NO_MEMORY;
674 }
675 *ppThread = NULL;
676
677 LogFlow(("MAIN::hgcmThreadCreate: vrc = %Rrc\n", vrc));
678 return vrc;
679}
680
681int hgcmThreadWait(HGCMThread *pThread)
682{
683 LogFlowFunc(("%p\n", pThread));
684
685 int vrc;
686 if (pThread)
687 {
688 vrc = pThread->WaitForTermination();
689
690 pThread->Dereference();
691 }
692 else
693 vrc = VERR_INVALID_HANDLE;
694
695 LogFlowFunc(("vrc = %Rrc\n", vrc));
696 return vrc;
697}
698
699int hgcmMsgAlloc(HGCMThread *pThread, HGCMMsgCore **ppMsg, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
700{
701 LogFlow(("hgcmMsgAlloc: pThread = %p, ppMsg = %p, sizeof (HGCMMsgCore) = %d\n", pThread, ppMsg, sizeof(HGCMMsgCore)));
702
703 AssertReturn(pThread, VERR_INVALID_HANDLE);
704 AssertReturn(ppMsg, VERR_INVALID_PARAMETER);
705
706 int vrc = pThread->MsgAlloc(ppMsg, u32MsgId, pfnNewMessage);
707
708 LogFlow(("MAIN::hgcmMsgAlloc: *ppMsg = %p, vrc = %Rrc\n", *ppMsg, vrc));
709 return vrc;
710}
711
712DECLINLINE(int) hgcmMsgPostInternal(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback, bool fWait)
713{
714 LogFlow(("MAIN::hgcmMsgPostInternal: pMsg = %p, pfnCallback = %p, fWait = %d\n", pMsg, pfnCallback, fWait));
715 Assert(pMsg);
716
717 pMsg->Reference(); /* paranoia? */
718
719 int vrc = pMsg->Thread()->MsgPost(pMsg, pfnCallback, fWait);
720
721 pMsg->Dereference();
722
723 LogFlow(("MAIN::hgcmMsgPostInternal: pMsg = %p, vrc = %Rrc\n", pMsg, vrc));
724 return vrc;
725}
726
727int hgcmMsgPost(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback)
728{
729 int vrc = hgcmMsgPostInternal(pMsg, pfnCallback, false);
730
731 if (RT_SUCCESS(vrc))
732 vrc = VINF_HGCM_ASYNC_EXECUTE;
733
734 return vrc;
735}
736
737int hgcmMsgSend(HGCMMsgCore *pMsg)
738{
739 return hgcmMsgPostInternal(pMsg, NULL, true);
740}
741
742int hgcmMsgGet(HGCMThread *pThread, HGCMMsgCore **ppMsg)
743{
744 LogFlow(("MAIN::hgcmMsgGet: pThread = %p, ppMsg = %p\n", pThread, ppMsg));
745
746 AssertReturn(pThread, VERR_INVALID_HANDLE);
747 AssertReturn(ppMsg, VERR_INVALID_PARAMETER);
748
749 pThread->Reference(); /* paranoia */
750
751 int vrc = pThread->MsgGet(ppMsg);
752
753 pThread->Dereference();
754
755 LogFlow(("MAIN::hgcmMsgGet: *ppMsg = %p, vrc = %Rrc\n", *ppMsg, vrc));
756 return vrc;
757}
758
759int hgcmMsgComplete(HGCMMsgCore *pMsg, int32_t vrcMsg)
760{
761 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, vrcMsg = %Rrc (%d)\n", pMsg, vrcMsg, vrcMsg));
762
763 int vrc;
764 if (pMsg)
765 vrc = pMsg->Thread()->MsgComplete(pMsg, vrcMsg);
766 else
767 vrc = VINF_SUCCESS;
768
769 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, vrcMsg =%Rrc (%d), returns vrc = %Rrc\n", pMsg, vrcMsg, vrcMsg, vrc));
770 return vrc;
771}
772
773int hgcmThreadInit(void)
774{
775 LogFlow(("MAIN::hgcmThreadInit\n"));
776
777 /** @todo error processing. */
778
779 int vrc = hgcmObjInit();
780
781 LogFlow(("MAIN::hgcmThreadInit: vrc = %Rrc\n", vrc));
782 return vrc;
783}
784
785void hgcmThreadUninit(void)
786{
787 hgcmObjUninit();
788}
789
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