VirtualBox

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

Last change on this file since 77369 was 77191, checked in by vboxsync, 6 years ago

Main/HGCMThread: Don't clear the thread handle when the thread exits as the thread was created waitable and the handle is required to properly wait on it for termination (first and foremost memory leak fix but who knows, might also fix some HGCM related races where the service thread didn't terminate and the service was already destroyed)

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

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