VirtualBox

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

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

Implemented HGCM save/load state

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