VirtualBox

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

Last change on this file since 1344 was 1344, checked in by vboxsync, 18 years ago

Disabled obsolete code in HGCM, added logging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.9 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 InnoTek Systemberatung 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 as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
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
124 inline int Enter (void);
125 inline void Leave (void);
126
127 HGCMMsgCore *FetchFreeListHead (void);
128
129 protected:
130 virtual ~HGCMThread (void);
131
132 public:
133
134 HGCMThread ();
135
136 int Initialize (HGCMTHREADHANDLE handle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser, uint32_t cbMsg);
137
138 int MsgAlloc (HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, uint32_t cbMsg, 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 cbMsg, uint32_t u32MsgId, HGCMThread *pThread)
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 = pThread;
164}
165
166
167/*
168 * HGCMThread implementation.
169 */
170
171static DECLCALLBACK(int) hgcmWorkerThreadFunc (RTTHREAD ThreadSelf, void *pvUser)
172{
173 int rc = VINF_SUCCESS;
174
175 HGCMThread *pThread = (HGCMThread *)pvUser;
176
177 LogFlow(("MAIN::hgcmWorkerThreadFunc: starting HGCM thread %p\n", pThread));
178
179 AssertRelease(pThread);
180
181 pThread->m_thread = ThreadSelf;
182 pThread->m_fu32ThreadFlags &= ~HGCMMSG_TF_INITIALIZING;
183 rc = RTThreadUserSignal (ThreadSelf);
184 AssertRC (rc);
185
186 pThread->m_pfnThread (pThread->Handle (), pThread->m_pvUser);
187
188 pThread->m_fu32ThreadFlags |= HGCMMSG_TF_TERMINATED;
189
190 hgcmObjDeleteHandle (pThread->Handle ());
191
192 LogFlow(("MAIN::hgcmWorkerThreadFunc: completed HGCM thread %p\n", pThread));
193
194 return rc;
195}
196
197HGCMThread::HGCMThread ()
198 :
199 HGCMObject(HGCMOBJ_THREAD),
200 m_pfnThread (NULL),
201 m_pvUser (NULL),
202 m_thread (NIL_RTTHREAD),
203 m_eventThread (0),
204 m_eventSend (0),
205 m_fu32ThreadFlags (0),
206 m_pMsgInputQueueHead (NULL),
207 m_pMsgInputQueueTail (NULL),
208 m_pMsgInProcessHead (NULL),
209 m_pMsgInProcessTail (NULL),
210 m_pFreeHead (NULL),
211 m_pFreeTail (NULL)
212{
213 memset (&m_critsect, 0, sizeof (m_critsect));
214}
215
216HGCMThread::~HGCMThread ()
217{
218 /*
219 * Free resources allocated for the thread.
220 */
221
222 if (RTCritSectIsInitialized (&m_critsect))
223 {
224 RTCritSectDelete (&m_critsect);
225 }
226
227 if (m_eventSend)
228 {
229 RTSemEventMultiDestroy (m_eventSend);
230 }
231
232 if (m_eventThread)
233 {
234 RTSemEventMultiDestroy (m_eventThread);
235 }
236
237 /*
238 * Wait for the thread to terminate, but let's not wait forever.
239 */
240 if ( m_thread != NIL_RTTHREAD
241 && !(m_fu32ThreadFlags & HGCMMSG_TF_TERMINATED))
242 {
243 int rc = RTThreadWait (m_thread, 5000, NULL);
244 AssertRC (rc);
245 }
246
247 return;
248}
249
250int HGCMThread::Initialize (HGCMTHREADHANDLE handle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser, uint32_t cbMsg)
251{
252 int rc = VINF_SUCCESS;
253
254 rc = RTSemEventMultiCreate (&m_eventThread);
255
256 if (VBOX_SUCCESS(rc))
257 {
258 rc = RTSemEventMultiCreate (&m_eventSend);
259
260 if (VBOX_SUCCESS(rc))
261 {
262 rc = RTCritSectInit (&m_critsect);
263
264 if (VBOX_SUCCESS(rc))
265 {
266 m_pfnThread = pfnThread;
267 m_pvUser = pvUser;
268
269 m_fu32ThreadFlags = HGCMMSG_TF_INITIALIZING;
270
271 RTTHREAD thread;
272 rc = RTThreadCreate (&thread, hgcmWorkerThreadFunc, this, 64 * _1K,
273 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
274 pszThreadName);
275
276 if (VBOX_SUCCESS(rc))
277 {
278 /* Wait until the thread is ready. */
279 rc = RTThreadUserWait (thread, 30000);
280 AssertRC (rc);
281 Assert (!(m_fu32ThreadFlags & HGCMMSG_TF_INITIALIZING) || VBOX_FAILURE (rc));
282 }
283 else
284 {
285 m_thread = NIL_RTTHREAD;
286 Log(("hgcmThreadCreate: FAILURE: Can't start worker thread.\n"));
287 }
288 }
289 else
290 {
291 Log(("hgcmThreadCreate: FAILURE: Can't init a critical section for a hgcm worker thread.\n"));
292 memset (&m_critsect, 0, sizeof (m_critsect));
293 }
294 }
295 else
296 {
297 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a sent messages.\n"));
298 m_eventSend = 0;
299 }
300 }
301 else
302 {
303 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a hgcm worker thread.\n"));
304 m_eventThread = 0;
305 }
306
307 return rc;
308}
309
310inline int HGCMThread::Enter (void)
311{
312 int rc = RTCritSectEnter (&m_critsect);
313
314#ifdef LOG_ENABLED
315 if (VBOX_FAILURE (rc))
316 {
317 Log(("HGCMThread::MsgPost: FAILURE: could not obtain worker thread mutex, rc = %Vrc!!!\n", rc));
318 }
319#endif /* LOG_ENABLED */
320
321 return rc;
322}
323
324inline void HGCMThread::Leave (void)
325{
326 RTCritSectLeave (&m_critsect);
327}
328
329
330int HGCMThread::MsgAlloc (HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, uint32_t cbMsg, PFNHGCMNEWMSGALLOC pfnNewMessage)
331{
332 int rc = VINF_SUCCESS;
333
334 HGCMMsgCore *pmsg = NULL;
335
336 bool fFromFreeList = false;
337
338 if (!pmsg && VBOX_SUCCESS(rc))
339 {
340 /* We have to allocate a new memory block. */
341 pmsg = pfnNewMessage (u32MsgId);
342
343 if (pmsg == NULL)
344 {
345 rc = VERR_NO_MEMORY;
346 }
347 }
348
349 if (VBOX_SUCCESS(rc))
350 {
351 /* Reference the thread because pMsg contains the pointer to it. */
352 Reference ();
353
354 /* Initialize just allocated message core */
355 pmsg->InitializeCore (cbMsg, u32MsgId, this);
356
357 /* and the message specific data. */
358 pmsg->Initialize ();
359
360 LogFlow(("MAIN::hgcmMsgAlloc: allocated message %p\n", pmsg));
361
362 /** Get handle of the message. The message will be also referenced
363 * until the handle is deleted.
364 */
365 *pHandle = hgcmObjGenerateHandle (pmsg);
366
367 if (fFromFreeList)
368 {
369 /* Message was referenced in the free list, now dereference it. */
370 pmsg->Dereference ();
371 }
372 }
373
374 return rc;
375}
376
377int HGCMThread::MsgPost (HGCMMsgCore *pMsg, PHGCMMSGCALLBACK pfnCallback, bool fWait)
378{
379 int rc = VINF_SUCCESS;
380
381 LogFlow(("HGCMThread::MsgPost: thread = %p, pMsg = %p, pfnCallback = %p\n", this, pMsg, pfnCallback));
382
383 rc = Enter ();
384
385 if (VBOX_SUCCESS(rc))
386 {
387 pMsg->m_pfnCallback = pfnCallback;
388
389 /* Insert the message to the queue tail. */
390 pMsg->m_pNext = NULL;
391 pMsg->m_pPrev = m_pMsgInputQueueTail;
392
393 if (m_pMsgInputQueueTail)
394 {
395 m_pMsgInputQueueTail->m_pNext = pMsg;
396 }
397 else
398 {
399 m_pMsgInputQueueHead = pMsg;
400 }
401
402 m_pMsgInputQueueTail = pMsg;
403
404 Leave ();
405
406 LogFlow(("HGCMThread::MsgPost: going to inform the thread %p about message, fWait = %d\n", this, fWait));
407
408 if (fWait)
409 {
410 pMsg->m_fu32Flags |= HGCM_MSG_F_WAIT;
411 }
412
413 /* Inform the worker thread that there is a message. */
414 RTSemEventMultiSignal (m_eventThread);
415
416 LogFlow(("HGCMThread::MsgPost: event signalled\n"));
417
418 if (fWait)
419 {
420 while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
421 {
422 RTSemEventMultiWait (m_eventSend, RT_INDEFINITE_WAIT);
423 RTSemEventMultiReset (m_eventSend);
424
425 LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags));
426 }
427
428 rc = pMsg->m_rcSend;
429 }
430 }
431
432 LogFlow(("HGCMThread::MsgPost: rc = %Vrc\n", rc));
433
434 return rc;
435}
436
437
438int HGCMThread::MsgGet (HGCMMsgCore **ppMsg)
439{
440 int rc = VINF_SUCCESS;
441
442 LogFlow(("HGCMThread::MsgGet: thread = %p, ppMsg = %p\n", this, ppMsg));
443
444 for (;;)
445 {
446 if (m_fu32ThreadFlags & HGCMMSG_TF_TERMINATE)
447 {
448 rc = VERR_INTERRUPTED;
449 break;
450 }
451
452 LogFlow(("MAIN::hgcmMsgGet: m_pMsgInputQueueHead = %p\n", m_pMsgInputQueueHead));
453
454 if (m_pMsgInputQueueHead)
455 {
456 /* Move the message to the m_pMsgInProcessHead list */
457 rc = Enter ();
458
459 if (VBOX_FAILURE (rc))
460 {
461 break;
462 }
463
464 HGCMMsgCore *pMsg = m_pMsgInputQueueHead;
465
466 /* Remove the message from the head of Queue list. */
467 Assert (m_pMsgInputQueueHead->m_pPrev == NULL);
468
469 if (m_pMsgInputQueueHead->m_pNext)
470 {
471 m_pMsgInputQueueHead = m_pMsgInputQueueHead->m_pNext;
472 m_pMsgInputQueueHead->m_pPrev = NULL;
473 }
474 else
475 {
476 Assert (m_pMsgInputQueueHead == m_pMsgInputQueueTail);
477
478 m_pMsgInputQueueHead = NULL;
479 m_pMsgInputQueueTail = NULL;
480 }
481
482 /* Insert the message to the tail of the m_pMsgInProcessHead list. */
483 pMsg->m_pNext = NULL;
484 pMsg->m_pPrev = m_pMsgInProcessTail;
485
486 if (m_pMsgInProcessTail)
487 {
488 m_pMsgInProcessTail->m_pNext = pMsg;
489 }
490 else
491 {
492 m_pMsgInProcessHead = pMsg;
493 }
494
495 m_pMsgInProcessTail = pMsg;
496
497 pMsg->m_fu32Flags |= HGCM_MSG_F_IN_PROCESS;
498
499 Leave ();
500
501 /* Return the message to the caller. */
502 *ppMsg = pMsg;
503
504 LogFlow(("MAIN::hgcmMsgGet: got message %p\n", *ppMsg));
505
506 break;
507 }
508
509 /* Wait for an event. */
510 RTSemEventMultiWait (m_eventThread, RT_INDEFINITE_WAIT);
511 RTSemEventMultiReset (m_eventThread);
512 }
513
514 LogFlow(("HGCMThread::MsgGet: *ppMsg = %p, return rc = %Vrc\n", *ppMsg, rc));
515
516 return rc;
517}
518
519void HGCMThread::MsgComplete (HGCMMsgCore *pMsg, int32_t result)
520{
521 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p\n", this, pMsg));
522
523 int rc = VINF_SUCCESS;
524
525 AssertRelease(pMsg->m_pThread == this);
526 AssertRelease((pMsg->m_fu32Flags & HGCM_MSG_F_IN_PROCESS) != 0);
527
528 if (pMsg->m_pfnCallback)
529 {
530 /** @todo call callback with error code in MsgPost in case of errors */
531
532 pMsg->m_pfnCallback (result, pMsg);
533
534 LogFlow(("HGCMThread::MsgComplete: callback executed. pMsg = %p, thread = %p\n", pMsg, this));
535 }
536
537 /* Message processing has been completed. */
538
539 rc = Enter ();
540
541 if (VBOX_SUCCESS(rc))
542 {
543 /* Remove the message from the InProcess queue. */
544
545 if (pMsg->m_pNext)
546 {
547 pMsg->m_pNext->m_pPrev = pMsg->m_pPrev;
548 }
549 else
550 {
551 m_pMsgInProcessTail = pMsg->m_pPrev;
552 }
553
554 if (pMsg->m_pPrev)
555 {
556 pMsg->m_pPrev->m_pNext = pMsg->m_pNext;
557 }
558 else
559 {
560 m_pMsgInProcessHead = pMsg->m_pNext;
561 }
562
563 pMsg->m_pNext = NULL;
564 pMsg->m_pPrev = NULL;
565
566 bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0);
567
568 /* The message is now completed. */
569 pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS;
570 pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT;
571 pMsg->m_fu32Flags |= HGCM_MSG_F_PROCESSED;
572
573 Leave ();
574
575 if (fWaited)
576 {
577 pMsg->m_rcSend = result;
578
579 /* Wake up all waiters. so they can decide if their message has been processed. */
580 RTSemEventMultiSignal (m_eventSend);
581 }
582
583 hgcmObjDeleteHandle (pMsg->Handle ());
584 }
585
586 return;
587}
588
589/*
590 * Thread API. Public interface.
591 */
592
593int hgcmThreadCreate (HGCMTHREADHANDLE *pHandle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser, uint32_t cbMsg)
594{
595 int rc = VINF_SUCCESS;
596
597 LogFlow(("MAIN::hgcmThreadCreate\n"));
598
599 HGCMTHREADHANDLE handle = 0;
600
601 /* Allocate memory for a new thread object. */
602 HGCMThread *pThread = new HGCMThread ();
603
604 if (pThread)
605 {
606 /* Put just created object to pool and obtain handle for it. */
607 handle = hgcmObjGenerateHandle (pThread);
608
609 /* Initialize the object. */
610 rc = pThread->Initialize (handle, pszThreadName, pfnThread, pvUser, cbMsg);
611 }
612 else
613 {
614 Log(("hgcmThreadCreate: FAILURE: Can't allocate memory for a hgcm worker thread.\n"));
615 rc = VERR_NO_MEMORY;
616 }
617
618 if (VBOX_SUCCESS (rc))
619 {
620 *pHandle = handle;
621 }
622 else
623 {
624 Log(("hgcmThreadCreate: FAILURE: rc = %Vrc.\n", rc));
625
626 if (handle != 0)
627 {
628 /* Delete allocated handle, this will also free the object memory. */
629 hgcmObjDeleteHandle (handle);
630 }
631 }
632
633 LogFlow(("MAIN::hgcmThreadCreate: rc = %Vrc\n", rc));
634
635 return rc;
636}
637
638int hgcmMsgAlloc (HGCMTHREADHANDLE hThread, HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, uint32_t cbMsg, PFNHGCMNEWMSGALLOC pfnNewMessage)
639{
640 LogFlow(("hgcmMsgAlloc: thread handle = %d, pHandle = %p, cbMsg = %d, sizeof (HGCMMsgCore) = %d\n", hThread, pHandle, cbMsg, sizeof (HGCMMsgCore)));
641
642 if (!pHandle || cbMsg < sizeof (HGCMMsgCore))
643 {
644 return VERR_INVALID_PARAMETER;
645 }
646
647 int rc = VINF_SUCCESS;
648
649 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
650
651 if (!pThread)
652 {
653 rc = VERR_INVALID_HANDLE;
654 }
655 else
656 {
657 rc = pThread->MsgAlloc (pHandle, u32MsgId, cbMsg, pfnNewMessage);
658
659 hgcmObjDereference (pThread);
660 }
661
662 LogFlow(("MAIN::hgcmMsgAlloc: handle %d, rc = %Vrc\n", *pHandle, rc));
663
664 return rc;
665}
666
667static int hgcmMsgPostInternal (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback, bool fWait)
668{
669 LogFlow(("MAIN::hgcmMsgPostInternal: hMsg = %d, pfnCallback = %p, fWait = %d\n", hMsg, pfnCallback, fWait));
670
671 int rc = VINF_SUCCESS;
672
673 HGCMMsgCore *pMsg = (HGCMMsgCore *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
674
675 if (!pMsg)
676 {
677 rc = VERR_INVALID_HANDLE;
678 }
679 else
680 {
681 rc = pMsg->Thread()->MsgPost (pMsg, pfnCallback, fWait);
682
683 hgcmObjDereference (pMsg);
684 }
685
686 LogFlow(("MAIN::hgcmMsgPostInternal: hMsg %d, rc = %Vrc\n", hMsg, rc));
687
688 return rc;
689}
690
691
692/* Post message to worker thread with a flag indication if this is a Send or Post.
693 *
694 * @thread any
695 */
696
697int hgcmMsgPost (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback)
698{
699 return hgcmMsgPostInternal (hMsg, pfnCallback, false);
700}
701
702/* Send message to worker thread. Sending thread will block until message is processed.
703 *
704 * @thread any
705 */
706
707int hgcmMsgSend (HGCMMSGHANDLE hMsg)
708{
709 return hgcmMsgPostInternal (hMsg, NULL, true);
710}
711
712
713int hgcmMsgGet (HGCMTHREADHANDLE hThread, HGCMMsgCore **ppMsg)
714{
715 LogFlow(("MAIN::hgcmMsgGet: hThread = %d, ppMsg = %p\n", hThread, ppMsg));
716
717 if (!hThread || !ppMsg)
718 {
719 return VERR_INVALID_PARAMETER;
720 }
721
722 int rc = VINF_SUCCESS;
723
724 HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
725
726 if (!pThread)
727 {
728 rc = VERR_INVALID_HANDLE;
729 }
730 else
731 {
732 rc = pThread->MsgGet (ppMsg);
733
734 hgcmObjDereference (pThread);
735 }
736
737 LogFlow(("MAIN::hgcmMsgGet: *ppMsg = %p, rc = %Vrc\n", *ppMsg, rc));
738
739 return rc;
740}
741
742
743void hgcmMsgComplete (HGCMMsgCore *pMsg, int32_t u32Result)
744{
745 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p\n", pMsg));
746
747 if (!pMsg)
748 {
749 return;
750 }
751
752 pMsg->Thread()->MsgComplete (pMsg, u32Result);
753
754 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rc = void\n", pMsg));
755
756 return;
757}
758
759
760int hgcmThreadInit (void)
761{
762 int rc = VINF_SUCCESS;
763
764 LogFlow(("MAIN::hgcmThreadInit\n"));
765
766 /** @todo error processing. */
767
768 rc = hgcmObjInit ();
769
770 LogFlow(("MAIN::hgcmThreadInit: rc = %Vrc\n", rc));
771
772 return rc;
773}
774
775void hgcmThreadUninit (void)
776{
777 hgcmObjUninit ();
778}
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