VirtualBox

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

Last change on this file since 94521 was 93444, checked in by vboxsync, 2 years ago

VMM,Main,HostServices: Use a function table for accessing the VBoxVMM.dll/so/dylib functionality, and load it dynamically when the Console object is initialized. Also converted a few drivers in Main to use device helpers to get config values and such. bugref:10074

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

© 2023 Oracle
ContactPrivacy policyTerms of Use