VirtualBox

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

Last change on this file since 40188 was 35909, checked in by vboxsync, 14 years ago

HGCM: fixed termination of threads.

  • 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 35909 2011-02-09 11:50:02Z 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 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 memset (&m_critsect, 0, sizeof (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 may need quite a bit */
290 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
291 pszThreadName);
292
293 if (RT_SUCCESS(rc))
294 {
295 /* Wait until the thread is ready. */
296 rc = RTThreadUserWait (thread, 30000);
297 AssertRC(rc);
298 Assert(!(m_fu32ThreadFlags & HGCMMSG_TF_INITIALIZING) || RT_FAILURE(rc));
299 }
300 else
301 {
302 m_thread = NIL_RTTHREAD;
303 Log(("hgcmThreadCreate: FAILURE: Can't start worker thread.\n"));
304 }
305 }
306 else
307 {
308 Log(("hgcmThreadCreate: FAILURE: Can't init a critical section for a hgcm worker thread.\n"));
309 memset (&m_critsect, 0, sizeof (m_critsect));
310 }
311 }
312 else
313 {
314 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a sent messages.\n"));
315 m_eventSend = 0;
316 }
317 }
318 else
319 {
320 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a hgcm worker thread.\n"));
321 m_eventThread = 0;
322 }
323
324 return rc;
325}
326
327inline int HGCMThread::Enter (void)
328{
329 int rc = RTCritSectEnter (&m_critsect);
330
331#ifdef LOG_ENABLED
332 if (RT_FAILURE(rc))
333 {
334 Log(("HGCMThread::MsgPost: FAILURE: could not obtain worker thread mutex, rc = %Rrc!!!\n", rc));
335 }
336#endif /* LOG_ENABLED */
337
338 return rc;
339}
340
341inline void HGCMThread::Leave (void)
342{
343 RTCritSectLeave (&m_critsect);
344}
345
346
347int HGCMThread::MsgAlloc (HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
348{
349 int rc = VINF_SUCCESS;
350
351 HGCMMsgCore *pmsg = NULL;
352
353 bool fFromFreeList = false;
354
355 if (!pmsg && RT_SUCCESS(rc))
356 {
357 /* We have to allocate a new memory block. */
358 pmsg = pfnNewMessage (u32MsgId);
359
360 if (pmsg == NULL)
361 {
362 rc = VERR_NO_MEMORY;
363 }
364 }
365
366 if (RT_SUCCESS(rc))
367 {
368 /* Initialize just allocated message core */
369 pmsg->InitializeCore (u32MsgId, m_handle);
370
371 /* and the message specific data. */
372 pmsg->Initialize ();
373
374 LogFlow(("MAIN::hgcmMsgAlloc: allocated message %p\n", pmsg));
375
376 /** Get handle of the message. The message will be also referenced
377 * until the handle is deleted.
378 */
379 *pHandle = hgcmObjGenerateHandle (pmsg);
380
381 if (fFromFreeList)
382 {
383 /* Message was referenced in the free list, now dereference it. */
384 pmsg->Dereference ();
385 }
386 }
387
388 return rc;
389}
390
391int HGCMThread::MsgPost (HGCMMsgCore *pMsg, PHGCMMSGCALLBACK pfnCallback, bool fWait)
392{
393 int rc = VINF_SUCCESS;
394
395 LogFlow(("HGCMThread::MsgPost: thread = %p, pMsg = %p, pfnCallback = %p\n", this, pMsg, pfnCallback));
396
397 rc = Enter ();
398
399 if (RT_SUCCESS(rc))
400 {
401 pMsg->m_pfnCallback = pfnCallback;
402
403 if (fWait)
404 {
405 pMsg->m_fu32Flags |= HGCM_MSG_F_WAIT;
406 }
407
408 /* Insert the message to the queue tail. */
409 pMsg->m_pNext = NULL;
410 pMsg->m_pPrev = m_pMsgInputQueueTail;
411
412 if (m_pMsgInputQueueTail)
413 {
414 m_pMsgInputQueueTail->m_pNext = pMsg;
415 }
416 else
417 {
418 m_pMsgInputQueueHead = pMsg;
419 }
420
421 m_pMsgInputQueueTail = pMsg;
422
423 Leave ();
424
425 LogFlow(("HGCMThread::MsgPost: going to inform the thread %p about message, fWait = %d\n", this, fWait));
426
427 /* Inform the worker thread that there is a message. */
428 RTSemEventMultiSignal (m_eventThread);
429
430 LogFlow(("HGCMThread::MsgPost: event signalled\n"));
431
432 if (fWait)
433 {
434 /* Immediately check if the message has been processed. */
435 while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
436 {
437 /* Poll infrequently to make sure no completed message has been missed. */
438 RTSemEventMultiWait (m_eventSend, 1000);
439
440 LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags));
441
442 if ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
443 {
444 RTThreadYield();
445 }
446 }
447
448 /* 'Our' message has been processed, so should reset the semaphore.
449 * There is still possible that another message has been processed
450 * and the semaphore has been signalled again.
451 * Reset only if there are no other messages completed.
452 */
453 int32_t c = ASMAtomicDecS32(&m_i32MessagesProcessed);
454 Assert(c >= 0);
455 if (c == 0)
456 {
457 RTSemEventMultiReset (m_eventSend);
458 }
459
460 rc = pMsg->m_rcSend;
461 }
462 }
463
464 LogFlow(("HGCMThread::MsgPost: rc = %Rrc\n", rc));
465
466 return rc;
467}
468
469
470int HGCMThread::MsgGet (HGCMMsgCore **ppMsg)
471{
472 int rc = VINF_SUCCESS;
473
474 LogFlow(("HGCMThread::MsgGet: thread = %p, ppMsg = %p\n", this, ppMsg));
475
476 for (;;)
477 {
478 if (m_fu32ThreadFlags & HGCMMSG_TF_TERMINATE)
479 {
480 rc = VERR_INTERRUPTED;
481 break;
482 }
483
484 LogFlow(("MAIN::hgcmMsgGet: m_pMsgInputQueueHead = %p\n", m_pMsgInputQueueHead));
485
486 if (m_pMsgInputQueueHead)
487 {
488 /* Move the message to the m_pMsgInProcessHead list */
489 rc = Enter ();
490
491 if (RT_FAILURE(rc))
492 {
493 break;
494 }
495
496 HGCMMsgCore *pMsg = m_pMsgInputQueueHead;
497
498 /* Remove the message from the head of Queue list. */
499 Assert(m_pMsgInputQueueHead->m_pPrev == NULL);
500
501 if (m_pMsgInputQueueHead->m_pNext)
502 {
503 m_pMsgInputQueueHead = m_pMsgInputQueueHead->m_pNext;
504 m_pMsgInputQueueHead->m_pPrev = NULL;
505 }
506 else
507 {
508 Assert(m_pMsgInputQueueHead == m_pMsgInputQueueTail);
509
510 m_pMsgInputQueueHead = NULL;
511 m_pMsgInputQueueTail = NULL;
512 }
513
514 /* Insert the message to the tail of the m_pMsgInProcessHead list. */
515 pMsg->m_pNext = NULL;
516 pMsg->m_pPrev = m_pMsgInProcessTail;
517
518 if (m_pMsgInProcessTail)
519 {
520 m_pMsgInProcessTail->m_pNext = pMsg;
521 }
522 else
523 {
524 m_pMsgInProcessHead = pMsg;
525 }
526
527 m_pMsgInProcessTail = pMsg;
528
529 pMsg->m_fu32Flags |= HGCM_MSG_F_IN_PROCESS;
530
531 Leave ();
532
533 /* Return the message to the caller. */
534 *ppMsg = pMsg;
535
536 LogFlow(("MAIN::hgcmMsgGet: got message %p\n", *ppMsg));
537
538 break;
539 }
540
541 /* Wait for an event. */
542 RTSemEventMultiWait (m_eventThread, RT_INDEFINITE_WAIT);
543 RTSemEventMultiReset (m_eventThread);
544 }
545
546 LogFlow(("HGCMThread::MsgGet: *ppMsg = %p, return rc = %Rrc\n", *ppMsg, rc));
547
548 return rc;
549}
550
551void HGCMThread::MsgComplete (HGCMMsgCore *pMsg, int32_t result)
552{
553 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p\n", this, pMsg));
554
555 int rc = VINF_SUCCESS;
556
557 AssertRelease(pMsg->m_pThread == this);
558 AssertReleaseMsg((pMsg->m_fu32Flags & HGCM_MSG_F_IN_PROCESS) != 0, ("%p %x\n", pMsg, pMsg->m_fu32Flags));
559
560 if (pMsg->m_pfnCallback)
561 {
562 /** @todo call callback with error code in MsgPost in case of errors */
563
564 pMsg->m_pfnCallback (result, pMsg);
565
566 LogFlow(("HGCMThread::MsgComplete: callback executed. pMsg = %p, thread = %p\n", pMsg, this));
567 }
568
569 /* Message processing has been completed. */
570
571 rc = Enter ();
572
573 if (RT_SUCCESS(rc))
574 {
575 /* Remove the message from the InProcess queue. */
576
577 if (pMsg->m_pNext)
578 {
579 pMsg->m_pNext->m_pPrev = pMsg->m_pPrev;
580 }
581 else
582 {
583 m_pMsgInProcessTail = pMsg->m_pPrev;
584 }
585
586 if (pMsg->m_pPrev)
587 {
588 pMsg->m_pPrev->m_pNext = pMsg->m_pNext;
589 }
590 else
591 {
592 m_pMsgInProcessHead = pMsg->m_pNext;
593 }
594
595 pMsg->m_pNext = NULL;
596 pMsg->m_pPrev = NULL;
597
598 bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0);
599
600 if (fWaited)
601 {
602 ASMAtomicIncS32(&m_i32MessagesProcessed);
603
604 /* This should be done before setting the HGCM_MSG_F_PROCESSED flag. */
605 pMsg->m_rcSend = result;
606 }
607
608 /* The message is now completed. */
609 pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS;
610 pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT;
611 pMsg->m_fu32Flags |= HGCM_MSG_F_PROCESSED;
612
613 hgcmObjDeleteHandle (pMsg->Handle ());
614
615 Leave ();
616
617 if (fWaited)
618 {
619 /* Wake up all waiters. so they can decide if their message has been processed. */
620 RTSemEventMultiSignal (m_eventSend);
621 }
622 }
623
624 return;
625}
626
627/*
628 * Thread API. Public interface.
629 */
630
631int hgcmThreadCreate (HGCMTHREADHANDLE *pHandle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser)
632{
633 int rc = VINF_SUCCESS;
634
635 LogFlow(("MAIN::hgcmThreadCreate\n"));
636
637 HGCMTHREADHANDLE handle = 0;
638
639 /* Allocate memory for a new thread object. */
640 HGCMThread *pThread = new HGCMThread ();
641
642 if (pThread)
643 {
644 /* Put just created object to pool and obtain handle for it. */
645 handle = hgcmObjGenerateHandle (pThread);
646
647 /* Initialize the object. */
648 rc = pThread->Initialize (handle, pszThreadName, pfnThread, pvUser);
649 }
650 else
651 {
652 Log(("hgcmThreadCreate: FAILURE: Can't allocate memory for a hgcm worker thread.\n"));
653 rc = VERR_NO_MEMORY;
654 }
655
656 if (RT_SUCCESS(rc))
657 {
658 *pHandle = handle;
659 }
660 else
661 {
662 Log(("hgcmThreadCreate: FAILURE: rc = %Rrc.\n", rc));
663
664 if (handle != 0)
665 {
666 /* Delete allocated handle, this will also free the object memory. */
667 hgcmObjDeleteHandle (handle);
668 }
669 }
670
671 LogFlow(("MAIN::hgcmThreadCreate: rc = %Rrc\n", rc));
672
673 return rc;
674}
675
676int hgcmThreadWait (HGCMTHREADHANDLE hThread)
677{
678 int rc = VERR_INVALID_HANDLE;
679 LogFlowFunc(("0x%08X\n", hThread));
680
681 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
682
683 if (pThread)
684 {
685 rc = pThread->WaitForTermination ();
686
687 hgcmObjDereference (pThread);
688 }
689
690 hgcmObjDeleteHandle (hThread);
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