~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/VMM/VMMR3/PDMThread.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: PDMThread.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
 
2
/** @file
 
3
 * PDM Thread - VM Thread Management.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2007 Oracle Corporation
 
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
 
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.
 
16
 */
 
17
 
 
18
/*******************************************************************************
 
19
*   Header Files                                                               *
 
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>
 
27
#include <VBox/err.h>
 
28
 
 
29
#include <VBox/log.h>
 
30
#include <iprt/asm.h>
 
31
#include <iprt/semaphore.h>
 
32
#include <iprt/assert.h>
 
33
#include <iprt/thread.h>
 
34
 
 
35
 
 
36
/*******************************************************************************
 
37
*   Internal Functions                                                         *
 
38
*******************************************************************************/
 
39
static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser);
 
40
 
 
41
 
 
42
/**
 
43
 * Wrapper around ASMAtomicCmpXchgSize.
 
44
 */
 
45
DECLINLINE(bool) pdmR3AtomicCmpXchgState(PPDMTHREAD pThread, PDMTHREADSTATE enmNewState, PDMTHREADSTATE enmOldState)
 
46
{
 
47
    bool fRc;
 
48
    ASMAtomicCmpXchgSize(&pThread->enmState, enmNewState, enmOldState, fRc);
 
49
    return fRc;
 
50
}
 
51
 
 
52
 
 
53
/**
 
54
 * Does the wakeup call.
 
55
 *
 
56
 * @returns VBox status code. Already asserted on failure.
 
57
 * @param   pThread     The PDM thread.
 
58
 */
 
59
static DECLCALLBACK(int) pdmR3ThreadWakeUp(PPDMTHREAD pThread)
 
60
{
 
61
    RTSemEventMultiSignal(pThread->Internal.s.SleepEvent);
 
62
 
 
63
    int rc;
 
64
    switch (pThread->Internal.s.enmType)
 
65
    {
 
66
        case PDMTHREADTYPE_DEVICE:
 
67
            rc = pThread->u.Dev.pfnWakeUp(pThread->u.Dev.pDevIns, pThread);
 
68
            break;
 
69
 
 
70
        case PDMTHREADTYPE_USB:
 
71
            rc = pThread->u.Usb.pfnWakeUp(pThread->u.Usb.pUsbIns, pThread);
 
72
            break;
 
73
 
 
74
        case PDMTHREADTYPE_DRIVER:
 
75
            rc = pThread->u.Drv.pfnWakeUp(pThread->u.Drv.pDrvIns, pThread);
 
76
            break;
 
77
 
 
78
        case PDMTHREADTYPE_INTERNAL:
 
79
            rc = pThread->u.Int.pfnWakeUp(pThread->Internal.s.pVM, pThread);
 
80
            break;
 
81
 
 
82
        case PDMTHREADTYPE_EXTERNAL:
 
83
            rc = pThread->u.Ext.pfnWakeUp(pThread);
 
84
            break;
 
85
 
 
86
        default:
 
87
            AssertMsgFailed(("%d\n", pThread->Internal.s.enmType));
 
88
            rc = VERR_INTERNAL_ERROR;
 
89
            break;
 
90
    }
 
91
    AssertRC(rc);
 
92
    return rc;
 
93
}
 
94
 
 
95
 
 
96
/**
 
97
 * Allocates new thread instance.
 
98
 *
 
99
 * @returns VBox status code.
 
100
 * @param   pVM         The VM handle.
 
101
 * @param   ppThread    Where to store the pointer to the instance.
 
102
 */
 
103
static int pdmR3ThreadNew(PVM pVM, PPPDMTHREAD ppThread)
 
104
{
 
105
    PPDMTHREAD pThread;
 
106
    int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_THREAD, sizeof(*pThread), (void **)&pThread);
 
107
    if (RT_FAILURE(rc))
 
108
        return rc;
 
109
 
 
110
    pThread->u32Version     = PDMTHREAD_VERSION;
 
111
    pThread->enmState       = PDMTHREADSTATE_INITIALIZING;
 
112
    pThread->Thread         = NIL_RTTHREAD;
 
113
    pThread->Internal.s.pVM = pVM;
 
114
 
 
115
    *ppThread = pThread;
 
116
    return VINF_SUCCESS;
 
117
}
 
118
 
 
119
 
 
120
 
 
121
/**
 
122
 * Initialize a new thread, this actually creates the thread.
 
123
 *
 
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().
 
130
 */
 
131
static int pdmR3ThreadInit(PVM pVM, PPPDMTHREAD ppThread, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
 
132
{
 
133
    PPDMTHREAD  pThread = *ppThread;
 
134
    PUVM        pUVM    = pVM->pUVM;
 
135
 
 
136
    /*
 
137
     * Initialize the remainder of the structure.
 
138
     */
 
139
    pThread->Internal.s.pVM = pVM;
 
140
 
 
141
    int rc = RTSemEventMultiCreate(&pThread->Internal.s.BlockEvent);
 
142
    if (RT_SUCCESS(rc))
 
143
    {
 
144
        rc = RTSemEventMultiCreate(&pThread->Internal.s.SleepEvent);
 
145
        if (RT_SUCCESS(rc))
 
146
        {
 
147
            /*
 
148
             * Create the thread and wait for it to initialize.
 
149
             * The newly created thread will set the PDMTHREAD::Thread member.
 
150
             */
 
151
            RTTHREAD Thread;
 
152
            rc = RTThreadCreate(&Thread, pdmR3ThreadMain, pThread, cbStack, enmType, RTTHREADFLAGS_WAITABLE, pszName);
 
153
            if (RT_SUCCESS(rc))
 
154
            {
 
155
                rc = RTThreadUserWait(Thread, 60*1000);
 
156
                if (    RT_SUCCESS(rc)
 
157
                    &&  pThread->enmState != PDMTHREADSTATE_SUSPENDED)
 
158
                    rc = VERR_INTERNAL_ERROR;
 
159
                if (RT_SUCCESS(rc))
 
160
                {
 
161
                    /*
 
162
                     * Insert it into the thread list.
 
163
                     */
 
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;
 
168
                    else
 
169
                        pUVM->pdm.s.pThreads = pThread;
 
170
                    pUVM->pdm.s.pThreadsTail = pThread;
 
171
                    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
 
172
 
 
173
                    rc = RTThreadUserReset(Thread);
 
174
                    AssertRC(rc);
 
175
                    return rc;
 
176
                }
 
177
 
 
178
                /* bailout */
 
179
                RTThreadWait(Thread, 60*1000, NULL);
 
180
            }
 
181
            RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent);
 
182
            pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI;
 
183
        }
 
184
        RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent);
 
185
        pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI;
 
186
    }
 
187
    MMHyperFree(pVM, pThread);
 
188
    *ppThread = NULL;
 
189
 
 
190
    return rc;
 
191
}
 
192
 
 
193
 
 
194
/**
 
195
 * Device Helper for creating a thread associated with a device.
 
196
 *
 
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.
 
208
 */
 
209
int pdmR3ThreadCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread,
 
210
                            PFNPDMTHREADWAKEUPDEV pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
 
211
{
 
212
    int rc = pdmR3ThreadNew(pVM, ppThread);
 
213
    if (RT_SUCCESS(rc))
 
214
    {
 
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);
 
222
    }
 
223
    return rc;
 
224
}
 
225
 
 
226
 
 
227
/**
 
228
 * USB Device Helper for creating a thread associated with an USB device.
 
229
 *
 
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.
 
241
 */
 
242
int pdmR3ThreadCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread,
 
243
                         PFNPDMTHREADWAKEUPUSB pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
 
244
{
 
245
    int rc = pdmR3ThreadNew(pVM, ppThread);
 
246
    if (RT_SUCCESS(rc))
 
247
    {
 
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);
 
255
    }
 
256
    return rc;
 
257
}
 
258
 
 
259
 
 
260
/**
 
261
 * Driver Helper for creating a thread associated with a driver.
 
262
 *
 
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.
 
274
 */
 
275
int pdmR3ThreadCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
 
276
                            PFNPDMTHREADWAKEUPDRV pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
 
277
{
 
278
    int rc = pdmR3ThreadNew(pVM, ppThread);
 
279
    if (RT_SUCCESS(rc))
 
280
    {
 
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);
 
288
    }
 
289
    return rc;
 
290
}
 
291
 
 
292
 
 
293
/**
 
294
 * Creates a PDM thread for internal use in the VM.
 
295
 *
 
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.
 
306
 */
 
307
VMMR3DECL(int) PDMR3ThreadCreate(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADINT pfnThread,
 
308
                                 PFNPDMTHREADWAKEUPINT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
 
309
{
 
310
    int rc = pdmR3ThreadNew(pVM, ppThread);
 
311
    if (RT_SUCCESS(rc))
 
312
    {
 
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);
 
319
    }
 
320
    return rc;
 
321
}
 
322
 
 
323
 
 
324
/**
 
325
 * Creates a PDM thread for VM use by some external party.
 
326
 *
 
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.
 
337
 */
 
338
VMMR3DECL(int) PDMR3ThreadCreateExternal(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADEXT pfnThread,
 
339
                                         PFNPDMTHREADWAKEUPEXT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
 
340
{
 
341
    int rc = pdmR3ThreadNew(pVM, ppThread);
 
342
    if (RT_SUCCESS(rc))
 
343
    {
 
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);
 
350
    }
 
351
    return rc;
 
352
}
 
353
 
 
354
 
 
355
/**
 
356
 * Destroys a PDM thread.
 
357
 *
 
358
 * This will wakeup the thread, tell it to terminate, and wait for it terminate.
 
359
 *
 
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).
 
366
 */
 
367
VMMR3DECL(int) PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread)
 
368
{
 
369
    /*
 
370
     * Assert sanity.
 
371
     */
 
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;
 
377
    VM_ASSERT_EMT(pVM);
 
378
    PUVM pUVM = pVM->pUVM;
 
379
 
 
380
    /*
 
381
     * Advance the thread to the terminating state.
 
382
     */
 
383
    int rc = VINF_SUCCESS;
 
384
    if (pThread->enmState <= PDMTHREADSTATE_TERMINATING)
 
385
    {
 
386
        for (;;)
 
387
        {
 
388
            PDMTHREADSTATE enmState = pThread->enmState;
 
389
            switch (enmState)
 
390
            {
 
391
                case PDMTHREADSTATE_RUNNING:
 
392
                    if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
 
393
                        continue;
 
394
                    rc = pdmR3ThreadWakeUp(pThread);
 
395
                    break;
 
396
 
 
397
                case PDMTHREADSTATE_SUSPENDED:
 
398
                case PDMTHREADSTATE_SUSPENDING:
 
399
                case PDMTHREADSTATE_RESUMING:
 
400
                case PDMTHREADSTATE_INITIALIZING:
 
401
                    if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
 
402
                        continue;
 
403
                    break;
 
404
 
 
405
                case PDMTHREADSTATE_TERMINATING:
 
406
                case PDMTHREADSTATE_TERMINATED:
 
407
                    break;
 
408
 
 
409
                default:
 
410
                    AssertMsgFailed(("enmState=%d\n", enmState));
 
411
                    rc = VERR_INTERNAL_ERROR;
 
412
                    break;
 
413
            }
 
414
            break;
 
415
        }
 
416
    }
 
417
    int rc2 = RTSemEventMultiSignal(pThread->Internal.s.BlockEvent);
 
418
    AssertRC(rc2);
 
419
 
 
420
    /*
 
421
     * Wait for it to terminate and the do cleanups.
 
422
     */
 
423
    rc2 = RTThreadWait(pThread->Thread, RT_SUCCESS(rc) ? 60*1000 : 150, pRcThread);
 
424
    if (RT_SUCCESS(rc2))
 
425
    {
 
426
        /* make it invalid. */
 
427
        pThread->u32Version = 0xffffffff;
 
428
        pThread->enmState = PDMTHREADSTATE_INVALID;
 
429
        pThread->Thread = NIL_RTTHREAD;
 
430
 
 
431
        /* unlink */
 
432
        RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
 
433
        if (pUVM->pdm.s.pThreads == pThread)
 
434
        {
 
435
            pUVM->pdm.s.pThreads = pThread->Internal.s.pNext;
 
436
            if (!pThread->Internal.s.pNext)
 
437
                pUVM->pdm.s.pThreadsTail = NULL;
 
438
        }
 
439
        else
 
440
        {
 
441
            PPDMTHREAD pPrev = pUVM->pdm.s.pThreads;
 
442
            while (pPrev && pPrev->Internal.s.pNext != pThread)
 
443
                pPrev = pPrev->Internal.s.pNext;
 
444
            Assert(pPrev);
 
445
            if (pPrev)
 
446
                pPrev->Internal.s.pNext = pThread->Internal.s.pNext;
 
447
            if (!pThread->Internal.s.pNext)
 
448
                pUVM->pdm.s.pThreadsTail = pPrev;
 
449
        }
 
450
        pThread->Internal.s.pNext = NULL;
 
451
        RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
 
452
 
 
453
        /* free the resources */
 
454
        RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent);
 
455
        pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI;
 
456
 
 
457
        RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent);
 
458
        pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI;
 
459
 
 
460
        MMR3HeapFree(pThread);
 
461
    }
 
462
    else if (RT_SUCCESS(rc))
 
463
        rc = rc2;
 
464
 
 
465
    return rc;
 
466
}
 
467
 
 
468
 
 
469
/**
 
470
 * Destroys all threads associated with a device.
 
471
 *
 
472
 * This function is called by PDMDevice when a device is
 
473
 * destroyed (not currently implemented).
 
474
 *
 
475
 * @returns VBox status code of the first failure.
 
476
 * @param   pVM         The VM handle.
 
477
 * @param   pDevIns     the device instance.
 
478
 */
 
479
int pdmR3ThreadDestroyDevice(PVM pVM, PPDMDEVINS pDevIns)
 
480
{
 
481
    int     rc   = VINF_SUCCESS;
 
482
    PUVM    pUVM = pVM->pUVM;
 
483
 
 
484
    AssertPtr(pDevIns);
 
485
 
 
486
    RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
 
487
    PPDMTHREAD pThread = pUVM->pdm.s.pThreads;
 
488
    while (pThread)
 
489
    {
 
490
        PPDMTHREAD pNext = pThread->Internal.s.pNext;
 
491
        if (    pThread->Internal.s.enmType == PDMTHREADTYPE_DEVICE
 
492
            &&  pThread->u.Dev.pDevIns == pDevIns)
 
493
        {
 
494
            int rc2 = PDMR3ThreadDestroy(pThread, NULL);
 
495
            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
 
496
                rc = rc2;
 
497
        }
 
498
        pThread = pNext;
 
499
    }
 
500
    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
 
501
    return rc;
 
502
}
 
503
 
 
504
 
 
505
/**
 
506
 * Destroys all threads associated with an USB device.
 
507
 *
 
508
 * This function is called by PDMUsb when a device is destroyed.
 
509
 *
 
510
 * @returns VBox status code of the first failure.
 
511
 * @param   pVM         The VM handle.
 
512
 * @param   pUsbIns     The USB device instance.
 
513
 */
 
514
int pdmR3ThreadDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns)
 
515
{
 
516
    int     rc   = VINF_SUCCESS;
 
517
    PUVM    pUVM = pVM->pUVM;
 
518
 
 
519
    AssertPtr(pUsbIns);
 
520
 
 
521
    RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
 
522
    PPDMTHREAD pThread = pUVM->pdm.s.pThreads;
 
523
    while (pThread)
 
524
    {
 
525
        PPDMTHREAD pNext = pThread->Internal.s.pNext;
 
526
        if (    pThread->Internal.s.enmType == PDMTHREADTYPE_DEVICE
 
527
            &&  pThread->u.Usb.pUsbIns == pUsbIns)
 
528
        {
 
529
            int rc2 = PDMR3ThreadDestroy(pThread, NULL);
 
530
            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
 
531
                rc = rc2;
 
532
        }
 
533
        pThread = pNext;
 
534
    }
 
535
    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
 
536
    return rc;
 
537
}
 
538
 
 
539
 
 
540
/**
 
541
 * Destroys all threads associated with a driver.
 
542
 *
 
543
 * This function is called by PDMDriver when a driver is destroyed.
 
544
 *
 
545
 * @returns VBox status code of the first failure.
 
546
 * @param   pVM         The VM handle.
 
547
 * @param   pDrvIns     The driver instance.
 
548
 */
 
549
int pdmR3ThreadDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns)
 
550
{
 
551
    int     rc   = VINF_SUCCESS;
 
552
    PUVM    pUVM = pVM->pUVM;
 
553
 
 
554
    AssertPtr(pDrvIns);
 
555
 
 
556
    RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
 
557
    PPDMTHREAD pThread = pUVM->pdm.s.pThreads;
 
558
    while (pThread)
 
559
    {
 
560
        PPDMTHREAD pNext = pThread->Internal.s.pNext;
 
561
        if (    pThread->Internal.s.enmType == PDMTHREADTYPE_DRIVER
 
562
            &&  pThread->u.Drv.pDrvIns == pDrvIns)
 
563
        {
 
564
            int rc2 = PDMR3ThreadDestroy(pThread, NULL);
 
565
            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
 
566
                rc = rc2;
 
567
        }
 
568
        pThread = pNext;
 
569
    }
 
570
    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
 
571
    return rc;
 
572
}
 
573
 
 
574
 
 
575
/**
 
576
 * Called For VM power off.
 
577
 *
 
578
 * @param   pVM         The VM handle.
 
579
 */
 
580
void pdmR3ThreadDestroyAll(PVM pVM)
 
581
{
 
582
    PUVM pUVM = pVM->pUVM;
 
583
    RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
 
584
    PPDMTHREAD pThread = pUVM->pdm.s.pThreads;
 
585
    while (pThread)
 
586
    {
 
587
        PPDMTHREAD pNext = pThread->Internal.s.pNext;
 
588
        int rc2 = PDMR3ThreadDestroy(pThread, NULL);
 
589
        AssertRC(rc2);
 
590
        pThread = pNext;
 
591
    }
 
592
    Assert(!pUVM->pdm.s.pThreads && !pUVM->pdm.s.pThreadsTail);
 
593
    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
 
594
}
 
595
 
 
596
 
 
597
/**
 
598
 * Initiate termination of the thread (self) because something failed in a bad way.
 
599
 *
 
600
 * @param   pThread         The PDM thread.
 
601
 */
 
602
static void pdmR3ThreadBailMeOut(PPDMTHREAD pThread)
 
603
{
 
604
    for (;;)
 
605
    {
 
606
        PDMTHREADSTATE enmState = pThread->enmState;
 
607
        switch (enmState)
 
608
        {
 
609
            case PDMTHREADSTATE_SUSPENDING:
 
610
            case PDMTHREADSTATE_SUSPENDED:
 
611
            case PDMTHREADSTATE_RESUMING:
 
612
            case PDMTHREADSTATE_RUNNING:
 
613
                if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
 
614
                    continue;
 
615
                break;
 
616
 
 
617
            case PDMTHREADSTATE_TERMINATING:
 
618
            case PDMTHREADSTATE_TERMINATED:
 
619
                break;
 
620
 
 
621
            case PDMTHREADSTATE_INITIALIZING:
 
622
            default:
 
623
                AssertMsgFailed(("enmState=%d\n", enmState));
 
624
                break;
 
625
        }
 
626
        break;
 
627
    }
 
628
}
 
629
 
 
630
 
 
631
/**
 
632
 * Called by the PDM thread in response to a wakeup call with
 
633
 * suspending as the new state.
 
634
 *
 
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.
 
638
 *
 
639
 * @returns VBox status code.
 
640
 *          On failure, terminate the thread.
 
641
 * @param   pThread     The PDM thread.
 
642
 */
 
643
VMMR3DECL(int) PDMR3ThreadIAmSuspending(PPDMTHREAD pThread)
 
644
{
 
645
    /*
 
646
     * Assert sanity.
 
647
     */
 
648
    AssertPtr(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);
 
654
 
 
655
    /*
 
656
     * Update the state, notify the control thread (the API caller) and go to sleep.
 
657
     */
 
658
    int rc = VERR_WRONG_ORDER;
 
659
    if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDED, enmState))
 
660
    {
 
661
        rc = RTThreadUserSignal(pThread->Thread);
 
662
        if (RT_SUCCESS(rc))
 
663
        {
 
664
            rc = RTSemEventMultiWait(pThread->Internal.s.BlockEvent, RT_INDEFINITE_WAIT);
 
665
            if (    RT_SUCCESS(rc)
 
666
                &&  pThread->enmState != PDMTHREADSTATE_SUSPENDED)
 
667
                return rc;
 
668
 
 
669
            if (RT_SUCCESS(rc))
 
670
                rc = VERR_INTERNAL_ERROR;
 
671
        }
 
672
    }
 
673
 
 
674
    AssertMsgFailed(("rc=%d enmState=%d\n", rc, pThread->enmState));
 
675
    pdmR3ThreadBailMeOut(pThread);
 
676
    return rc;
 
677
}
 
678
 
 
679
 
 
680
/**
 
681
 * Called by the PDM thread in response to a resuming state.
 
682
 *
 
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.
 
686
 *
 
687
 * @returns VBox status code.
 
688
 *          On failure, terminate the thread.
 
689
 * @param   pThread     The PDM thread.
 
690
 */
 
691
VMMR3DECL(int) PDMR3ThreadIAmRunning(PPDMTHREAD pThread)
 
692
{
 
693
    /*
 
694
     * Assert sanity.
 
695
     */
 
696
    Assert(pThread->enmState == PDMTHREADSTATE_RESUMING);
 
697
    Assert(pThread->Thread == RTThreadSelf());
 
698
 
 
699
    /*
 
700
     * Update the state and tell the control thread (the guy calling the resume API).
 
701
     */
 
702
    int rc = VERR_WRONG_ORDER;
 
703
    if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_RUNNING, PDMTHREADSTATE_RESUMING))
 
704
    {
 
705
        rc = RTThreadUserSignal(pThread->Thread);
 
706
        if (RT_SUCCESS(rc))
 
707
            return rc;
 
708
    }
 
709
 
 
710
    AssertMsgFailed(("rc=%d enmState=%d\n", rc, pThread->enmState));
 
711
    pdmR3ThreadBailMeOut(pThread);
 
712
    return rc;
 
713
}
 
714
 
 
715
 
 
716
/**
 
717
 * Called by the PDM thread instead of RTThreadSleep.
 
718
 *
 
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.
 
721
 *
 
722
 * @returns VBox status code.
 
723
 * @retval  VINF_SUCCESS on success or state change.
 
724
 * @retval  VERR_INTERRUPTED on signal or APC.
 
725
 *
 
726
 * @param   pThread     The PDM thread.
 
727
 * @param   cMillies    The number of milliseconds to sleep.
 
728
 */
 
729
VMMR3DECL(int) PDMR3ThreadSleep(PPDMTHREAD pThread, RTMSINTERVAL cMillies)
 
730
{
 
731
    /*
 
732
     * Assert sanity.
 
733
     */
 
734
    AssertReturn(pThread->enmState > PDMTHREADSTATE_INVALID && pThread->enmState < PDMTHREADSTATE_TERMINATED, VERR_INTERNAL_ERROR);
 
735
    AssertReturn(pThread->Thread == RTThreadSelf(), VERR_INTERNAL_ERROR);
 
736
 
 
737
    /*
 
738
     * Reset the event semaphore, check the state and sleep.
 
739
     */
 
740
    RTSemEventMultiReset(pThread->Internal.s.SleepEvent);
 
741
    if (pThread->enmState != PDMTHREADSTATE_RUNNING)
 
742
        return VINF_SUCCESS;
 
743
    return RTSemEventMultiWaitNoResume(pThread->Internal.s.SleepEvent, cMillies);
 
744
}
 
745
 
 
746
 
 
747
/**
 
748
 * The PDM thread function.
 
749
 *
 
750
 * @returns return from pfnThread.
 
751
 *
 
752
 * @param   Thread  The thread handle.
 
753
 * @param   pvUser  Pointer to the PDMTHREAD structure.
 
754
 */
 
755
static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser)
 
756
{
 
757
    PPDMTHREAD pThread = (PPDMTHREAD)pvUser;
 
758
    Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread)));
 
759
    pThread->Thread = Thread;
 
760
 
 
761
    /*
 
762
     * The run loop.
 
763
     *
 
764
     * It handles simple thread functions which returns when they see a suspending
 
765
     * request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning
 
766
     * parts to us.
 
767
     */
 
768
    int rc;
 
769
    for (;;)
 
770
    {
 
771
        switch (pThread->Internal.s.enmType)
 
772
        {
 
773
            case PDMTHREADTYPE_DEVICE:
 
774
                rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread);
 
775
                break;
 
776
 
 
777
            case PDMTHREADTYPE_USB:
 
778
                rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread);
 
779
                break;
 
780
 
 
781
            case PDMTHREADTYPE_DRIVER:
 
782
                rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread);
 
783
                break;
 
784
 
 
785
            case PDMTHREADTYPE_INTERNAL:
 
786
                rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread);
 
787
                break;
 
788
 
 
789
            case PDMTHREADTYPE_EXTERNAL:
 
790
                rc = pThread->u.Ext.pfnThread(pThread);
 
791
                break;
 
792
 
 
793
            default:
 
794
                AssertMsgFailed(("%d\n", pThread->Internal.s.enmType));
 
795
                rc = VERR_INTERNAL_ERROR;
 
796
                break;
 
797
        }
 
798
        if (RT_FAILURE(rc))
 
799
            break;
 
800
 
 
801
        /*
 
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.
 
804
         */
 
805
        if (    pThread->enmState != PDMTHREADSTATE_SUSPENDING
 
806
            &&  pThread->enmState != PDMTHREADSTATE_INITIALIZING)
 
807
        {
 
808
            Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING);
 
809
            break;
 
810
        }
 
811
        rc = PDMR3ThreadIAmSuspending(pThread);
 
812
        if (RT_FAILURE(rc))
 
813
            break;
 
814
        if (pThread->enmState != PDMTHREADSTATE_RESUMING)
 
815
        {
 
816
            Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING);
 
817
            break;
 
818
        }
 
819
 
 
820
        rc = PDMR3ThreadIAmRunning(pThread);
 
821
        if (RT_FAILURE(rc))
 
822
            break;
 
823
    }
 
824
 
 
825
    if (RT_FAILURE(rc))
 
826
        LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc));
 
827
 
 
828
    /*
 
829
     * Advance the state to terminating and then on to terminated.
 
830
     */
 
831
    for (;;)
 
832
    {
 
833
        PDMTHREADSTATE enmState = pThread->enmState;
 
834
        if (    enmState == PDMTHREADSTATE_TERMINATING
 
835
            ||  pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
 
836
            break;
 
837
    }
 
838
 
 
839
    ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED);
 
840
    int rc2 = RTThreadUserSignal(Thread); AssertRC(rc2);
 
841
 
 
842
    Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc));
 
843
    return rc;
 
844
}
 
845
 
 
846
 
 
847
/**
 
848
 * Initiate termination of the thread because something failed in a bad way.
 
849
 *
 
850
 * @param   pThread         The PDM thread.
 
851
 */
 
852
static void pdmR3ThreadBailOut(PPDMTHREAD pThread)
 
853
{
 
854
    for (;;)
 
855
    {
 
856
        PDMTHREADSTATE enmState = pThread->enmState;
 
857
        switch (enmState)
 
858
        {
 
859
            case PDMTHREADSTATE_SUSPENDING:
 
860
            case PDMTHREADSTATE_SUSPENDED:
 
861
                if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
 
862
                    continue;
 
863
                RTSemEventMultiSignal(pThread->Internal.s.BlockEvent);
 
864
                break;
 
865
 
 
866
            case PDMTHREADSTATE_RESUMING:
 
867
                if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
 
868
                    continue;
 
869
                break;
 
870
 
 
871
            case PDMTHREADSTATE_RUNNING:
 
872
                if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
 
873
                    continue;
 
874
                pdmR3ThreadWakeUp(pThread);
 
875
                break;
 
876
 
 
877
            case PDMTHREADSTATE_TERMINATING:
 
878
            case PDMTHREADSTATE_TERMINATED:
 
879
                break;
 
880
 
 
881
            case PDMTHREADSTATE_INITIALIZING:
 
882
            default:
 
883
                AssertMsgFailed(("enmState=%d\n", enmState));
 
884
                break;
 
885
        }
 
886
        break;
 
887
    }
 
888
}
 
889
 
 
890
 
 
891
/**
 
892
 * Suspends the thread.
 
893
 *
 
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.
 
897
 *
 
898
 * The caller is responsible for serializing the control operations on the
 
899
 * thread. That basically means, always do these calls from the EMT.
 
900
 *
 
901
 * @returns VBox status code.
 
902
 * @param   pThread     The PDM thread.
 
903
 */
 
904
VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread)
 
905
{
 
906
    /*
 
907
     * Assert sanity.
 
908
     */
 
909
    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
 
910
    AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
 
911
    Assert(pThread->Thread != RTThreadSelf());
 
912
 
 
913
    /*
 
914
     * This is a noop if the thread is already suspended.
 
915
     */
 
916
    if (pThread->enmState == PDMTHREADSTATE_SUSPENDED)
 
917
        return VINF_SUCCESS;
 
918
 
 
919
    /*
 
920
     * Change the state to resuming and kick the thread.
 
921
     */
 
922
    int rc = RTSemEventMultiReset(pThread->Internal.s.BlockEvent);
 
923
    if (RT_SUCCESS(rc))
 
924
    {
 
925
        rc = RTThreadUserReset(pThread->Thread);
 
926
        if (RT_SUCCESS(rc))
 
927
        {
 
928
            rc = VERR_WRONG_ORDER;
 
929
            if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDING, PDMTHREADSTATE_RUNNING))
 
930
            {
 
931
                rc = pdmR3ThreadWakeUp(pThread);
 
932
                if (RT_SUCCESS(rc))
 
933
                {
 
934
                    /*
 
935
                     * Wait for the thread to reach the suspended state.
 
936
                     */
 
937
                    if (pThread->enmState != PDMTHREADSTATE_SUSPENDED)
 
938
                        rc = RTThreadUserWait(pThread->Thread, 60*1000);
 
939
                    if (    RT_SUCCESS(rc)
 
940
                        &&  pThread->enmState != PDMTHREADSTATE_SUSPENDED)
 
941
                        rc = VERR_INTERNAL_ERROR;
 
942
                    if (RT_SUCCESS(rc))
 
943
                        return rc;
 
944
                }
 
945
            }
 
946
        }
 
947
    }
 
948
 
 
949
    /*
 
950
     * Something failed, initialize termination.
 
951
     */
 
952
    AssertMsgFailed(("PDMR3ThreadSuspend -> rc=%Rrc enmState=%d\n", rc, pThread->enmState));
 
953
    pdmR3ThreadBailOut(pThread);
 
954
    return rc;
 
955
}
 
956
 
 
957
 
 
958
/**
 
959
 * Suspend all running threads.
 
960
 *
 
961
 * This is called by PDMR3Suspend() and PDMR3PowerOff() after all the devices
 
962
 * and drivers have been notified about the suspend / power off.
 
963
 *
 
964
 * @return VBox status code.
 
965
 * @param   pVM         The VM handle.
 
966
 */
 
967
int pdmR3ThreadSuspendAll(PVM pVM)
 
968
{
 
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)
 
973
        {
 
974
            case PDMTHREADSTATE_RUNNING:
 
975
            {
 
976
                int rc = PDMR3ThreadSuspend(pThread);
 
977
                AssertRCReturn(rc, rc);
 
978
                break;
 
979
            }
 
980
 
 
981
            /* suspend -> power off; voluntary suspend. */
 
982
            case PDMTHREADSTATE_SUSPENDED:
 
983
                break;
 
984
 
 
985
            default:
 
986
                AssertMsgFailed(("pThread=%p enmState=%d\n", pThread, pThread->enmState));
 
987
                break;
 
988
        }
 
989
    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
 
990
    return VINF_SUCCESS;
 
991
}
 
992
 
 
993
 
 
994
/**
 
995
 * Resumes the thread.
 
996
 *
 
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).
 
1000
 *
 
1001
 * The caller is responsible for serializing the control operations on the
 
1002
 * thread. That basically means, always do these calls from the EMT.
 
1003
 *
 
1004
 * @returns VBox status code.
 
1005
 * @param   pThread     The PDM thread.
 
1006
 */
 
1007
VMMR3DECL(int) PDMR3ThreadResume(PPDMTHREAD pThread)
 
1008
{
 
1009
    /*
 
1010
     * Assert sanity.
 
1011
     */
 
1012
    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
 
1013
    AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
 
1014
    Assert(pThread->Thread != RTThreadSelf());
 
1015
 
 
1016
    /*
 
1017
     * Change the state to resuming and kick the thread.
 
1018
     */
 
1019
    int rc = RTThreadUserReset(pThread->Thread);
 
1020
    if (RT_SUCCESS(rc))
 
1021
    {
 
1022
        rc = VERR_WRONG_ORDER;
 
1023
        if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_RESUMING, PDMTHREADSTATE_SUSPENDED))
 
1024
        {
 
1025
            rc = RTSemEventMultiSignal(pThread->Internal.s.BlockEvent);
 
1026
            if (RT_SUCCESS(rc))
 
1027
            {
 
1028
                /*
 
1029
                 * Wait for the thread to reach the running state.
 
1030
                 */
 
1031
                rc = RTThreadUserWait(pThread->Thread, 60*1000);
 
1032
                if (    RT_SUCCESS(rc)
 
1033
                    &&  pThread->enmState != PDMTHREADSTATE_RUNNING)
 
1034
                    rc = VERR_INTERNAL_ERROR;
 
1035
                if (RT_SUCCESS(rc))
 
1036
                    return rc;
 
1037
            }
 
1038
        }
 
1039
    }
 
1040
 
 
1041
    /*
 
1042
     * Something failed, initialize termination.
 
1043
     */
 
1044
    AssertMsgFailed(("PDMR3ThreadResume -> rc=%Rrc enmState=%d\n", rc, pThread->enmState));
 
1045
    pdmR3ThreadBailOut(pThread);
 
1046
    return rc;
 
1047
}
 
1048
 
 
1049
 
 
1050
/**
 
1051
 * Resumes all threads not running.
 
1052
 *
 
1053
 * This is called by PDMR3Resume() and PDMR3PowerOn() after all the devices
 
1054
 * and drivers have been notified about the resume / power on .
 
1055
 *
 
1056
 * @return VBox status code.
 
1057
 * @param   pVM         The VM handle.
 
1058
 */
 
1059
int pdmR3ThreadResumeAll(PVM pVM)
 
1060
{
 
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)
 
1065
        {
 
1066
            case PDMTHREADSTATE_SUSPENDED:
 
1067
            {
 
1068
                int rc = PDMR3ThreadResume(pThread);
 
1069
                AssertRCReturn(rc, rc);
 
1070
                break;
 
1071
            }
 
1072
 
 
1073
            default:
 
1074
                AssertMsgFailed(("pThread=%p enmState=%d\n", pThread, pThread->enmState));
 
1075
                break;
 
1076
        }
 
1077
    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
 
1078
    return VINF_SUCCESS;
 
1079
}
 
1080