VirtualBox

source: vbox/trunk/src/VBox/Main/hgcm/HGCMThread.cpp@ 34079

Last change on this file since 34079 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

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