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