VirtualBox

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

Last change on this file since 73768 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use