VirtualBox

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

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