VirtualBox

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

Last change on this file since 98273 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • 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 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * HGCMThread - Host-Guest Communication Manager Threads
4 */
5
6/*
7 * Copyright (C) 2006-2023 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_rcSend = 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 only one pending message.",
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 only one pending message.",
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 only one pending message.",
329 "/HGCM/%s/PostMsgManyPending", pszStatsSubDir);
330 }
331
332
333 /* Wait until the thread is ready. */
334 vrc = RTThreadUserWait(hThread, 30000);
335 AssertRC(vrc);
336 Assert(!(m_fu32ThreadFlags & HGCMMSG_TF_INITIALIZING) || RT_FAILURE(vrc));
337 }
338 else
339 {
340 m_hThread = NIL_RTTHREAD;
341 Log(("hgcmThreadCreate: FAILURE: Can't start worker thread.\n"));
342 }
343 }
344 else
345 {
346 Log(("hgcmThreadCreate: FAILURE: Can't init a critical section for a hgcm worker thread.\n"));
347 RT_ZERO(m_critsect);
348 }
349 }
350 else
351 {
352 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a sent messages.\n"));
353 m_eventSend = NIL_RTSEMEVENTMULTI;
354 }
355 }
356 else
357 {
358 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a hgcm worker thread.\n"));
359 m_eventThread = NIL_RTSEMEVENT;
360 }
361
362 return vrc;
363}
364
365inline int HGCMThread::Enter(void)
366{
367 int vrc = RTCritSectEnter(&m_critsect);
368
369#ifdef LOG_ENABLED
370 if (RT_FAILURE(vrc))
371 Log(("HGCMThread::MsgPost: FAILURE: could not obtain worker thread mutex, vrc = %Rrc!!!\n", vrc));
372#endif
373
374 return vrc;
375}
376
377inline void HGCMThread::Leave(void)
378{
379 RTCritSectLeave(&m_critsect);
380}
381
382
383int HGCMThread::MsgAlloc(HGCMMsgCore **ppMsg, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
384{
385 /** @todo Implement this free list / cache thingy. */
386 HGCMMsgCore *pmsg = NULL;
387
388 bool fFromFreeList = false;
389
390 if (!pmsg)
391 {
392 /* We have to allocate a new memory block. */
393 pmsg = pfnNewMessage(u32MsgId);
394 if (pmsg != NULL)
395 pmsg->Reference(); /* (it's created with zero references) */
396 else
397 return VERR_NO_MEMORY;
398 }
399
400 /* Initialize just allocated message core */
401 pmsg->InitializeCore(u32MsgId, this);
402
403 /* and the message specific data. */
404 pmsg->Initialize();
405
406 LogFlow(("MAIN::hgcmMsgAlloc: allocated message %p\n", pmsg));
407
408 *ppMsg = pmsg;
409
410 if (fFromFreeList)
411 {
412 /* Message was referenced in the free list, now dereference it. */
413 pmsg->Dereference();
414 }
415
416 return VINF_SUCCESS;
417}
418
419int HGCMThread::MsgPost(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback, bool fWait)
420{
421 LogFlow(("HGCMThread::MsgPost: thread = %p, pMsg = %p, pfnCallback = %p\n", this, pMsg, pfnCallback));
422
423 int vrc = Enter();
424
425 if (RT_SUCCESS(vrc))
426 {
427 pMsg->m_pfnCallback = pfnCallback;
428
429 if (fWait)
430 pMsg->m_fu32Flags |= HGCM_MSG_F_WAIT;
431
432 /* Insert the message to the queue tail. */
433 pMsg->m_pNext = NULL;
434 HGCMMsgCore * const pPrev = m_pMsgInputQueueTail;
435 pMsg->m_pPrev = pPrev;
436
437 if (pPrev)
438 {
439 pPrev->m_pNext = pMsg;
440 if (!pPrev->m_pPrev)
441 STAM_REL_COUNTER_INC(&m_StatPostMsgOnePending);
442 else if (!pPrev->m_pPrev)
443 STAM_REL_COUNTER_INC(&m_StatPostMsgTwoPending);
444 else if (!pPrev->m_pPrev->m_pPrev)
445 STAM_REL_COUNTER_INC(&m_StatPostMsgThreePending);
446 else
447 STAM_REL_COUNTER_INC(&m_StatPostMsgManyPending);
448 }
449 else
450 {
451 m_pMsgInputQueueHead = pMsg;
452 STAM_REL_COUNTER_INC(&m_StatPostMsgNoPending);
453 }
454
455 m_pMsgInputQueueTail = pMsg;
456
457 Leave();
458
459 LogFlow(("HGCMThread::MsgPost: going to inform the thread %p about message, fWait = %d\n", this, fWait));
460
461 /* Inform the worker thread that there is a message. */
462 RTSemEventSignal(m_eventThread);
463
464 LogFlow(("HGCMThread::MsgPost: event signalled\n"));
465
466 if (fWait)
467 {
468 /* Immediately check if the message has been processed. */
469 while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
470 {
471 /* Poll infrequently to make sure no completed message has been missed. */
472 RTSemEventMultiWait(m_eventSend, 1000);
473
474 LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags));
475
476 if ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
477 RTThreadYield();
478 }
479
480 /* 'Our' message has been processed, so should reset the semaphore.
481 * There is still possible that another message has been processed
482 * and the semaphore has been signalled again.
483 * Reset only if there are no other messages completed.
484 */
485 int32_t c = ASMAtomicDecS32(&m_i32MessagesProcessed);
486 Assert(c >= 0);
487 if (c == 0)
488 RTSemEventMultiReset(m_eventSend);
489
490 vrc = pMsg->m_rcSend;
491 }
492 }
493
494 LogFlow(("HGCMThread::MsgPost: vrc = %Rrc\n", vrc));
495 return vrc;
496}
497
498
499int HGCMThread::MsgGet(HGCMMsgCore **ppMsg)
500{
501 int vrc = VINF_SUCCESS;
502
503 LogFlow(("HGCMThread::MsgGet: thread = %p, ppMsg = %p\n", this, ppMsg));
504
505 for (;;)
506 {
507 if (m_fu32ThreadFlags & HGCMMSG_TF_TERMINATE)
508 {
509 vrc = VERR_INTERRUPTED;
510 break;
511 }
512
513 LogFlow(("MAIN::hgcmMsgGet: m_pMsgInputQueueHead = %p\n", m_pMsgInputQueueHead));
514
515 if (m_pMsgInputQueueHead)
516 {
517 /* Move the message to the m_pMsgInProcessHead list */
518 vrc = Enter();
519
520 if (RT_FAILURE(vrc))
521 {
522 break;
523 }
524
525 HGCMMsgCore *pMsg = m_pMsgInputQueueHead;
526
527 /* Remove the message from the head of Queue list. */
528 Assert(m_pMsgInputQueueHead->m_pPrev == NULL);
529
530 if (m_pMsgInputQueueHead->m_pNext)
531 {
532 m_pMsgInputQueueHead = m_pMsgInputQueueHead->m_pNext;
533 m_pMsgInputQueueHead->m_pPrev = NULL;
534 }
535 else
536 {
537 Assert(m_pMsgInputQueueHead == m_pMsgInputQueueTail);
538
539 m_pMsgInputQueueHead = NULL;
540 m_pMsgInputQueueTail = NULL;
541 }
542
543 /* Insert the message to the tail of the m_pMsgInProcessHead list. */
544 pMsg->m_pNext = NULL;
545 pMsg->m_pPrev = m_pMsgInProcessTail;
546
547 if (m_pMsgInProcessTail)
548 m_pMsgInProcessTail->m_pNext = pMsg;
549 else
550 m_pMsgInProcessHead = pMsg;
551
552 m_pMsgInProcessTail = pMsg;
553
554 pMsg->m_fu32Flags |= HGCM_MSG_F_IN_PROCESS;
555
556 Leave();
557
558 /* Return the message to the caller. */
559 *ppMsg = pMsg;
560
561 LogFlow(("MAIN::hgcmMsgGet: got message %p\n", *ppMsg));
562
563 break;
564 }
565
566 /* Wait for an event. */
567 RTSemEventWait(m_eventThread, RT_INDEFINITE_WAIT);
568 }
569
570 LogFlow(("HGCMThread::MsgGet: *ppMsg = %p, return vrc = %Rrc\n", *ppMsg, vrc));
571 return vrc;
572}
573
574int HGCMThread::MsgComplete(HGCMMsgCore *pMsg, int32_t result)
575{
576 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p, result = %Rrc (%d)\n", this, pMsg, result, result));
577
578 AssertRelease(pMsg->m_pThread == this);
579 AssertReleaseMsg((pMsg->m_fu32Flags & HGCM_MSG_F_IN_PROCESS) != 0, ("%p %x\n", pMsg, pMsg->m_fu32Flags));
580
581 int vrcRet = VINF_SUCCESS;
582 if (pMsg->m_pfnCallback)
583 {
584 /** @todo call callback with error code in MsgPost in case of errors */
585
586 vrcRet = pMsg->m_pfnCallback(result, pMsg);
587
588 LogFlow(("HGCMThread::MsgComplete: callback executed. pMsg = %p, thread = %p, rcRet = %Rrc\n", pMsg, this, vrcRet));
589 }
590
591 /* Message processing has been completed. */
592
593 int vrc = Enter();
594
595 if (RT_SUCCESS(vrc))
596 {
597 /* Remove the message from the InProcess queue. */
598
599 if (pMsg->m_pNext)
600 pMsg->m_pNext->m_pPrev = pMsg->m_pPrev;
601 else
602 m_pMsgInProcessTail = pMsg->m_pPrev;
603
604 if (pMsg->m_pPrev)
605 pMsg->m_pPrev->m_pNext = pMsg->m_pNext;
606 else
607 m_pMsgInProcessHead = pMsg->m_pNext;
608
609 pMsg->m_pNext = NULL;
610 pMsg->m_pPrev = NULL;
611
612 bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0);
613
614 if (fWaited)
615 {
616 ASMAtomicIncS32(&m_i32MessagesProcessed);
617
618 /* This should be done before setting the HGCM_MSG_F_PROCESSED flag. */
619 pMsg->m_rcSend = result;
620 }
621
622 /* The message is now completed. */
623 pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS;
624 pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT;
625 pMsg->m_fu32Flags |= HGCM_MSG_F_PROCESSED;
626
627 pMsg->Dereference();
628
629 Leave();
630
631 if (fWaited)
632 {
633 /* Wake up all waiters. so they can decide if their message has been processed. */
634 RTSemEventMultiSignal(m_eventSend);
635 }
636 }
637
638 return vrcRet;
639}
640
641/*
642 * Thread API. Public interface.
643 */
644
645int hgcmThreadCreate(HGCMThread **ppThread, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser,
646 const char *pszStatsSubDir, PUVM pUVM, PCVMMR3VTABLE pVMM)
647{
648 LogFlow(("MAIN::hgcmThreadCreate\n"));
649 int vrc;
650
651 /* Allocate memory for a new thread object. */
652 HGCMThread *pThread = new (std::nothrow) HGCMThread();
653
654 if (pThread)
655 {
656 pThread->Reference(); /* (it's created with zero references) */
657
658 /* Initialize the object. */
659 vrc = pThread->Initialize(pszThreadName, pfnThread, pvUser, pszStatsSubDir, pUVM, pVMM);
660 if (RT_SUCCESS(vrc))
661 {
662 *ppThread = pThread;
663 LogFlow(("MAIN::hgcmThreadCreate: vrc = %Rrc\n", vrc));
664 return vrc;
665 }
666
667 Log(("hgcmThreadCreate: FAILURE: Initialize failed: vrc = %Rrc\n", vrc));
668
669 pThread->Dereference();
670 }
671 else
672 {
673 Log(("hgcmThreadCreate: FAILURE: Can't allocate memory for a hgcm worker thread.\n"));
674 vrc = VERR_NO_MEMORY;
675 }
676 *ppThread = NULL;
677
678 LogFlow(("MAIN::hgcmThreadCreate: vrc = %Rrc\n", vrc));
679 return vrc;
680}
681
682int hgcmThreadWait(HGCMThread *pThread)
683{
684 LogFlowFunc(("%p\n", pThread));
685
686 int vrc;
687 if (pThread)
688 {
689 vrc = pThread->WaitForTermination();
690
691 pThread->Dereference();
692 }
693 else
694 vrc = VERR_INVALID_HANDLE;
695
696 LogFlowFunc(("vrc = %Rrc\n", vrc));
697 return vrc;
698}
699
700int hgcmMsgAlloc(HGCMThread *pThread, HGCMMsgCore **ppMsg, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
701{
702 LogFlow(("hgcmMsgAlloc: pThread = %p, ppMsg = %p, sizeof (HGCMMsgCore) = %d\n", pThread, ppMsg, sizeof(HGCMMsgCore)));
703
704 AssertReturn(pThread, VERR_INVALID_HANDLE);
705 AssertReturn(ppMsg, VERR_INVALID_PARAMETER);
706
707 int vrc = pThread->MsgAlloc(ppMsg, u32MsgId, pfnNewMessage);
708
709 LogFlow(("MAIN::hgcmMsgAlloc: *ppMsg = %p, vrc = %Rrc\n", *ppMsg, vrc));
710 return vrc;
711}
712
713DECLINLINE(int) hgcmMsgPostInternal(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback, bool fWait)
714{
715 LogFlow(("MAIN::hgcmMsgPostInternal: pMsg = %p, pfnCallback = %p, fWait = %d\n", pMsg, pfnCallback, fWait));
716 Assert(pMsg);
717
718 pMsg->Reference(); /* paranoia? */
719
720 int vrc = pMsg->Thread()->MsgPost(pMsg, pfnCallback, fWait);
721
722 pMsg->Dereference();
723
724 LogFlow(("MAIN::hgcmMsgPostInternal: pMsg = %p, vrc = %Rrc\n", pMsg, vrc));
725 return vrc;
726}
727
728int hgcmMsgPost(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback)
729{
730 int vrc = hgcmMsgPostInternal(pMsg, pfnCallback, false);
731
732 if (RT_SUCCESS(vrc))
733 vrc = VINF_HGCM_ASYNC_EXECUTE;
734
735 return vrc;
736}
737
738int hgcmMsgSend(HGCMMsgCore *pMsg)
739{
740 return hgcmMsgPostInternal(pMsg, NULL, true);
741}
742
743int hgcmMsgGet(HGCMThread *pThread, HGCMMsgCore **ppMsg)
744{
745 LogFlow(("MAIN::hgcmMsgGet: pThread = %p, ppMsg = %p\n", pThread, ppMsg));
746
747 AssertReturn(pThread, VERR_INVALID_HANDLE);
748 AssertReturn(ppMsg, VERR_INVALID_PARAMETER);
749
750 pThread->Reference(); /* paranoia */
751
752 int vrc = pThread->MsgGet(ppMsg);
753
754 pThread->Dereference();
755
756 LogFlow(("MAIN::hgcmMsgGet: *ppMsg = %p, vrc = %Rrc\n", *ppMsg, vrc));
757 return vrc;
758}
759
760int hgcmMsgComplete(HGCMMsgCore *pMsg, int32_t rcMsg)
761{
762 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rcMsg = %Rrc (%d)\n", pMsg, rcMsg, rcMsg));
763
764 int vrc;
765 if (pMsg)
766 vrc = pMsg->Thread()->MsgComplete(pMsg, rcMsg);
767 else
768 vrc = VINF_SUCCESS;
769
770 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rcMsg =%Rrc (%d), returns vrc = %Rrc\n", pMsg, rcMsg, rcMsg, vrc));
771 return vrc;
772}
773
774int hgcmThreadInit(void)
775{
776 LogFlow(("MAIN::hgcmThreadInit\n"));
777
778 /** @todo error processing. */
779
780 int vrc = hgcmObjInit();
781
782 LogFlow(("MAIN::hgcmThreadInit: vrc = %Rrc\n", vrc));
783 return vrc;
784}
785
786void hgcmThreadUninit(void)
787{
788 hgcmObjUninit();
789}
790
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