VirtualBox

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

Last change on this file since 35421 was 35374, checked in by vboxsync, 14 years ago

hgcm -> main

  • 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 35374 2010-12-30 14:42:15Z vboxsync $ */
2/** @file
3 * HGCMThread - Host-Guest Communication Manager Threads
4 */
5
6/*
7 * Copyright (C) 2006-2007 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_MAIN_OVERRIDE LOG_GROUP_HGCM
19#include "Logging.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 hgcmObjDeleteHandle (pThread->Handle ());
199
200 pThread->m_thread = NIL_RTTHREAD;
201
202 LogFlow(("MAIN::hgcmWorkerThreadFunc: completed HGCM thread %p\n", pThread));
203
204 return rc;
205}
206
207HGCMThread::HGCMThread ()
208 :
209 HGCMObject(HGCMOBJ_THREAD),
210 m_pfnThread (NULL),
211 m_pvUser (NULL),
212 m_thread (NIL_RTTHREAD),
213 m_eventThread (0),
214 m_eventSend (0),
215 m_i32MessagesProcessed (0),
216 m_fu32ThreadFlags (0),
217 m_pMsgInputQueueHead (NULL),
218 m_pMsgInputQueueTail (NULL),
219 m_pMsgInProcessHead (NULL),
220 m_pMsgInProcessTail (NULL),
221 m_pFreeHead (NULL),
222 m_pFreeTail (NULL),
223 m_handle (0)
224{
225 memset (&m_critsect, 0, sizeof (m_critsect));
226}
227
228HGCMThread::~HGCMThread ()
229{
230 /*
231 * Free resources allocated for the thread.
232 */
233
234 Assert(m_fu32ThreadFlags & HGCMMSG_TF_TERMINATED);
235
236 if (RTCritSectIsInitialized (&m_critsect))
237 {
238 RTCritSectDelete (&m_critsect);
239 }
240
241 if (m_eventSend)
242 {
243 RTSemEventMultiDestroy (m_eventSend);
244 }
245
246 if (m_eventThread)
247 {
248 RTSemEventMultiDestroy (m_eventThread);
249 }
250
251 return;
252}
253
254int HGCMThread::WaitForTermination (void)
255{
256 int rc = VINF_SUCCESS;
257 LogFlowFunc(("\n"));
258
259 if (m_thread != NIL_RTTHREAD)
260 {
261 rc = RTThreadWait (m_thread, 5000, NULL);
262 }
263
264 LogFlowFunc(("rc = %Rrc\n", rc));
265 return rc;
266}
267
268int HGCMThread::Initialize (HGCMTHREADHANDLE handle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser)
269{
270 int rc = VINF_SUCCESS;
271
272 rc = RTSemEventMultiCreate (&m_eventThread);
273
274 if (RT_SUCCESS(rc))
275 {
276 rc = RTSemEventMultiCreate (&m_eventSend);
277
278 if (RT_SUCCESS(rc))
279 {
280 rc = RTCritSectInit (&m_critsect);
281
282 if (RT_SUCCESS(rc))
283 {
284 m_pfnThread = pfnThread;
285 m_pvUser = pvUser;
286 m_handle = handle;
287
288 m_fu32ThreadFlags = HGCMMSG_TF_INITIALIZING;
289
290 RTTHREAD thread;
291 rc = RTThreadCreate (&thread, hgcmWorkerThreadFunc, this, 0, /* default stack size; some service may need quite a bit */
292 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
293 pszThreadName);
294
295 if (RT_SUCCESS(rc))
296 {
297 /* Wait until the thread is ready. */
298 rc = RTThreadUserWait (thread, 30000);
299 AssertRC(rc);
300 Assert(!(m_fu32ThreadFlags & HGCMMSG_TF_INITIALIZING) || RT_FAILURE(rc));
301 }
302 else
303 {
304 m_thread = NIL_RTTHREAD;
305 Log(("hgcmThreadCreate: FAILURE: Can't start worker thread.\n"));
306 }
307 }
308 else
309 {
310 Log(("hgcmThreadCreate: FAILURE: Can't init a critical section for a hgcm worker thread.\n"));
311 memset (&m_critsect, 0, sizeof (m_critsect));
312 }
313 }
314 else
315 {
316 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a sent messages.\n"));
317 m_eventSend = 0;
318 }
319 }
320 else
321 {
322 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a hgcm worker thread.\n"));
323 m_eventThread = 0;
324 }
325
326 return rc;
327}
328
329inline int HGCMThread::Enter (void)
330{
331 int rc = RTCritSectEnter (&m_critsect);
332
333#ifdef LOG_ENABLED
334 if (RT_FAILURE(rc))
335 {
336 Log(("HGCMThread::MsgPost: FAILURE: could not obtain worker thread mutex, rc = %Rrc!!!\n", rc));
337 }
338#endif /* LOG_ENABLED */
339
340 return rc;
341}
342
343inline void HGCMThread::Leave (void)
344{
345 RTCritSectLeave (&m_critsect);
346}
347
348
349int HGCMThread::MsgAlloc (HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
350{
351 int rc = VINF_SUCCESS;
352
353 HGCMMsgCore *pmsg = NULL;
354
355 bool fFromFreeList = false;
356
357 if (!pmsg && RT_SUCCESS(rc))
358 {
359 /* We have to allocate a new memory block. */
360 pmsg = pfnNewMessage (u32MsgId);
361
362 if (pmsg == NULL)
363 {
364 rc = VERR_NO_MEMORY;
365 }
366 }
367
368 if (RT_SUCCESS(rc))
369 {
370 /* Initialize just allocated message core */
371 pmsg->InitializeCore (u32MsgId, m_handle);
372
373 /* and the message specific data. */
374 pmsg->Initialize ();
375
376 LogFlow(("MAIN::hgcmMsgAlloc: allocated message %p\n", pmsg));
377
378 /** Get handle of the message. The message will be also referenced
379 * until the handle is deleted.
380 */
381 *pHandle = hgcmObjGenerateHandle (pmsg);
382
383 if (fFromFreeList)
384 {
385 /* Message was referenced in the free list, now dereference it. */
386 pmsg->Dereference ();
387 }
388 }
389
390 return rc;
391}
392
393int HGCMThread::MsgPost (HGCMMsgCore *pMsg, PHGCMMSGCALLBACK pfnCallback, bool fWait)
394{
395 int rc = VINF_SUCCESS;
396
397 LogFlow(("HGCMThread::MsgPost: thread = %p, pMsg = %p, pfnCallback = %p\n", this, pMsg, pfnCallback));
398
399 rc = Enter ();
400
401 if (RT_SUCCESS(rc))
402 {
403 pMsg->m_pfnCallback = pfnCallback;
404
405 if (fWait)
406 {
407 pMsg->m_fu32Flags |= HGCM_MSG_F_WAIT;
408 }
409
410 /* Insert the message to the queue tail. */
411 pMsg->m_pNext = NULL;
412 pMsg->m_pPrev = m_pMsgInputQueueTail;
413
414 if (m_pMsgInputQueueTail)
415 {
416 m_pMsgInputQueueTail->m_pNext = pMsg;
417 }
418 else
419 {
420 m_pMsgInputQueueHead = pMsg;
421 }
422
423 m_pMsgInputQueueTail = pMsg;
424
425 Leave ();
426
427 LogFlow(("HGCMThread::MsgPost: going to inform the thread %p about message, fWait = %d\n", this, fWait));
428
429 /* Inform the worker thread that there is a message. */
430 RTSemEventMultiSignal (m_eventThread);
431
432 LogFlow(("HGCMThread::MsgPost: event signalled\n"));
433
434 if (fWait)
435 {
436 /* Immediately check if the message has been processed. */
437 while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
438 {
439 /* Poll infrequently to make sure no completed message has been missed. */
440 RTSemEventMultiWait (m_eventSend, 1000);
441
442 LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags));
443
444 if ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
445 {
446 RTThreadYield();
447 }
448 }
449
450 /* 'Our' message has been processed, so should reset the semaphore.
451 * There is still possible that another message has been processed
452 * and the semaphore has been signalled again.
453 * Reset only if there are no other messages completed.
454 */
455 int32_t c = ASMAtomicDecS32(&m_i32MessagesProcessed);
456 Assert(c >= 0);
457 if (c == 0)
458 {
459 RTSemEventMultiReset (m_eventSend);
460 }
461
462 rc = pMsg->m_rcSend;
463 }
464 }
465
466 LogFlow(("HGCMThread::MsgPost: rc = %Rrc\n", rc));
467
468 return rc;
469}
470
471
472int HGCMThread::MsgGet (HGCMMsgCore **ppMsg)
473{
474 int rc = VINF_SUCCESS;
475
476 LogFlow(("HGCMThread::MsgGet: thread = %p, ppMsg = %p\n", this, ppMsg));
477
478 for (;;)
479 {
480 if (m_fu32ThreadFlags & HGCMMSG_TF_TERMINATE)
481 {
482 rc = VERR_INTERRUPTED;
483 break;
484 }
485
486 LogFlow(("MAIN::hgcmMsgGet: m_pMsgInputQueueHead = %p\n", m_pMsgInputQueueHead));
487
488 if (m_pMsgInputQueueHead)
489 {
490 /* Move the message to the m_pMsgInProcessHead list */
491 rc = Enter ();
492
493 if (RT_FAILURE(rc))
494 {
495 break;
496 }
497
498 HGCMMsgCore *pMsg = m_pMsgInputQueueHead;
499
500 /* Remove the message from the head of Queue list. */
501 Assert(m_pMsgInputQueueHead->m_pPrev == NULL);
502
503 if (m_pMsgInputQueueHead->m_pNext)
504 {
505 m_pMsgInputQueueHead = m_pMsgInputQueueHead->m_pNext;
506 m_pMsgInputQueueHead->m_pPrev = NULL;
507 }
508 else
509 {
510 Assert(m_pMsgInputQueueHead == m_pMsgInputQueueTail);
511
512 m_pMsgInputQueueHead = NULL;
513 m_pMsgInputQueueTail = NULL;
514 }
515
516 /* Insert the message to the tail of the m_pMsgInProcessHead list. */
517 pMsg->m_pNext = NULL;
518 pMsg->m_pPrev = m_pMsgInProcessTail;
519
520 if (m_pMsgInProcessTail)
521 {
522 m_pMsgInProcessTail->m_pNext = pMsg;
523 }
524 else
525 {
526 m_pMsgInProcessHead = pMsg;
527 }
528
529 m_pMsgInProcessTail = pMsg;
530
531 pMsg->m_fu32Flags |= HGCM_MSG_F_IN_PROCESS;
532
533 Leave ();
534
535 /* Return the message to the caller. */
536 *ppMsg = pMsg;
537
538 LogFlow(("MAIN::hgcmMsgGet: got message %p\n", *ppMsg));
539
540 break;
541 }
542
543 /* Wait for an event. */
544 RTSemEventMultiWait (m_eventThread, RT_INDEFINITE_WAIT);
545 RTSemEventMultiReset (m_eventThread);
546 }
547
548 LogFlow(("HGCMThread::MsgGet: *ppMsg = %p, return rc = %Rrc\n", *ppMsg, rc));
549
550 return rc;
551}
552
553void HGCMThread::MsgComplete (HGCMMsgCore *pMsg, int32_t result)
554{
555 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p\n", this, pMsg));
556
557 int rc = VINF_SUCCESS;
558
559 AssertRelease(pMsg->m_pThread == this);
560 AssertReleaseMsg((pMsg->m_fu32Flags & HGCM_MSG_F_IN_PROCESS) != 0, ("%p %x\n", pMsg, pMsg->m_fu32Flags));
561
562 if (pMsg->m_pfnCallback)
563 {
564 /** @todo call callback with error code in MsgPost in case of errors */
565
566 pMsg->m_pfnCallback (result, pMsg);
567
568 LogFlow(("HGCMThread::MsgComplete: callback executed. pMsg = %p, thread = %p\n", pMsg, this));
569 }
570
571 /* Message processing has been completed. */
572
573 rc = Enter ();
574
575 if (RT_SUCCESS(rc))
576 {
577 /* Remove the message from the InProcess queue. */
578
579 if (pMsg->m_pNext)
580 {
581 pMsg->m_pNext->m_pPrev = pMsg->m_pPrev;
582 }
583 else
584 {
585 m_pMsgInProcessTail = pMsg->m_pPrev;
586 }
587
588 if (pMsg->m_pPrev)
589 {
590 pMsg->m_pPrev->m_pNext = pMsg->m_pNext;
591 }
592 else
593 {
594 m_pMsgInProcessHead = pMsg->m_pNext;
595 }
596
597 pMsg->m_pNext = NULL;
598 pMsg->m_pPrev = NULL;
599
600 bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0);
601
602 if (fWaited)
603 {
604 ASMAtomicIncS32(&m_i32MessagesProcessed);
605
606 /* This should be done before setting the HGCM_MSG_F_PROCESSED flag. */
607 pMsg->m_rcSend = result;
608 }
609
610 /* The message is now completed. */
611 pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS;
612 pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT;
613 pMsg->m_fu32Flags |= HGCM_MSG_F_PROCESSED;
614
615 hgcmObjDeleteHandle (pMsg->Handle ());
616
617 Leave ();
618
619 if (fWaited)
620 {
621 /* Wake up all waiters. so they can decide if their message has been processed. */
622 RTSemEventMultiSignal (m_eventSend);
623 }
624 }
625
626 return;
627}
628
629/*
630 * Thread API. Public interface.
631 */
632
633int hgcmThreadCreate (HGCMTHREADHANDLE *pHandle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser)
634{
635 int rc = VINF_SUCCESS;
636
637 LogFlow(("MAIN::hgcmThreadCreate\n"));
638
639 HGCMTHREADHANDLE handle = 0;
640
641 /* Allocate memory for a new thread object. */
642 HGCMThread *pThread = new HGCMThread ();
643
644 if (pThread)
645 {
646 /* Put just created object to pool and obtain handle for it. */
647 handle = hgcmObjGenerateHandle (pThread);
648
649 /* Initialize the object. */
650 rc = pThread->Initialize (handle, pszThreadName, pfnThread, pvUser);
651 }
652 else
653 {
654 Log(("hgcmThreadCreate: FAILURE: Can't allocate memory for a hgcm worker thread.\n"));
655 rc = VERR_NO_MEMORY;
656 }
657
658 if (RT_SUCCESS(rc))
659 {
660 *pHandle = handle;
661 }
662 else
663 {
664 Log(("hgcmThreadCreate: FAILURE: rc = %Rrc.\n", rc));
665
666 if (handle != 0)
667 {
668 /* Delete allocated handle, this will also free the object memory. */
669 hgcmObjDeleteHandle (handle);
670 }
671 }
672
673 LogFlow(("MAIN::hgcmThreadCreate: rc = %Rrc\n", rc));
674
675 return rc;
676}
677
678int hgcmThreadWait (HGCMTHREADHANDLE hThread)
679{
680 int rc = VERR_INVALID_HANDLE;
681 LogFlowFunc(("0x%08X\n", hThread));
682
683 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
684
685 if (pThread)
686 {
687 rc = pThread->WaitForTermination ();
688
689 hgcmObjDereference (pThread);
690 }
691
692 LogFlowFunc(("rc = %Rrc\n", rc));
693 return rc;
694}
695
696int hgcmMsgAlloc (HGCMTHREADHANDLE hThread, HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
697{
698 LogFlow(("hgcmMsgAlloc: thread handle = 0x%08X, pHandle = %p, sizeof (HGCMMsgCore) = %d\n", hThread, pHandle, sizeof (HGCMMsgCore)));
699
700 if (!pHandle)
701 {
702 return VERR_INVALID_PARAMETER;
703 }
704
705 int rc = VINF_SUCCESS;
706
707 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
708
709 if (!pThread)
710 {
711 rc = VERR_INVALID_HANDLE;
712 }
713 else
714 {
715 rc = pThread->MsgAlloc (pHandle, u32MsgId, pfnNewMessage);
716
717 hgcmObjDereference (pThread);
718 }
719
720 LogFlow(("MAIN::hgcmMsgAlloc: handle 0x%08X, rc = %Rrc\n", *pHandle, rc));
721
722 return rc;
723}
724
725static int hgcmMsgPostInternal (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback, bool fWait)
726{
727 LogFlow(("MAIN::hgcmMsgPostInternal: hMsg = 0x%08X, pfnCallback = %p, fWait = %d\n", hMsg, pfnCallback, fWait));
728
729 int rc = VINF_SUCCESS;
730
731 HGCMMsgCore *pMsg = (HGCMMsgCore *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
732
733 if (!pMsg)
734 {
735 rc = VERR_INVALID_HANDLE;
736 }
737 else
738 {
739 rc = pMsg->Thread()->MsgPost (pMsg, pfnCallback, fWait);
740
741 hgcmObjDereference (pMsg);
742 }
743
744 LogFlow(("MAIN::hgcmMsgPostInternal: hMsg 0x%08X, rc = %Rrc\n", hMsg, rc));
745
746 return rc;
747}
748
749
750/* Post message to worker thread with a flag indication if this is a Send or Post.
751 *
752 * @thread any
753 */
754
755int hgcmMsgPost (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback)
756{
757 int rc = hgcmMsgPostInternal (hMsg, pfnCallback, false);
758
759 if (RT_SUCCESS(rc))
760 {
761 rc = VINF_HGCM_ASYNC_EXECUTE;
762 }
763
764 return rc;
765}
766
767/* Send message to worker thread. Sending thread will block until message is processed.
768 *
769 * @thread any
770 */
771
772int hgcmMsgSend (HGCMMSGHANDLE hMsg)
773{
774 return hgcmMsgPostInternal (hMsg, NULL, true);
775}
776
777
778int hgcmMsgGet (HGCMTHREADHANDLE hThread, HGCMMsgCore **ppMsg)
779{
780 LogFlow(("MAIN::hgcmMsgGet: hThread = 0x%08X, ppMsg = %p\n", hThread, ppMsg));
781
782 if (!hThread || !ppMsg)
783 {
784 return VERR_INVALID_PARAMETER;
785 }
786
787 int rc = VINF_SUCCESS;
788
789 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
790
791 if (!pThread)
792 {
793 rc = VERR_INVALID_HANDLE;
794 }
795 else
796 {
797 rc = pThread->MsgGet (ppMsg);
798
799 hgcmObjDereference (pThread);
800 }
801
802 LogFlow(("MAIN::hgcmMsgGet: *ppMsg = %p, rc = %Rrc\n", *ppMsg, rc));
803
804 return rc;
805}
806
807
808void hgcmMsgComplete (HGCMMsgCore *pMsg, int32_t u32Result)
809{
810 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p\n", pMsg));
811
812 if (!pMsg)
813 {
814 return;
815 }
816
817 pMsg->Thread()->MsgComplete (pMsg, u32Result);
818
819 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rc = void\n", pMsg));
820
821 return;
822}
823
824
825int hgcmThreadInit (void)
826{
827 int rc = VINF_SUCCESS;
828
829 LogFlow(("MAIN::hgcmThreadInit\n"));
830
831 /** @todo error processing. */
832
833 rc = hgcmObjInit ();
834
835 LogFlow(("MAIN::hgcmThreadInit: rc = %Rrc\n", rc));
836
837 return rc;
838}
839
840void hgcmThreadUninit (void)
841{
842 hgcmObjUninit ();
843}
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