VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/HGCMThread.cpp@ 86506

Last change on this file since 86506 was 85121, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.6 KB
RevLine 
[35374]1/* $Id: HGCMThread.cpp 85121 2020-07-08 19:33:26Z vboxsync $ */
[1]2/** @file
3 * HGCMThread - Host-Guest Communication Manager Threads
4 */
5
6/*
[82968]7 * Copyright (C) 2006-2020 Oracle Corporation
[1]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
[5999]12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
[1]16 */
17
[67914]18#define LOG_GROUP LOG_GROUP_HGCM
19#include "LoggingNew.h"
[1]20
[35374]21#include "HGCMThread.h"
[1]22
23#include <VBox/err.h>
[75498]24#include <VBox/vmm/stam.h>
[1]25#include <iprt/semaphore.h>
26#include <iprt/thread.h>
27#include <iprt/string.h>
28
[75540]29#include <new> /* for std:nothrow */
[1]30
[75540]31
[1]32/* HGCM uses worker threads, which process messages from other threads.
33 * A message consists of the message header and message specific data.
34 * Message header is opaque for callers, but message data is defined
35 * and used by them.
36 *
37 * Messages are distinguished by message identifier and worker thread
38 * they are allocated for.
39 *
40 * Messages are allocated for a worker thread and belong to
41 * the thread. A worker thread holds the queue of messages.
42 *
43 * The calling thread creates a message, specifying which worker thread
44 * the message is created for, then, optionally, initializes message
45 * specific data and, also optionally, references the message.
46 *
47 * Message then is posted or sent to worker thread by inserting
48 * it to the worker thread message queue and referencing the message.
49 * Worker thread then again may fetch next message.
50 *
51 * Upon processing the message the worker thread dereferences it.
52 * Dereferencing also automatically deletes message from the thread
53 * queue and frees memory allocated for the message, if no more
54 * references left. If there are references, the message remains
55 * in the queue.
56 *
57 */
58
59/* Version of HGCM message header */
60#define HGCMMSG_VERSION (1)
61
62/* Thread is initializing. */
63#define HGCMMSG_TF_INITIALIZING (0x00000001)
64/* Thread must be terminated. */
65#define HGCMMSG_TF_TERMINATE (0x00000002)
66/* Thread has been terminated. */
67#define HGCMMSG_TF_TERMINATED (0x00000004)
68
[1344]69/** @todo consider use of RTReq */
[1]70
[75539]71static DECLCALLBACK(int) hgcmWorkerThreadFunc(RTTHREAD ThreadSelf, void *pvUser);
[1]72
[75539]73class HGCMThread : public HGCMReferencedObject
[1]74{
75 private:
[75539]76 friend DECLCALLBACK(int) hgcmWorkerThreadFunc(RTTHREAD ThreadSelf, void *pvUser);
[1]77
78 /* Worker thread function. */
79 PFNHGCMTHREAD m_pfnThread;
80
81 /* A user supplied thread parameter. */
82 void *m_pvUser;
83
84 /* The thread runtime handle. */
[75539]85 RTTHREAD m_hThread;
[1]86
[75601]87 /** Event the thread waits for, signalled when a message to process is posted to
88 * the thread, automatically reset. */
89 RTSEMEVENT m_eventThread;
[1]90
91 /* A caller thread waits for completion of a SENT message on this event. */
92 RTSEMEVENTMULTI m_eventSend;
[29976]93 int32_t volatile m_i32MessagesProcessed;
[1]94
95 /* Critical section for accessing the thread data, mostly for message queues. */
96 RTCRITSECT m_critsect;
97
98 /* thread state/operation flags */
99 uint32_t m_fu32ThreadFlags;
100
101 /* Message queue variables. Messages are inserted at tail of message
[33540]102 * queue. They are consumed by worker thread sequentially. If a message was
[1]103 * consumed, it is removed from message queue.
104 */
105
106 /* Head of message queue. */
107 HGCMMsgCore *m_pMsgInputQueueHead;
108 /* Message which another message will be inserted after. */
109 HGCMMsgCore *m_pMsgInputQueueTail;
110
111 /* Head of messages being processed queue. */
112 HGCMMsgCore *m_pMsgInProcessHead;
113 /* Message which another message will be inserted after. */
114 HGCMMsgCore *m_pMsgInProcessTail;
115
116 /* Head of free message structures list. */
117 HGCMMsgCore *m_pFreeHead;
118 /* Tail of free message structures list. */
119 HGCMMsgCore *m_pFreeTail;
120
[75498]121 /** @name Statistics
122 * @{ */
123 STAMCOUNTER m_StatPostMsgNoPending;
124 STAMCOUNTER m_StatPostMsgOnePending;
125 STAMCOUNTER m_StatPostMsgTwoPending;
126 STAMCOUNTER m_StatPostMsgThreePending;
127 STAMCOUNTER m_StatPostMsgManyPending;
128 /** @} */
129
[75540]130 inline int Enter(void);
131 inline void Leave(void);
[1]132
[75540]133 HGCMMsgCore *FetchFreeListHead(void);
[1]134
135 protected:
[75540]136 virtual ~HGCMThread(void);
[1]137
138 public:
139
140 HGCMThread ();
141
[1788]142 int WaitForTermination (void);
143
[75539]144 int Initialize(const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser, const char *pszStatsSubDir, PUVM pUVM);
[1]145
[75541]146 int MsgAlloc(HGCMMsgCore **pMsg, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage);
[75539]147 int MsgGet(HGCMMsgCore **ppMsg);
[85121]148 int MsgPost(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback, bool bWait);
[75747]149 int MsgComplete(HGCMMsgCore *pMsg, int32_t result);
[1]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
[75539]161void HGCMMsgCore::InitializeCore(uint32_t u32MsgId, HGCMThread *pThread)
[1]162{
163 m_u32Version = HGCMMSG_VERSION;
164 m_u32Msg = u32MsgId;
165 m_pfnCallback = NULL;
166 m_pNext = NULL;
167 m_pPrev = NULL;
168 m_fu32Flags = 0;
169 m_rcSend = VINF_SUCCESS;
[75539]170 m_pThread = pThread;
171 pThread->Reference();
[1]172}
173
[75539]174/* virtual */ HGCMMsgCore::~HGCMMsgCore()
[1681]175{
176 if (m_pThread)
177 {
[75539]178 m_pThread->Dereference();
[1681]179 m_pThread = NULL;
180 }
181}
[1]182
183/*
184 * HGCMThread implementation.
185 */
186
[75539]187static DECLCALLBACK(int) hgcmWorkerThreadFunc(RTTHREAD hThreadSelf, void *pvUser)
[1]188{
189 HGCMThread *pThread = (HGCMThread *)pvUser;
190
191 LogFlow(("MAIN::hgcmWorkerThreadFunc: starting HGCM thread %p\n", pThread));
192
193 AssertRelease(pThread);
194
[75539]195 pThread->m_hThread = hThreadSelf;
[1]196 pThread->m_fu32ThreadFlags &= ~HGCMMSG_TF_INITIALIZING;
[75539]197 int rc = RTThreadUserSignal(hThreadSelf);
[26186]198 AssertRC(rc);
[1]199
[75539]200 pThread->m_pfnThread(pThread, pThread->m_pvUser);
[1]201
202 pThread->m_fu32ThreadFlags |= HGCMMSG_TF_TERMINATED;
203
204 LogFlow(("MAIN::hgcmWorkerThreadFunc: completed HGCM thread %p\n", pThread));
205
206 return rc;
207}
208
[75539]209HGCMThread::HGCMThread()
[1]210 :
[75539]211 HGCMReferencedObject(HGCMOBJ_THREAD),
212 m_pfnThread(NULL),
213 m_pvUser(NULL),
214 m_hThread(NIL_RTTHREAD),
[75601]215 m_eventThread(NIL_RTSEMEVENT),
[75539]216 m_eventSend(NIL_RTSEMEVENTMULTI),
217 m_i32MessagesProcessed(0),
218 m_fu32ThreadFlags(0),
219 m_pMsgInputQueueHead(NULL),
220 m_pMsgInputQueueTail(NULL),
221 m_pMsgInProcessHead(NULL),
222 m_pMsgInProcessTail(NULL),
223 m_pFreeHead(NULL),
224 m_pFreeTail(NULL)
[1]225{
[47117]226 RT_ZERO(m_critsect);
[1]227}
228
[75539]229HGCMThread::~HGCMThread()
[1]230{
231 /*
232 * Free resources allocated for the thread.
233 */
234
[3042]235 Assert(m_fu32ThreadFlags & HGCMMSG_TF_TERMINATED);
[1788]236
[75539]237 if (RTCritSectIsInitialized(&m_critsect))
238 RTCritSectDelete(&m_critsect);
[1]239
[75539]240 if (m_eventSend != NIL_RTSEMEVENTMULTI)
[1]241 {
[75539]242 RTSemEventMultiDestroy(m_eventSend);
243 m_eventSend = NIL_RTSEMEVENTMULTI;
[1]244 }
245
[75601]246 if (m_eventThread != NIL_RTSEMEVENT)
[1]247 {
[75601]248 RTSemEventDestroy(m_eventThread);
249 m_eventThread = NIL_RTSEMEVENT;
[1]250 }
[1788]251}
252
[75539]253int HGCMThread::WaitForTermination(void)
[1788]254{
255 int rc = VINF_SUCCESS;
256 LogFlowFunc(("\n"));
257
[75539]258 if (m_hThread != NIL_RTTHREAD)
[77191]259 {
[75539]260 rc = RTThreadWait(m_hThread, 5000, NULL);
[77191]261 m_hThread = NIL_RTTHREAD;
262 }
[1]263
[13837]264 LogFlowFunc(("rc = %Rrc\n", rc));
[1788]265 return rc;
[1]266}
267
[75539]268int HGCMThread::Initialize(const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser, const char *pszStatsSubDir, PUVM pUVM)
[1]269{
[75601]270 int rc = RTSemEventCreate(&m_eventThread);
[1]271
[13835]272 if (RT_SUCCESS(rc))
[1]273 {
[75539]274 rc = RTSemEventMultiCreate(&m_eventSend);
[1]275
[13835]276 if (RT_SUCCESS(rc))
[1]277 {
[75539]278 rc = RTCritSectInit(&m_critsect);
[1]279
[13835]280 if (RT_SUCCESS(rc))
[1]281 {
282 m_pfnThread = pfnThread;
283 m_pvUser = pvUser;
284
285 m_fu32ThreadFlags = HGCMMSG_TF_INITIALIZING;
286
[75539]287 RTTHREAD hThread;
288 rc = RTThreadCreate(&hThread, hgcmWorkerThreadFunc, this, 0, /* default stack size; some services
[51092]289 may need quite a bit */
[75539]290 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
291 pszThreadName);
[1]292
[13835]293 if (RT_SUCCESS(rc))
[1]294 {
[75498]295 /* Register statistics while the thread starts. */
296 if (pUVM)
297 {
298 STAMR3RegisterFU(pUVM, &m_StatPostMsgNoPending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
299 "Times a message was appended to an empty input queue.",
300 "/HGCM/%s/PostMsg0Pending", pszStatsSubDir);
301 STAMR3RegisterFU(pUVM, &m_StatPostMsgOnePending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
302 "Times a message was appended to input queue with only one pending message.",
303 "/HGCM/%s/PostMsg1Pending", pszStatsSubDir);
304 STAMR3RegisterFU(pUVM, &m_StatPostMsgTwoPending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
305 "Times a message was appended to input queue with only one pending message.",
306 "/HGCM/%s/PostMsg2Pending", pszStatsSubDir);
[77562]307 STAMR3RegisterFU(pUVM, &m_StatPostMsgThreePending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
[75498]308 "Times a message was appended to input queue with only one pending message.",
309 "/HGCM/%s/PostMsg3Pending", pszStatsSubDir);
310 STAMR3RegisterFU(pUVM, &m_StatPostMsgManyPending, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
311 "Times a message was appended to input queue with only one pending message.",
312 "/HGCM/%s/PostMsgManyPending", pszStatsSubDir);
313 }
314
315
[1]316 /* Wait until the thread is ready. */
[75539]317 rc = RTThreadUserWait(hThread, 30000);
[26186]318 AssertRC(rc);
319 Assert(!(m_fu32ThreadFlags & HGCMMSG_TF_INITIALIZING) || RT_FAILURE(rc));
[1]320 }
321 else
322 {
[75539]323 m_hThread = NIL_RTTHREAD;
[1]324 Log(("hgcmThreadCreate: FAILURE: Can't start worker thread.\n"));
325 }
326 }
327 else
328 {
329 Log(("hgcmThreadCreate: FAILURE: Can't init a critical section for a hgcm worker thread.\n"));
[47117]330 RT_ZERO(m_critsect);
[1]331 }
332 }
333 else
334 {
335 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a sent messages.\n"));
[75498]336 m_eventSend = NIL_RTSEMEVENTMULTI;
[1]337 }
338 }
339 else
340 {
341 Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a hgcm worker thread.\n"));
[75601]342 m_eventThread = NIL_RTSEMEVENT;
[1]343 }
344
345 return rc;
346}
347
[75539]348inline int HGCMThread::Enter(void)
[1]349{
[75539]350 int rc = RTCritSectEnter(&m_critsect);
[1]351
352#ifdef LOG_ENABLED
[21878]353 if (RT_FAILURE(rc))
[13837]354 Log(("HGCMThread::MsgPost: FAILURE: could not obtain worker thread mutex, rc = %Rrc!!!\n", rc));
[75539]355#endif
[1]356
357 return rc;
358}
359
[75539]360inline void HGCMThread::Leave(void)
[1]361{
[75539]362 RTCritSectLeave(&m_critsect);
[1]363}
364
365
[75541]366int HGCMThread::MsgAlloc(HGCMMsgCore **ppMsg, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
[1]367{
[75539]368 /** @todo Implement this free list / cache thingy. */
[1]369 HGCMMsgCore *pmsg = NULL;
370
371 bool fFromFreeList = false;
372
[75539]373 if (!pmsg)
[1]374 {
375 /* We have to allocate a new memory block. */
[75539]376 pmsg = pfnNewMessage(u32MsgId);
[75541]377 if (pmsg != NULL)
378 pmsg->Reference(); /* (it's created with zero references) */
379 else
[75539]380 return VERR_NO_MEMORY;
[1]381 }
382
[75539]383 /* Initialize just allocated message core */
384 pmsg->InitializeCore(u32MsgId, this);
[1]385
[75539]386 /* and the message specific data. */
387 pmsg->Initialize();
[1]388
[75539]389 LogFlow(("MAIN::hgcmMsgAlloc: allocated message %p\n", pmsg));
[1]390
[75541]391 *ppMsg = pmsg;
[1]392
[75539]393 if (fFromFreeList)
394 {
395 /* Message was referenced in the free list, now dereference it. */
396 pmsg->Dereference();
[1]397 }
398
[75539]399 return VINF_SUCCESS;
[1]400}
401
[85121]402int HGCMThread::MsgPost(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback, bool fWait)
[1]403{
404 LogFlow(("HGCMThread::MsgPost: thread = %p, pMsg = %p, pfnCallback = %p\n", this, pMsg, pfnCallback));
405
[75539]406 int rc = Enter();
[1]407
[13835]408 if (RT_SUCCESS(rc))
[1]409 {
410 pMsg->m_pfnCallback = pfnCallback;
411
[12651]412 if (fWait)
413 pMsg->m_fu32Flags |= HGCM_MSG_F_WAIT;
414
[1]415 /* Insert the message to the queue tail. */
416 pMsg->m_pNext = NULL;
[75498]417 HGCMMsgCore * const pPrev = m_pMsgInputQueueTail;
418 pMsg->m_pPrev = pPrev;
[1]419
[75498]420 if (pPrev)
[1]421 {
[75498]422 pPrev->m_pNext = pMsg;
423 if (!pPrev->m_pPrev)
424 STAM_REL_COUNTER_INC(&m_StatPostMsgOnePending);
425 else if (!pPrev->m_pPrev)
426 STAM_REL_COUNTER_INC(&m_StatPostMsgTwoPending);
427 else if (!pPrev->m_pPrev->m_pPrev)
428 STAM_REL_COUNTER_INC(&m_StatPostMsgThreePending);
429 else
430 STAM_REL_COUNTER_INC(&m_StatPostMsgManyPending);
[1]431 }
432 else
433 {
434 m_pMsgInputQueueHead = pMsg;
[75498]435 STAM_REL_COUNTER_INC(&m_StatPostMsgNoPending);
[1]436 }
437
438 m_pMsgInputQueueTail = pMsg;
439
[75539]440 Leave();
[1]441
442 LogFlow(("HGCMThread::MsgPost: going to inform the thread %p about message, fWait = %d\n", this, fWait));
443
444 /* Inform the worker thread that there is a message. */
[75601]445 RTSemEventSignal(m_eventThread);
[1]446
447 LogFlow(("HGCMThread::MsgPost: event signalled\n"));
448
449 if (fWait)
450 {
[29976]451 /* Immediately check if the message has been processed. */
[1]452 while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
453 {
[29976]454 /* Poll infrequently to make sure no completed message has been missed. */
[75601]455 RTSemEventMultiWait(m_eventSend, 1000);
[1]456
457 LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags));
[29976]458
459 if ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
460 RTThreadYield();
[1]461 }
462
[29976]463 /* 'Our' message has been processed, so should reset the semaphore.
464 * There is still possible that another message has been processed
465 * and the semaphore has been signalled again.
466 * Reset only if there are no other messages completed.
467 */
468 int32_t c = ASMAtomicDecS32(&m_i32MessagesProcessed);
469 Assert(c >= 0);
470 if (c == 0)
[75539]471 RTSemEventMultiReset(m_eventSend);
[29976]472
[1]473 rc = pMsg->m_rcSend;
474 }
475 }
476
[13837]477 LogFlow(("HGCMThread::MsgPost: rc = %Rrc\n", rc));
[1]478 return rc;
479}
480
481
[75539]482int HGCMThread::MsgGet(HGCMMsgCore **ppMsg)
[1]483{
484 int rc = VINF_SUCCESS;
485
486 LogFlow(("HGCMThread::MsgGet: thread = %p, ppMsg = %p\n", this, ppMsg));
487
488 for (;;)
489 {
490 if (m_fu32ThreadFlags & HGCMMSG_TF_TERMINATE)
491 {
492 rc = VERR_INTERRUPTED;
493 break;
494 }
495
496 LogFlow(("MAIN::hgcmMsgGet: m_pMsgInputQueueHead = %p\n", m_pMsgInputQueueHead));
497
498 if (m_pMsgInputQueueHead)
499 {
500 /* Move the message to the m_pMsgInProcessHead list */
[75539]501 rc = Enter();
[1]502
[21878]503 if (RT_FAILURE(rc))
[1]504 {
505 break;
506 }
507
508 HGCMMsgCore *pMsg = m_pMsgInputQueueHead;
509
510 /* Remove the message from the head of Queue list. */
[26186]511 Assert(m_pMsgInputQueueHead->m_pPrev == NULL);
[1]512
513 if (m_pMsgInputQueueHead->m_pNext)
514 {
515 m_pMsgInputQueueHead = m_pMsgInputQueueHead->m_pNext;
516 m_pMsgInputQueueHead->m_pPrev = NULL;
517 }
518 else
519 {
[26186]520 Assert(m_pMsgInputQueueHead == m_pMsgInputQueueTail);
[1]521
522 m_pMsgInputQueueHead = NULL;
523 m_pMsgInputQueueTail = NULL;
524 }
525
526 /* Insert the message to the tail of the m_pMsgInProcessHead list. */
527 pMsg->m_pNext = NULL;
528 pMsg->m_pPrev = m_pMsgInProcessTail;
529
530 if (m_pMsgInProcessTail)
531 m_pMsgInProcessTail->m_pNext = pMsg;
532 else
533 m_pMsgInProcessHead = pMsg;
534
535 m_pMsgInProcessTail = pMsg;
536
537 pMsg->m_fu32Flags |= HGCM_MSG_F_IN_PROCESS;
538
[75539]539 Leave();
[1]540
541 /* Return the message to the caller. */
542 *ppMsg = pMsg;
543
544 LogFlow(("MAIN::hgcmMsgGet: got message %p\n", *ppMsg));
545
546 break;
547 }
548
549 /* Wait for an event. */
[75601]550 RTSemEventWait(m_eventThread, RT_INDEFINITE_WAIT);
[1]551 }
552
[13837]553 LogFlow(("HGCMThread::MsgGet: *ppMsg = %p, return rc = %Rrc\n", *ppMsg, rc));
[1]554 return rc;
555}
556
[75747]557int HGCMThread::MsgComplete(HGCMMsgCore *pMsg, int32_t result)
[1]558{
[75798]559 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p, result = %Rrc (%d)\n", this, pMsg, result, result));
[1]560
561 AssertRelease(pMsg->m_pThread == this);
[1681]562 AssertReleaseMsg((pMsg->m_fu32Flags & HGCM_MSG_F_IN_PROCESS) != 0, ("%p %x\n", pMsg, pMsg->m_fu32Flags));
[1]563
[75747]564 int rcRet = VINF_SUCCESS;
[1]565 if (pMsg->m_pfnCallback)
566 {
567 /** @todo call callback with error code in MsgPost in case of errors */
568
[75747]569 rcRet = pMsg->m_pfnCallback(result, pMsg);
[1]570
[75747]571 LogFlow(("HGCMThread::MsgComplete: callback executed. pMsg = %p, thread = %p, rcRet = %Rrc\n", pMsg, this, rcRet));
[1]572 }
573
574 /* Message processing has been completed. */
575
[75539]576 int rc = Enter();
[1]577
[13835]578 if (RT_SUCCESS(rc))
[1]579 {
580 /* Remove the message from the InProcess queue. */
581
582 if (pMsg->m_pNext)
583 pMsg->m_pNext->m_pPrev = pMsg->m_pPrev;
584 else
585 m_pMsgInProcessTail = pMsg->m_pPrev;
586
587 if (pMsg->m_pPrev)
588 pMsg->m_pPrev->m_pNext = pMsg->m_pNext;
589 else
590 m_pMsgInProcessHead = pMsg->m_pNext;
591
592 pMsg->m_pNext = NULL;
593 pMsg->m_pPrev = NULL;
594
595 bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0);
596
[29976]597 if (fWaited)
598 {
599 ASMAtomicIncS32(&m_i32MessagesProcessed);
600
601 /* This should be done before setting the HGCM_MSG_F_PROCESSED flag. */
602 pMsg->m_rcSend = result;
603 }
604
[1]605 /* The message is now completed. */
606 pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS;
607 pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT;
608 pMsg->m_fu32Flags |= HGCM_MSG_F_PROCESSED;
609
[75541]610 pMsg->Dereference();
[1772]611
[75539]612 Leave();
[1]613
614 if (fWaited)
615 {
616 /* Wake up all waiters. so they can decide if their message has been processed. */
[75539]617 RTSemEventMultiSignal(m_eventSend);
[1]618 }
619 }
[75747]620
621 return rcRet;
[1]622}
623
624/*
625 * Thread API. Public interface.
626 */
627
[75539]628int hgcmThreadCreate(HGCMThread **ppThread, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser,
629 const char *pszStatsSubDir, PUVM pUVM)
[1]630{
631 LogFlow(("MAIN::hgcmThreadCreate\n"));
[75539]632 int rc;
[1]633
634 /* Allocate memory for a new thread object. */
[75539]635 HGCMThread *pThread = new (std::nothrow) HGCMThread();
[1]636
637 if (pThread)
638 {
[75539]639 pThread->Reference(); /* (it's created with zero references) */
[1]640
641 /* Initialize the object. */
[75539]642 rc = pThread->Initialize(pszThreadName, pfnThread, pvUser, pszStatsSubDir, pUVM);
643 if (RT_SUCCESS(rc))
644 {
645 *ppThread = pThread;
646 LogFlow(("MAIN::hgcmThreadCreate: rc = %Rrc\n", rc));
647 return rc;
648 }
649
650 Log(("hgcmThreadCreate: FAILURE: Initialize failed: rc = %Rrc\n", rc));
651
652 pThread->Dereference();
[1]653 }
654 else
655 {
656 Log(("hgcmThreadCreate: FAILURE: Can't allocate memory for a hgcm worker thread.\n"));
657 rc = VERR_NO_MEMORY;
658 }
[75539]659 *ppThread = NULL;
[1]660
[13837]661 LogFlow(("MAIN::hgcmThreadCreate: rc = %Rrc\n", rc));
[1]662 return rc;
663}
664
[75539]665int hgcmThreadWait(HGCMThread *pThread)
[1788]666{
[75539]667 LogFlowFunc(("%p\n", pThread));
[1788]668
[75539]669 int rc;
[1788]670 if (pThread)
671 {
[75539]672 rc = pThread->WaitForTermination();
[1788]673
[75539]674 pThread->Dereference();
[1788]675 }
[75539]676 else
677 rc = VERR_INVALID_HANDLE;
[1788]678
[13837]679 LogFlowFunc(("rc = %Rrc\n", rc));
[1788]680 return rc;
681}
682
[75541]683int hgcmMsgAlloc(HGCMThread *pThread, HGCMMsgCore **ppMsg, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
[1]684{
[75541]685 LogFlow(("hgcmMsgAlloc: pThread = %p, ppMsg = %p, sizeof (HGCMMsgCore) = %d\n", pThread, ppMsg, sizeof(HGCMMsgCore)));
[1]686
[75539]687 AssertReturn(pThread, VERR_INVALID_HANDLE);
[75541]688 AssertReturn(ppMsg, VERR_INVALID_PARAMETER);
[1]689
[75541]690 int rc = pThread->MsgAlloc(ppMsg, u32MsgId, pfnNewMessage);
[1]691
[75541]692 LogFlow(("MAIN::hgcmMsgAlloc: *ppMsg = %p, rc = %Rrc\n", *ppMsg, rc));
[1]693 return rc;
694}
695
[85121]696DECLINLINE(int) hgcmMsgPostInternal(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback, bool fWait)
[1]697{
[75541]698 LogFlow(("MAIN::hgcmMsgPostInternal: pMsg = %p, pfnCallback = %p, fWait = %d\n", pMsg, pfnCallback, fWait));
699 Assert(pMsg);
[1]700
[75541]701 pMsg->Reference(); /* paranoia? */
[1]702
[75541]703 int rc = pMsg->Thread()->MsgPost(pMsg, pfnCallback, fWait);
[1]704
[75541]705 pMsg->Dereference();
[1]706
[75990]707 LogFlow(("MAIN::hgcmMsgPostInternal: pMsg = %p, rc = %Rrc\n", pMsg, rc));
[1]708 return rc;
709}
710
[85121]711int hgcmMsgPost(HGCMMsgCore *pMsg, PFNHGCMMSGCALLBACK pfnCallback)
[1]712{
[75541]713 int rc = hgcmMsgPostInternal(pMsg, pfnCallback, false);
[1711]714
[21878]715 if (RT_SUCCESS(rc))
[1711]716 rc = VINF_HGCM_ASYNC_EXECUTE;
717
718 return rc;
[1]719}
720
[75541]721int hgcmMsgSend(HGCMMsgCore *pMsg)
[1]722{
[75541]723 return hgcmMsgPostInternal(pMsg, NULL, true);
[1]724}
725
[75539]726int hgcmMsgGet(HGCMThread *pThread, HGCMMsgCore **ppMsg)
[1]727{
[75539]728 LogFlow(("MAIN::hgcmMsgGet: pThread = %p, ppMsg = %p\n", pThread, ppMsg));
[1]729
[75539]730 AssertReturn(pThread, VERR_INVALID_HANDLE);
731 AssertReturn(ppMsg, VERR_INVALID_PARAMETER);
[1]732
[75539]733 pThread->Reference(); /* paranoia */
[1]734
[75539]735 int rc = pThread->MsgGet(ppMsg);
[1]736
[75539]737 pThread->Dereference();
[1]738
[13837]739 LogFlow(("MAIN::hgcmMsgGet: *ppMsg = %p, rc = %Rrc\n", *ppMsg, rc));
[1]740 return rc;
741}
742
[75798]743int hgcmMsgComplete(HGCMMsgCore *pMsg, int32_t rcMsg)
[1]744{
[75798]745 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rcMsg = %Rrc (%d)\n", pMsg, rcMsg, rcMsg));
[1]746
[75747]747 int rc;
[75539]748 if (pMsg)
[75798]749 rc = pMsg->Thread()->MsgComplete(pMsg, rcMsg);
[75747]750 else
751 rc = VINF_SUCCESS;
[1]752
[75798]753 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rcMsg =%Rrc (%d), returns rc = %Rrc\n", pMsg, rcMsg, rcMsg, rc));
[75747]754 return rc;
[1]755}
756
[75539]757int hgcmThreadInit(void)
[1]758{
759 LogFlow(("MAIN::hgcmThreadInit\n"));
760
761 /** @todo error processing. */
762
[75539]763 int rc = hgcmObjInit();
[1]764
[13837]765 LogFlow(("MAIN::hgcmThreadInit: rc = %Rrc\n", rc));
[1]766 return rc;
767}
768
[75539]769void hgcmThreadUninit(void)
[1]770{
[75539]771 hgcmObjUninit();
[1]772}
[75539]773
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use