VirtualBox

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

Last change on this file since 75861 was 75798, checked in by vboxsync, 6 years ago

VBoxGuestControl: Optimizing message handling - part 1. bugref:9313

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