VirtualBox

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

Last change on this file since 13762 was 12651, checked in by vboxsync, 16 years ago

HGCM: initialize flags before adding the message to the queue.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use