VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/HGCMThread.cpp@ 5999

最後變更 在這個檔案從5999是 5999,由 vboxsync 提交於 17 年 前

The Giant CDDL Dual-License Header Change.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette