VirtualBox

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

Last change on this file was 98278, checked in by vboxsync, 16 months ago

Main/src-client: Some more rc -> hrc/vrc stuff found by grep. A build fix. bugref:10223

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

© 2023 Oracle
ContactPrivacy policyTerms of Use