VirtualBox

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

Last change on this file since 6382 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.6 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 innotek GmbH
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
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 sequently. 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_fu32ThreadFlags (0),
216 m_pMsgInputQueueHead (NULL),
217 m_pMsgInputQueueTail (NULL),
218 m_pMsgInProcessHead (NULL),
219 m_pMsgInProcessTail (NULL),
220 m_pFreeHead (NULL),
221 m_pFreeTail (NULL),
222 m_handle (0)
223{
224 memset (&m_critsect, 0, sizeof (m_critsect));
225}
226
227HGCMThread::~HGCMThread ()
228{
229 /*
230 * Free resources allocated for the thread.
231 */
232
233 Assert(m_fu32ThreadFlags & HGCMMSG_TF_TERMINATED);
234
235 if (RTCritSectIsInitialized (&m_critsect))
236 {
237 RTCritSectDelete (&m_critsect);
238 }
239
240 if (m_eventSend)
241 {
242 RTSemEventMultiDestroy (m_eventSend);
243 }
244
245 if (m_eventThread)
246 {
247 RTSemEventMultiDestroy (m_eventThread);
248 }
249
250 return;
251}
252
253int HGCMThread::WaitForTermination (void)
254{
255 int rc = VINF_SUCCESS;
256 LogFlowFunc(("\n"));
257
258 if (m_thread != NIL_RTTHREAD)
259 {
260 rc = RTThreadWait (m_thread, 5000, NULL);
261 }
262
263 LogFlowFunc(("rc = %Vrc\n", rc));
264 return rc;
265}
266
267int HGCMThread::Initialize (HGCMTHREADHANDLE handle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser)
268{
269 int rc = VINF_SUCCESS;
270
271 rc = RTSemEventMultiCreate (&m_eventThread);
272
273 if (VBOX_SUCCESS(rc))
274 {
275 rc = RTSemEventMultiCreate (&m_eventSend);
276
277 if (VBOX_SUCCESS(rc))
278 {
279 rc = RTCritSectInit (&m_critsect);
280
281 if (VBOX_SUCCESS(rc))
282 {
283 m_pfnThread = pfnThread;
284 m_pvUser = pvUser;
285 m_handle = handle;
286
287 m_fu32ThreadFlags = HGCMMSG_TF_INITIALIZING;
288
289 RTTHREAD thread;
290 rc = RTThreadCreate (&thread, hgcmWorkerThreadFunc, this, 0, /* default stack size; some service may need quite a bit */
291 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
292 pszThreadName);
293
294 if (VBOX_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) || VBOX_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 memset (&m_critsect, 0, sizeof (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 (VBOX_FAILURE (rc))
334 {
335 Log(("HGCMThread::MsgPost: FAILURE: could not obtain worker thread mutex, rc = %Vrc!!!\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 && VBOX_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 (VBOX_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 (VBOX_SUCCESS(rc))
401 {
402 pMsg->m_pfnCallback = pfnCallback;
403
404 /* Insert the message to the queue tail. */
405 pMsg->m_pNext = NULL;
406 pMsg->m_pPrev = m_pMsgInputQueueTail;
407
408 if (m_pMsgInputQueueTail)
409 {
410 m_pMsgInputQueueTail->m_pNext = pMsg;
411 }
412 else
413 {
414 m_pMsgInputQueueHead = pMsg;
415 }
416
417 m_pMsgInputQueueTail = pMsg;
418
419 Leave ();
420
421 LogFlow(("HGCMThread::MsgPost: going to inform the thread %p about message, fWait = %d\n", this, fWait));
422
423 if (fWait)
424 {
425 pMsg->m_fu32Flags |= HGCM_MSG_F_WAIT;
426 }
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 while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
436 {
437 RTSemEventMultiWait (m_eventSend, RT_INDEFINITE_WAIT);
438 RTSemEventMultiReset (m_eventSend);
439
440 LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags));
441 }
442
443 rc = pMsg->m_rcSend;
444 }
445 }
446
447 LogFlow(("HGCMThread::MsgPost: rc = %Vrc\n", rc));
448
449 return rc;
450}
451
452
453int HGCMThread::MsgGet (HGCMMsgCore **ppMsg)
454{
455 int rc = VINF_SUCCESS;
456
457 LogFlow(("HGCMThread::MsgGet: thread = %p, ppMsg = %p\n", this, ppMsg));
458
459 for (;;)
460 {
461 if (m_fu32ThreadFlags & HGCMMSG_TF_TERMINATE)
462 {
463 rc = VERR_INTERRUPTED;
464 break;
465 }
466
467 LogFlow(("MAIN::hgcmMsgGet: m_pMsgInputQueueHead = %p\n", m_pMsgInputQueueHead));
468
469 if (m_pMsgInputQueueHead)
470 {
471 /* Move the message to the m_pMsgInProcessHead list */
472 rc = Enter ();
473
474 if (VBOX_FAILURE (rc))
475 {
476 break;
477 }
478
479 HGCMMsgCore *pMsg = m_pMsgInputQueueHead;
480
481 /* Remove the message from the head of Queue list. */
482 Assert (m_pMsgInputQueueHead->m_pPrev == NULL);
483
484 if (m_pMsgInputQueueHead->m_pNext)
485 {
486 m_pMsgInputQueueHead = m_pMsgInputQueueHead->m_pNext;
487 m_pMsgInputQueueHead->m_pPrev = NULL;
488 }
489 else
490 {
491 Assert (m_pMsgInputQueueHead == m_pMsgInputQueueTail);
492
493 m_pMsgInputQueueHead = NULL;
494 m_pMsgInputQueueTail = NULL;
495 }
496
497 /* Insert the message to the tail of the m_pMsgInProcessHead list. */
498 pMsg->m_pNext = NULL;
499 pMsg->m_pPrev = m_pMsgInProcessTail;
500
501 if (m_pMsgInProcessTail)
502 {
503 m_pMsgInProcessTail->m_pNext = pMsg;
504 }
505 else
506 {
507 m_pMsgInProcessHead = pMsg;
508 }
509
510 m_pMsgInProcessTail = pMsg;
511
512 pMsg->m_fu32Flags |= HGCM_MSG_F_IN_PROCESS;
513
514 Leave ();
515
516 /* Return the message to the caller. */
517 *ppMsg = pMsg;
518
519 LogFlow(("MAIN::hgcmMsgGet: got message %p\n", *ppMsg));
520
521 break;
522 }
523
524 /* Wait for an event. */
525 RTSemEventMultiWait (m_eventThread, RT_INDEFINITE_WAIT);
526 RTSemEventMultiReset (m_eventThread);
527 }
528
529 LogFlow(("HGCMThread::MsgGet: *ppMsg = %p, return rc = %Vrc\n", *ppMsg, rc));
530
531 return rc;
532}
533
534void HGCMThread::MsgComplete (HGCMMsgCore *pMsg, int32_t result)
535{
536 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p\n", this, pMsg));
537
538 int rc = VINF_SUCCESS;
539
540 AssertRelease(pMsg->m_pThread == this);
541 AssertReleaseMsg((pMsg->m_fu32Flags & HGCM_MSG_F_IN_PROCESS) != 0, ("%p %x\n", pMsg, pMsg->m_fu32Flags));
542
543 if (pMsg->m_pfnCallback)
544 {
545 /** @todo call callback with error code in MsgPost in case of errors */
546
547 pMsg->m_pfnCallback (result, pMsg);
548
549 LogFlow(("HGCMThread::MsgComplete: callback executed. pMsg = %p, thread = %p\n", pMsg, this));
550 }
551
552 /* Message processing has been completed. */
553
554 rc = Enter ();
555
556 if (VBOX_SUCCESS(rc))
557 {
558 /* Remove the message from the InProcess queue. */
559
560 if (pMsg->m_pNext)
561 {
562 pMsg->m_pNext->m_pPrev = pMsg->m_pPrev;
563 }
564 else
565 {
566 m_pMsgInProcessTail = pMsg->m_pPrev;
567 }
568
569 if (pMsg->m_pPrev)
570 {
571 pMsg->m_pPrev->m_pNext = pMsg->m_pNext;
572 }
573 else
574 {
575 m_pMsgInProcessHead = pMsg->m_pNext;
576 }
577
578 pMsg->m_pNext = NULL;
579 pMsg->m_pPrev = NULL;
580
581 bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0);
582
583 /* The message is now completed. */
584 pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS;
585 pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT;
586 pMsg->m_fu32Flags |= HGCM_MSG_F_PROCESSED;
587
588 hgcmObjDeleteHandle (pMsg->Handle ());
589
590 Leave ();
591
592 if (fWaited)
593 {
594 /* If message is being waited, then it is referenced by the waiter and the pointer
595 * if valid even after hgcmObjDeleteHandle.
596 */
597 pMsg->m_rcSend = result;
598
599 /* Wake up all waiters. so they can decide if their message has been processed. */
600 RTSemEventMultiSignal (m_eventSend);
601 }
602 }
603
604 return;
605}
606
607/*
608 * Thread API. Public interface.
609 */
610
611int hgcmThreadCreate (HGCMTHREADHANDLE *pHandle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser)
612{
613 int rc = VINF_SUCCESS;
614
615 LogFlow(("MAIN::hgcmThreadCreate\n"));
616
617 HGCMTHREADHANDLE handle = 0;
618
619 /* Allocate memory for a new thread object. */
620 HGCMThread *pThread = new HGCMThread ();
621
622 if (pThread)
623 {
624 /* Put just created object to pool and obtain handle for it. */
625 handle = hgcmObjGenerateHandle (pThread);
626
627 /* Initialize the object. */
628 rc = pThread->Initialize (handle, pszThreadName, pfnThread, pvUser);
629 }
630 else
631 {
632 Log(("hgcmThreadCreate: FAILURE: Can't allocate memory for a hgcm worker thread.\n"));
633 rc = VERR_NO_MEMORY;
634 }
635
636 if (VBOX_SUCCESS (rc))
637 {
638 *pHandle = handle;
639 }
640 else
641 {
642 Log(("hgcmThreadCreate: FAILURE: rc = %Vrc.\n", rc));
643
644 if (handle != 0)
645 {
646 /* Delete allocated handle, this will also free the object memory. */
647 hgcmObjDeleteHandle (handle);
648 }
649 }
650
651 LogFlow(("MAIN::hgcmThreadCreate: rc = %Vrc\n", rc));
652
653 return rc;
654}
655
656int hgcmThreadWait (HGCMTHREADHANDLE hThread)
657{
658 int rc = VERR_INVALID_HANDLE;
659 LogFlowFunc(("0x%08X\n", hThread));
660
661 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
662
663 if (pThread)
664 {
665 rc = pThread->WaitForTermination ();
666
667 hgcmObjDereference (pThread);
668 }
669
670 LogFlowFunc(("rc = %Vrc\n", rc));
671 return rc;
672}
673
674int hgcmMsgAlloc (HGCMTHREADHANDLE hThread, HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
675{
676 LogFlow(("hgcmMsgAlloc: thread handle = 0x%08X, pHandle = %p, sizeof (HGCMMsgCore) = %d\n", hThread, pHandle, sizeof (HGCMMsgCore)));
677
678 if (!pHandle)
679 {
680 return VERR_INVALID_PARAMETER;
681 }
682
683 int rc = VINF_SUCCESS;
684
685 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
686
687 if (!pThread)
688 {
689 rc = VERR_INVALID_HANDLE;
690 }
691 else
692 {
693 rc = pThread->MsgAlloc (pHandle, u32MsgId, pfnNewMessage);
694
695 hgcmObjDereference (pThread);
696 }
697
698 LogFlow(("MAIN::hgcmMsgAlloc: handle 0x%08X, rc = %Vrc\n", *pHandle, rc));
699
700 return rc;
701}
702
703static int hgcmMsgPostInternal (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback, bool fWait)
704{
705 LogFlow(("MAIN::hgcmMsgPostInternal: hMsg = 0x%08X, pfnCallback = %p, fWait = %d\n", hMsg, pfnCallback, fWait));
706
707 int rc = VINF_SUCCESS;
708
709 HGCMMsgCore *pMsg = (HGCMMsgCore *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
710
711 if (!pMsg)
712 {
713 rc = VERR_INVALID_HANDLE;
714 }
715 else
716 {
717 rc = pMsg->Thread()->MsgPost (pMsg, pfnCallback, fWait);
718
719 hgcmObjDereference (pMsg);
720 }
721
722 LogFlow(("MAIN::hgcmMsgPostInternal: hMsg 0x%08X, rc = %Vrc\n", hMsg, rc));
723
724 return rc;
725}
726
727
728/* Post message to worker thread with a flag indication if this is a Send or Post.
729 *
730 * @thread any
731 */
732
733int hgcmMsgPost (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback)
734{
735 int rc = hgcmMsgPostInternal (hMsg, pfnCallback, false);
736
737 if (VBOX_SUCCESS (rc))
738 {
739 rc = VINF_HGCM_ASYNC_EXECUTE;
740 }
741
742 return rc;
743}
744
745/* Send message to worker thread. Sending thread will block until message is processed.
746 *
747 * @thread any
748 */
749
750int hgcmMsgSend (HGCMMSGHANDLE hMsg)
751{
752 return hgcmMsgPostInternal (hMsg, NULL, true);
753}
754
755
756int hgcmMsgGet (HGCMTHREADHANDLE hThread, HGCMMsgCore **ppMsg)
757{
758 LogFlow(("MAIN::hgcmMsgGet: hThread = 0x%08X, ppMsg = %p\n", hThread, ppMsg));
759
760 if (!hThread || !ppMsg)
761 {
762 return VERR_INVALID_PARAMETER;
763 }
764
765 int rc = VINF_SUCCESS;
766
767 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
768
769 if (!pThread)
770 {
771 rc = VERR_INVALID_HANDLE;
772 }
773 else
774 {
775 rc = pThread->MsgGet (ppMsg);
776
777 hgcmObjDereference (pThread);
778 }
779
780 LogFlow(("MAIN::hgcmMsgGet: *ppMsg = %p, rc = %Vrc\n", *ppMsg, rc));
781
782 return rc;
783}
784
785
786void hgcmMsgComplete (HGCMMsgCore *pMsg, int32_t u32Result)
787{
788 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p\n", pMsg));
789
790 if (!pMsg)
791 {
792 return;
793 }
794
795 pMsg->Thread()->MsgComplete (pMsg, u32Result);
796
797 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rc = void\n", pMsg));
798
799 return;
800}
801
802
803int hgcmThreadInit (void)
804{
805 int rc = VINF_SUCCESS;
806
807 LogFlow(("MAIN::hgcmThreadInit\n"));
808
809 /** @todo error processing. */
810
811 rc = hgcmObjInit ();
812
813 LogFlow(("MAIN::hgcmThreadInit: rc = %Vrc\n", rc));
814
815 return rc;
816}
817
818void hgcmThreadUninit (void)
819{
820 hgcmObjUninit ();
821}
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