1
/* $Id: PDMThread.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
3
* PDM Thread - VM Thread Management.
7
* Copyright (C) 2007 Oracle Corporation
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
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.
18
/*******************************************************************************
20
*******************************************************************************/
21
///@todo #define LOG_GROUP LOG_GROUP_PDM_THREAD
22
#include "PDMInternal.h"
23
#include <VBox/vmm/pdm.h>
24
#include <VBox/vmm/mm.h>
25
#include <VBox/vmm/vm.h>
26
#include <VBox/vmm/uvm.h>
31
#include <iprt/semaphore.h>
32
#include <iprt/assert.h>
33
#include <iprt/thread.h>
36
/*******************************************************************************
37
* Internal Functions *
38
*******************************************************************************/
39
static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser);
43
* Wrapper around ASMAtomicCmpXchgSize.
45
DECLINLINE(bool) pdmR3AtomicCmpXchgState(PPDMTHREAD pThread, PDMTHREADSTATE enmNewState, PDMTHREADSTATE enmOldState)
48
ASMAtomicCmpXchgSize(&pThread->enmState, enmNewState, enmOldState, fRc);
54
* Does the wakeup call.
56
* @returns VBox status code. Already asserted on failure.
57
* @param pThread The PDM thread.
59
static DECLCALLBACK(int) pdmR3ThreadWakeUp(PPDMTHREAD pThread)
61
RTSemEventMultiSignal(pThread->Internal.s.SleepEvent);
64
switch (pThread->Internal.s.enmType)
66
case PDMTHREADTYPE_DEVICE:
67
rc = pThread->u.Dev.pfnWakeUp(pThread->u.Dev.pDevIns, pThread);
70
case PDMTHREADTYPE_USB:
71
rc = pThread->u.Usb.pfnWakeUp(pThread->u.Usb.pUsbIns, pThread);
74
case PDMTHREADTYPE_DRIVER:
75
rc = pThread->u.Drv.pfnWakeUp(pThread->u.Drv.pDrvIns, pThread);
78
case PDMTHREADTYPE_INTERNAL:
79
rc = pThread->u.Int.pfnWakeUp(pThread->Internal.s.pVM, pThread);
82
case PDMTHREADTYPE_EXTERNAL:
83
rc = pThread->u.Ext.pfnWakeUp(pThread);
87
AssertMsgFailed(("%d\n", pThread->Internal.s.enmType));
88
rc = VERR_INTERNAL_ERROR;
97
* Allocates new thread instance.
99
* @returns VBox status code.
100
* @param pVM The VM handle.
101
* @param ppThread Where to store the pointer to the instance.
103
static int pdmR3ThreadNew(PVM pVM, PPPDMTHREAD ppThread)
106
int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_THREAD, sizeof(*pThread), (void **)&pThread);
110
pThread->u32Version = PDMTHREAD_VERSION;
111
pThread->enmState = PDMTHREADSTATE_INITIALIZING;
112
pThread->Thread = NIL_RTTHREAD;
113
pThread->Internal.s.pVM = pVM;
122
* Initialize a new thread, this actually creates the thread.
124
* @returns VBox status code.
125
* @param pVM The VM handle.
126
* @param ppThread Where the thread instance data handle is.
127
* @param cbStack The stack size, see RTThreadCreate().
128
* @param enmType The thread type, see RTThreadCreate().
129
* @param pszName The thread name, see RTThreadCreate().
131
static int pdmR3ThreadInit(PVM pVM, PPPDMTHREAD ppThread, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
133
PPDMTHREAD pThread = *ppThread;
134
PUVM pUVM = pVM->pUVM;
137
* Initialize the remainder of the structure.
139
pThread->Internal.s.pVM = pVM;
141
int rc = RTSemEventMultiCreate(&pThread->Internal.s.BlockEvent);
144
rc = RTSemEventMultiCreate(&pThread->Internal.s.SleepEvent);
148
* Create the thread and wait for it to initialize.
149
* The newly created thread will set the PDMTHREAD::Thread member.
152
rc = RTThreadCreate(&Thread, pdmR3ThreadMain, pThread, cbStack, enmType, RTTHREADFLAGS_WAITABLE, pszName);
155
rc = RTThreadUserWait(Thread, 60*1000);
157
&& pThread->enmState != PDMTHREADSTATE_SUSPENDED)
158
rc = VERR_INTERNAL_ERROR;
162
* Insert it into the thread list.
164
RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
165
pThread->Internal.s.pNext = NULL;
166
if (pUVM->pdm.s.pThreadsTail)
167
pUVM->pdm.s.pThreadsTail->Internal.s.pNext = pThread;
169
pUVM->pdm.s.pThreads = pThread;
170
pUVM->pdm.s.pThreadsTail = pThread;
171
RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
173
rc = RTThreadUserReset(Thread);
179
RTThreadWait(Thread, 60*1000, NULL);
181
RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent);
182
pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI;
184
RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent);
185
pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI;
187
MMHyperFree(pVM, pThread);
195
* Device Helper for creating a thread associated with a device.
197
* @returns VBox status code.
198
* @param pVM The VM handle.
199
* @param pDevIns The device instance.
200
* @param ppThread Where to store the thread 'handle'.
201
* @param pvUser The user argument to the thread function.
202
* @param pfnThread The thread function.
203
* @param pfnWakeUp The wakup callback. This is called on the EMT thread when
204
* a state change is pending.
205
* @param cbStack See RTThreadCreate.
206
* @param enmType See RTThreadCreate.
207
* @param pszName See RTThreadCreate.
209
int pdmR3ThreadCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread,
210
PFNPDMTHREADWAKEUPDEV pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
212
int rc = pdmR3ThreadNew(pVM, ppThread);
215
PPDMTHREAD pThread = *ppThread;
216
pThread->pvUser = pvUser;
217
pThread->Internal.s.enmType = PDMTHREADTYPE_DEVICE;
218
pThread->u.Dev.pDevIns = pDevIns;
219
pThread->u.Dev.pfnThread = pfnThread;
220
pThread->u.Dev.pfnWakeUp = pfnWakeUp;
221
rc = pdmR3ThreadInit(pVM, ppThread, cbStack, enmType, pszName);
228
* USB Device Helper for creating a thread associated with an USB device.
230
* @returns VBox status code.
231
* @param pVM The VM handle.
232
* @param pUsbIns The USB device instance.
233
* @param ppThread Where to store the thread 'handle'.
234
* @param pvUser The user argument to the thread function.
235
* @param pfnThread The thread function.
236
* @param pfnWakeUp The wakup callback. This is called on the EMT thread when
237
* a state change is pending.
238
* @param cbStack See RTThreadCreate.
239
* @param enmType See RTThreadCreate.
240
* @param pszName See RTThreadCreate.
242
int pdmR3ThreadCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread,
243
PFNPDMTHREADWAKEUPUSB pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
245
int rc = pdmR3ThreadNew(pVM, ppThread);
248
PPDMTHREAD pThread = *ppThread;
249
pThread->pvUser = pvUser;
250
pThread->Internal.s.enmType = PDMTHREADTYPE_USB;
251
pThread->u.Usb.pUsbIns = pUsbIns;
252
pThread->u.Usb.pfnThread = pfnThread;
253
pThread->u.Usb.pfnWakeUp = pfnWakeUp;
254
rc = pdmR3ThreadInit(pVM, ppThread, cbStack, enmType, pszName);
261
* Driver Helper for creating a thread associated with a driver.
263
* @returns VBox status code.
264
* @param pVM The VM handle.
265
* @param pDrvIns The driver instance.
266
* @param ppThread Where to store the thread 'handle'.
267
* @param pvUser The user argument to the thread function.
268
* @param pfnThread The thread function.
269
* @param pfnWakeUp The wakup callback. This is called on the EMT thread when
270
* a state change is pending.
271
* @param cbStack See RTThreadCreate.
272
* @param enmType See RTThreadCreate.
273
* @param pszName See RTThreadCreate.
275
int pdmR3ThreadCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
276
PFNPDMTHREADWAKEUPDRV pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
278
int rc = pdmR3ThreadNew(pVM, ppThread);
281
PPDMTHREAD pThread = *ppThread;
282
pThread->pvUser = pvUser;
283
pThread->Internal.s.enmType = PDMTHREADTYPE_DRIVER;
284
pThread->u.Drv.pDrvIns = pDrvIns;
285
pThread->u.Drv.pfnThread = pfnThread;
286
pThread->u.Drv.pfnWakeUp = pfnWakeUp;
287
rc = pdmR3ThreadInit(pVM, ppThread, cbStack, enmType, pszName);
294
* Creates a PDM thread for internal use in the VM.
296
* @returns VBox status code.
297
* @param pVM The VM handle.
298
* @param ppThread Where to store the thread 'handle'.
299
* @param pvUser The user argument to the thread function.
300
* @param pfnThread The thread function.
301
* @param pfnWakeUp The wakup callback. This is called on the EMT thread when
302
* a state change is pending.
303
* @param cbStack See RTThreadCreate.
304
* @param enmType See RTThreadCreate.
305
* @param pszName See RTThreadCreate.
307
VMMR3DECL(int) PDMR3ThreadCreate(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADINT pfnThread,
308
PFNPDMTHREADWAKEUPINT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
310
int rc = pdmR3ThreadNew(pVM, ppThread);
313
PPDMTHREAD pThread = *ppThread;
314
pThread->pvUser = pvUser;
315
pThread->Internal.s.enmType = PDMTHREADTYPE_INTERNAL;
316
pThread->u.Int.pfnThread = pfnThread;
317
pThread->u.Int.pfnWakeUp = pfnWakeUp;
318
rc = pdmR3ThreadInit(pVM, ppThread, cbStack, enmType, pszName);
325
* Creates a PDM thread for VM use by some external party.
327
* @returns VBox status code.
328
* @param pVM The VM handle.
329
* @param ppThread Where to store the thread 'handle'.
330
* @param pvUser The user argument to the thread function.
331
* @param pfnThread The thread function.
332
* @param pfnWakeUp The wakup callback. This is called on the EMT thread when
333
* a state change is pending.
334
* @param cbStack See RTThreadCreate.
335
* @param enmType See RTThreadCreate.
336
* @param pszName See RTThreadCreate.
338
VMMR3DECL(int) PDMR3ThreadCreateExternal(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADEXT pfnThread,
339
PFNPDMTHREADWAKEUPEXT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
341
int rc = pdmR3ThreadNew(pVM, ppThread);
344
PPDMTHREAD pThread = *ppThread;
345
pThread->pvUser = pvUser;
346
pThread->Internal.s.enmType = PDMTHREADTYPE_EXTERNAL;
347
pThread->u.Ext.pfnThread = pfnThread;
348
pThread->u.Ext.pfnWakeUp = pfnWakeUp;
349
rc = pdmR3ThreadInit(pVM, ppThread, cbStack, enmType, pszName);
356
* Destroys a PDM thread.
358
* This will wakeup the thread, tell it to terminate, and wait for it terminate.
360
* @returns VBox status code.
361
* This reflects the success off destroying the thread and not the exit code
362
* of the thread as this is stored in *pRcThread.
363
* @param pThread The thread to destroy.
364
* @param pRcThread Where to store the thread exit code. Optional.
365
* @thread The emulation thread (EMT).
367
VMMR3DECL(int) PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread)
372
AssertPtrReturn(pThread, VERR_INVALID_POINTER);
373
AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
374
Assert(pThread->Thread != RTThreadSelf());
375
AssertPtrNullReturn(pRcThread, VERR_INVALID_POINTER);
376
PVM pVM = pThread->Internal.s.pVM;
378
PUVM pUVM = pVM->pUVM;
381
* Advance the thread to the terminating state.
383
int rc = VINF_SUCCESS;
384
if (pThread->enmState <= PDMTHREADSTATE_TERMINATING)
388
PDMTHREADSTATE enmState = pThread->enmState;
391
case PDMTHREADSTATE_RUNNING:
392
if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
394
rc = pdmR3ThreadWakeUp(pThread);
397
case PDMTHREADSTATE_SUSPENDED:
398
case PDMTHREADSTATE_SUSPENDING:
399
case PDMTHREADSTATE_RESUMING:
400
case PDMTHREADSTATE_INITIALIZING:
401
if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
405
case PDMTHREADSTATE_TERMINATING:
406
case PDMTHREADSTATE_TERMINATED:
410
AssertMsgFailed(("enmState=%d\n", enmState));
411
rc = VERR_INTERNAL_ERROR;
417
int rc2 = RTSemEventMultiSignal(pThread->Internal.s.BlockEvent);
421
* Wait for it to terminate and the do cleanups.
423
rc2 = RTThreadWait(pThread->Thread, RT_SUCCESS(rc) ? 60*1000 : 150, pRcThread);
426
/* make it invalid. */
427
pThread->u32Version = 0xffffffff;
428
pThread->enmState = PDMTHREADSTATE_INVALID;
429
pThread->Thread = NIL_RTTHREAD;
432
RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
433
if (pUVM->pdm.s.pThreads == pThread)
435
pUVM->pdm.s.pThreads = pThread->Internal.s.pNext;
436
if (!pThread->Internal.s.pNext)
437
pUVM->pdm.s.pThreadsTail = NULL;
441
PPDMTHREAD pPrev = pUVM->pdm.s.pThreads;
442
while (pPrev && pPrev->Internal.s.pNext != pThread)
443
pPrev = pPrev->Internal.s.pNext;
446
pPrev->Internal.s.pNext = pThread->Internal.s.pNext;
447
if (!pThread->Internal.s.pNext)
448
pUVM->pdm.s.pThreadsTail = pPrev;
450
pThread->Internal.s.pNext = NULL;
451
RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
453
/* free the resources */
454
RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent);
455
pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI;
457
RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent);
458
pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI;
460
MMR3HeapFree(pThread);
462
else if (RT_SUCCESS(rc))
470
* Destroys all threads associated with a device.
472
* This function is called by PDMDevice when a device is
473
* destroyed (not currently implemented).
475
* @returns VBox status code of the first failure.
476
* @param pVM The VM handle.
477
* @param pDevIns the device instance.
479
int pdmR3ThreadDestroyDevice(PVM pVM, PPDMDEVINS pDevIns)
481
int rc = VINF_SUCCESS;
482
PUVM pUVM = pVM->pUVM;
486
RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
487
PPDMTHREAD pThread = pUVM->pdm.s.pThreads;
490
PPDMTHREAD pNext = pThread->Internal.s.pNext;
491
if ( pThread->Internal.s.enmType == PDMTHREADTYPE_DEVICE
492
&& pThread->u.Dev.pDevIns == pDevIns)
494
int rc2 = PDMR3ThreadDestroy(pThread, NULL);
495
if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
500
RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
506
* Destroys all threads associated with an USB device.
508
* This function is called by PDMUsb when a device is destroyed.
510
* @returns VBox status code of the first failure.
511
* @param pVM The VM handle.
512
* @param pUsbIns The USB device instance.
514
int pdmR3ThreadDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns)
516
int rc = VINF_SUCCESS;
517
PUVM pUVM = pVM->pUVM;
521
RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
522
PPDMTHREAD pThread = pUVM->pdm.s.pThreads;
525
PPDMTHREAD pNext = pThread->Internal.s.pNext;
526
if ( pThread->Internal.s.enmType == PDMTHREADTYPE_DEVICE
527
&& pThread->u.Usb.pUsbIns == pUsbIns)
529
int rc2 = PDMR3ThreadDestroy(pThread, NULL);
530
if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
535
RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
541
* Destroys all threads associated with a driver.
543
* This function is called by PDMDriver when a driver is destroyed.
545
* @returns VBox status code of the first failure.
546
* @param pVM The VM handle.
547
* @param pDrvIns The driver instance.
549
int pdmR3ThreadDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns)
551
int rc = VINF_SUCCESS;
552
PUVM pUVM = pVM->pUVM;
556
RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
557
PPDMTHREAD pThread = pUVM->pdm.s.pThreads;
560
PPDMTHREAD pNext = pThread->Internal.s.pNext;
561
if ( pThread->Internal.s.enmType == PDMTHREADTYPE_DRIVER
562
&& pThread->u.Drv.pDrvIns == pDrvIns)
564
int rc2 = PDMR3ThreadDestroy(pThread, NULL);
565
if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
570
RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
576
* Called For VM power off.
578
* @param pVM The VM handle.
580
void pdmR3ThreadDestroyAll(PVM pVM)
582
PUVM pUVM = pVM->pUVM;
583
RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
584
PPDMTHREAD pThread = pUVM->pdm.s.pThreads;
587
PPDMTHREAD pNext = pThread->Internal.s.pNext;
588
int rc2 = PDMR3ThreadDestroy(pThread, NULL);
592
Assert(!pUVM->pdm.s.pThreads && !pUVM->pdm.s.pThreadsTail);
593
RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
598
* Initiate termination of the thread (self) because something failed in a bad way.
600
* @param pThread The PDM thread.
602
static void pdmR3ThreadBailMeOut(PPDMTHREAD pThread)
606
PDMTHREADSTATE enmState = pThread->enmState;
609
case PDMTHREADSTATE_SUSPENDING:
610
case PDMTHREADSTATE_SUSPENDED:
611
case PDMTHREADSTATE_RESUMING:
612
case PDMTHREADSTATE_RUNNING:
613
if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
617
case PDMTHREADSTATE_TERMINATING:
618
case PDMTHREADSTATE_TERMINATED:
621
case PDMTHREADSTATE_INITIALIZING:
623
AssertMsgFailed(("enmState=%d\n", enmState));
632
* Called by the PDM thread in response to a wakeup call with
633
* suspending as the new state.
635
* The thread will block in side this call until the state is changed in
636
* response to a VM state change or to the device/driver/whatever calling the
637
* PDMR3ThreadResume API.
639
* @returns VBox status code.
640
* On failure, terminate the thread.
641
* @param pThread The PDM thread.
643
VMMR3DECL(int) PDMR3ThreadIAmSuspending(PPDMTHREAD pThread)
649
AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
650
Assert(pThread->Thread == RTThreadSelf() || pThread->enmState == PDMTHREADSTATE_INITIALIZING);
651
PDMTHREADSTATE enmState = pThread->enmState;
652
Assert( enmState == PDMTHREADSTATE_SUSPENDING
653
|| enmState == PDMTHREADSTATE_INITIALIZING);
656
* Update the state, notify the control thread (the API caller) and go to sleep.
658
int rc = VERR_WRONG_ORDER;
659
if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDED, enmState))
661
rc = RTThreadUserSignal(pThread->Thread);
664
rc = RTSemEventMultiWait(pThread->Internal.s.BlockEvent, RT_INDEFINITE_WAIT);
666
&& pThread->enmState != PDMTHREADSTATE_SUSPENDED)
670
rc = VERR_INTERNAL_ERROR;
674
AssertMsgFailed(("rc=%d enmState=%d\n", rc, pThread->enmState));
675
pdmR3ThreadBailMeOut(pThread);
681
* Called by the PDM thread in response to a resuming state.
683
* The purpose of this API is to tell the PDMR3ThreadResume caller that
684
* the PDM thread has successfully resumed. It will also do the
685
* state transition from the resuming to the running state.
687
* @returns VBox status code.
688
* On failure, terminate the thread.
689
* @param pThread The PDM thread.
691
VMMR3DECL(int) PDMR3ThreadIAmRunning(PPDMTHREAD pThread)
696
Assert(pThread->enmState == PDMTHREADSTATE_RESUMING);
697
Assert(pThread->Thread == RTThreadSelf());
700
* Update the state and tell the control thread (the guy calling the resume API).
702
int rc = VERR_WRONG_ORDER;
703
if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_RUNNING, PDMTHREADSTATE_RESUMING))
705
rc = RTThreadUserSignal(pThread->Thread);
710
AssertMsgFailed(("rc=%d enmState=%d\n", rc, pThread->enmState));
711
pdmR3ThreadBailMeOut(pThread);
717
* Called by the PDM thread instead of RTThreadSleep.
719
* The difference is that the sleep will be interrupted on state change. The
720
* thread must be in the running state, otherwise it will return immediately.
722
* @returns VBox status code.
723
* @retval VINF_SUCCESS on success or state change.
724
* @retval VERR_INTERRUPTED on signal or APC.
726
* @param pThread The PDM thread.
727
* @param cMillies The number of milliseconds to sleep.
729
VMMR3DECL(int) PDMR3ThreadSleep(PPDMTHREAD pThread, RTMSINTERVAL cMillies)
734
AssertReturn(pThread->enmState > PDMTHREADSTATE_INVALID && pThread->enmState < PDMTHREADSTATE_TERMINATED, VERR_INTERNAL_ERROR);
735
AssertReturn(pThread->Thread == RTThreadSelf(), VERR_INTERNAL_ERROR);
738
* Reset the event semaphore, check the state and sleep.
740
RTSemEventMultiReset(pThread->Internal.s.SleepEvent);
741
if (pThread->enmState != PDMTHREADSTATE_RUNNING)
743
return RTSemEventMultiWaitNoResume(pThread->Internal.s.SleepEvent, cMillies);
748
* The PDM thread function.
750
* @returns return from pfnThread.
752
* @param Thread The thread handle.
753
* @param pvUser Pointer to the PDMTHREAD structure.
755
static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser)
757
PPDMTHREAD pThread = (PPDMTHREAD)pvUser;
758
Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread)));
759
pThread->Thread = Thread;
764
* It handles simple thread functions which returns when they see a suspending
765
* request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning
771
switch (pThread->Internal.s.enmType)
773
case PDMTHREADTYPE_DEVICE:
774
rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread);
777
case PDMTHREADTYPE_USB:
778
rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread);
781
case PDMTHREADTYPE_DRIVER:
782
rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread);
785
case PDMTHREADTYPE_INTERNAL:
786
rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread);
789
case PDMTHREADTYPE_EXTERNAL:
790
rc = pThread->u.Ext.pfnThread(pThread);
794
AssertMsgFailed(("%d\n", pThread->Internal.s.enmType));
795
rc = VERR_INTERNAL_ERROR;
802
* If this is a simple thread function, the state will be suspending
803
* or initializing now. If it isn't we're supposed to terminate.
805
if ( pThread->enmState != PDMTHREADSTATE_SUSPENDING
806
&& pThread->enmState != PDMTHREADSTATE_INITIALIZING)
808
Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING);
811
rc = PDMR3ThreadIAmSuspending(pThread);
814
if (pThread->enmState != PDMTHREADSTATE_RESUMING)
816
Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING);
820
rc = PDMR3ThreadIAmRunning(pThread);
826
LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc));
829
* Advance the state to terminating and then on to terminated.
833
PDMTHREADSTATE enmState = pThread->enmState;
834
if ( enmState == PDMTHREADSTATE_TERMINATING
835
|| pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
839
ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED);
840
int rc2 = RTThreadUserSignal(Thread); AssertRC(rc2);
842
Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc));
848
* Initiate termination of the thread because something failed in a bad way.
850
* @param pThread The PDM thread.
852
static void pdmR3ThreadBailOut(PPDMTHREAD pThread)
856
PDMTHREADSTATE enmState = pThread->enmState;
859
case PDMTHREADSTATE_SUSPENDING:
860
case PDMTHREADSTATE_SUSPENDED:
861
if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
863
RTSemEventMultiSignal(pThread->Internal.s.BlockEvent);
866
case PDMTHREADSTATE_RESUMING:
867
if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
871
case PDMTHREADSTATE_RUNNING:
872
if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
874
pdmR3ThreadWakeUp(pThread);
877
case PDMTHREADSTATE_TERMINATING:
878
case PDMTHREADSTATE_TERMINATED:
881
case PDMTHREADSTATE_INITIALIZING:
883
AssertMsgFailed(("enmState=%d\n", enmState));
892
* Suspends the thread.
894
* This can be called at the power off / suspend notifications to suspend the
895
* PDM thread a bit early. The thread will be automatically suspend upon
896
* completion of the device/driver notification cycle.
898
* The caller is responsible for serializing the control operations on the
899
* thread. That basically means, always do these calls from the EMT.
901
* @returns VBox status code.
902
* @param pThread The PDM thread.
904
VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread)
909
AssertPtrReturn(pThread, VERR_INVALID_POINTER);
910
AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
911
Assert(pThread->Thread != RTThreadSelf());
914
* This is a noop if the thread is already suspended.
916
if (pThread->enmState == PDMTHREADSTATE_SUSPENDED)
920
* Change the state to resuming and kick the thread.
922
int rc = RTSemEventMultiReset(pThread->Internal.s.BlockEvent);
925
rc = RTThreadUserReset(pThread->Thread);
928
rc = VERR_WRONG_ORDER;
929
if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDING, PDMTHREADSTATE_RUNNING))
931
rc = pdmR3ThreadWakeUp(pThread);
935
* Wait for the thread to reach the suspended state.
937
if (pThread->enmState != PDMTHREADSTATE_SUSPENDED)
938
rc = RTThreadUserWait(pThread->Thread, 60*1000);
940
&& pThread->enmState != PDMTHREADSTATE_SUSPENDED)
941
rc = VERR_INTERNAL_ERROR;
950
* Something failed, initialize termination.
952
AssertMsgFailed(("PDMR3ThreadSuspend -> rc=%Rrc enmState=%d\n", rc, pThread->enmState));
953
pdmR3ThreadBailOut(pThread);
959
* Suspend all running threads.
961
* This is called by PDMR3Suspend() and PDMR3PowerOff() after all the devices
962
* and drivers have been notified about the suspend / power off.
964
* @return VBox status code.
965
* @param pVM The VM handle.
967
int pdmR3ThreadSuspendAll(PVM pVM)
969
PUVM pUVM = pVM->pUVM;
970
RTCritSectEnter(&pUVM->pdm.s.ListCritSect); /* This may cause deadlocks later... */
971
for (PPDMTHREAD pThread = pUVM->pdm.s.pThreads; pThread; pThread = pThread->Internal.s.pNext)
972
switch (pThread->enmState)
974
case PDMTHREADSTATE_RUNNING:
976
int rc = PDMR3ThreadSuspend(pThread);
977
AssertRCReturn(rc, rc);
981
/* suspend -> power off; voluntary suspend. */
982
case PDMTHREADSTATE_SUSPENDED:
986
AssertMsgFailed(("pThread=%p enmState=%d\n", pThread, pThread->enmState));
989
RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
995
* Resumes the thread.
997
* This can be called the power on / resume notifications to resume the
998
* PDM thread a bit early. The thread will be automatically resumed upon
999
* return from these two notification callbacks (devices/drivers).
1001
* The caller is responsible for serializing the control operations on the
1002
* thread. That basically means, always do these calls from the EMT.
1004
* @returns VBox status code.
1005
* @param pThread The PDM thread.
1007
VMMR3DECL(int) PDMR3ThreadResume(PPDMTHREAD pThread)
1012
AssertPtrReturn(pThread, VERR_INVALID_POINTER);
1013
AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
1014
Assert(pThread->Thread != RTThreadSelf());
1017
* Change the state to resuming and kick the thread.
1019
int rc = RTThreadUserReset(pThread->Thread);
1022
rc = VERR_WRONG_ORDER;
1023
if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_RESUMING, PDMTHREADSTATE_SUSPENDED))
1025
rc = RTSemEventMultiSignal(pThread->Internal.s.BlockEvent);
1029
* Wait for the thread to reach the running state.
1031
rc = RTThreadUserWait(pThread->Thread, 60*1000);
1033
&& pThread->enmState != PDMTHREADSTATE_RUNNING)
1034
rc = VERR_INTERNAL_ERROR;
1042
* Something failed, initialize termination.
1044
AssertMsgFailed(("PDMR3ThreadResume -> rc=%Rrc enmState=%d\n", rc, pThread->enmState));
1045
pdmR3ThreadBailOut(pThread);
1051
* Resumes all threads not running.
1053
* This is called by PDMR3Resume() and PDMR3PowerOn() after all the devices
1054
* and drivers have been notified about the resume / power on .
1056
* @return VBox status code.
1057
* @param pVM The VM handle.
1059
int pdmR3ThreadResumeAll(PVM pVM)
1061
PUVM pUVM = pVM->pUVM;
1062
RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1063
for (PPDMTHREAD pThread = pUVM->pdm.s.pThreads; pThread; pThread = pThread->Internal.s.pNext)
1064
switch (pThread->enmState)
1066
case PDMTHREADSTATE_SUSPENDED:
1068
int rc = PDMR3ThreadResume(pThread);
1069
AssertRCReturn(rc, rc);
1074
AssertMsgFailed(("pThread=%p enmState=%d\n", pThread, pThread->enmState));
1077
RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1078
return VINF_SUCCESS;