VirtualBox

Changeset 93609 in vbox


Ignore:
Timestamp:
Feb 5, 2022 7:03:08 PM (3 years ago)
Author:
vboxsync
Message:

VMM/PDMQueue: Rewrote the queue code to not use the hyper heap and be a bit safer. Added a testcase (driverless). bugref:10093

Location:
trunk
Files:
1 added
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/types.h

    r93444 r93609  
    446446/** Pointer to a const PDM read/write critical section. */
    447447typedef union PDMCRITSECTRW const *PCPDMCRITSECTRW;
     448
     449/** PDM queue handle. */
     450typedef uint64_t PDMQUEUEHANDLE;
     451/** Pointer to a PDM queue handle. */
     452typedef PDMQUEUEHANDLE *PPDMQUEUEHANDLE;
     453/** NIL PDM queue handle. */
     454#define NIL_PDMQUEUEHANDLE ((PDMQUEUEHANDLE)UINT64_MAX)
    448455
    449456/** R3 pointer to a timer. */
  • trunk/include/VBox/vmm/gvm.h

    r93594 r93609  
    247247        struct PDMR0PERVM   s;
    248248#endif
    249         uint8_t             padding[2176];
     249        uint8_t             padding[3008];
    250250    } pdmr0;
    251251
     
    300300    /** Padding so aCpus starts on a page boundrary.  */
    301301#ifdef VBOX_WITH_NEM_R0
    302     uint8_t         abPadding2[16384 - 64 - 4352 - 1024 - 256 - 256 - 64 - 2176 - 640 - 512 - 64 - 1024 - 128 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT];
     302    uint8_t         abPadding2[16384 - 64 - 4352 - 1024 - 256 - 256 - 64 - 3008 - 640 - 512 - 64 - 1024 - 128 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT];
    303303#else
    304     uint8_t         abPadding2[16384 - 64 - 4352 - 1024 - 256 -       64 - 2176 - 640 - 512 - 64 - 1024 - 128 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT];
     304    uint8_t         abPadding2[16384 - 64 - 4352 - 1024 - 256 -       64 - 3008 - 640 - 512 - 64 - 1024 - 128 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT];
    305305#endif
    306306
  • trunk/include/VBox/vmm/gvm.mac

    r93593 r93609  
    8383        .rawpci             resb 64
    8484        alignb 64
    85         .pdmr0              resb 2176
     85        .pdmr0              resb 3008
    8686        alignb 64
    8787        .pgmr0              resb 640
  • trunk/include/VBox/vmm/pdmapi.h

    r93115 r93609  
    343343VMMR0_INT_DECL(int) PDMR0DeviceCompatSetCritSectReqHandler(PGVM pGVM, PPDMDEVICECOMPATSETCRITSECTREQ pReq);
    344344
     345
     346/**
     347 * Request buffer for PDMR0QueueCreateReqHandler / VMMR0_DO_PDM_QUEUE_CREATE.
     348 * @see PDMR0QueueCreateReqHandler.
     349 */
     350typedef struct PDMQUEUECREATEREQ
     351{
     352    /** The header. */
     353    SUPVMMR0REQHDR          Hdr;
     354
     355    /** Number of queue items. */
     356    uint32_t                cItems;
     357    /** Queue item size.   */
     358    uint32_t                cbItem;
     359    /** Owner type (PDMQUEUETYPE). */
     360    uint32_t                enmType;
     361    /** The ring-3 owner pointer. */
     362    RTR3PTR                 pvOwner;
     363    /** The ring-3 callback function address. */
     364    RTR3PTR                 pfnCallback;
     365    /** The queue name. */
     366    char                    szName[40];
     367
     368    /** Output: The queue handle. */
     369    PDMQUEUEHANDLE          hQueue;
     370} PDMQUEUECREATEREQ;
     371/** Pointer to a PDMR0QueueCreateReqHandler / VMMR0_DO_PDM_QUEUE_CREATE request buffer. */
     372typedef PDMQUEUECREATEREQ *PPDMQUEUECREATEREQ;
     373
     374VMMR0_INT_DECL(int) PDMR0QueueCreateReqHandler(PGVM pGVM, PPDMQUEUECREATEREQ pReq);
     375
    345376/** @} */
    346377
  • trunk/include/VBox/vmm/pdmdev.h

    r93115 r93609  
    40004000
    40014001    DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue));
    4002     DECLR3CALLBACKMEMBER(void, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem));
     4002    DECLR3CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem));
    40034003    DECLR3CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue));
    40044004    /** @} */
     
    57675767     * @{ */
    57685768    DECLR0CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue));
    5769     DECLR0CALLBACKMEMBER(void, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem));
     5769    DECLR0CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem));
    57705770    DECLR0CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue));
    57715771    /** @} */
     
    84248424 * @copydoc PDMDEVHLPR3::pfnQueueInsert
    84258425 */
    8426 DECLINLINE(void) PDMDevHlpQueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
    8427 {
    8428     pDevIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDevIns, hQueue, pItem);
     8426DECLINLINE(int) PDMDevHlpQueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
     8427{
     8428    return pDevIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDevIns, hQueue, pItem);
    84298429}
    84308430
  • trunk/include/VBox/vmm/pdmdrv.h

    r93115 r93609  
    841841
    842842    DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue));
    843     DECLR3CALLBACKMEMBER(void, pfnQueueInsert,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem));
     843    DECLR3CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem));
    844844    DECLR3CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue));
    845845    /** @} */
     
    17051705 * @copydoc PDMDRVHLPR3::pfnQueueInsert
    17061706 */
    1707 DECLINLINE(void) PDMDrvHlpQueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
    1708 {
    1709     pDrvIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDrvIns, hQueue, pItem);
     1707DECLINLINE(int) PDMDrvHlpQueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
     1708{
     1709    return pDrvIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDrvIns, hQueue, pItem);
    17101710}
    17111711
  • trunk/include/VBox/vmm/pdmqueue.h

    r93115 r93609  
    3939 */
    4040
    41 /** PDM queue handle. */
    42 typedef uint64_t PDMQUEUEHANDLE;
    43 /** NIL PDM queue handle. */
    44 #define NIL_PDMQUEUEHANDLE      UINT64_MAX
    45 
    4641/** Pointer to a PDM queue. */
    4742typedef struct PDMQUEUE *PPDMQUEUE;
    4843
    4944/** Pointer to a PDM queue item core. */
    50 typedef struct PDMQUEUEITEMCORE *PPDMQUEUEITEMCORE;
     45typedef union PDMQUEUEITEMCORE *PPDMQUEUEITEMCORE;
    5146
    5247/**
    5348 * PDM queue item core.
    5449 */
    55 typedef struct PDMQUEUEITEMCORE
     50typedef union PDMQUEUEITEMCORE
    5651{
    57     /** Pointer to the next item in the pending list - R3 Pointer. */
    58     R3PTRTYPE(PPDMQUEUEITEMCORE)    pNextR3;
    59     /** Pointer to the next item in the pending list - R0 Pointer. */
    60     R0PTRTYPE(PPDMQUEUEITEMCORE)    pNextR0;
     52    /** The next queue item on the pending list (UINT32_MAX for NIL). */
     53    uint32_t volatile               iNext;
     54    /** The next item about to be flushed. */
     55    R3PTRTYPE(PPDMQUEUEITEMCORE)    pNext;
     56    /** Make sure the core is 64-bit wide. */
     57    uint64_t                        u64View;
    6158} PDMQUEUEITEMCORE;
    6259
     
    134131
    135132#ifdef VBOX_IN_VMM
    136 VMMR3_INT_DECL(int)  PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
    137                                             PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue);
    138 VMMR3_INT_DECL(int)  PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
    139                                             PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue);
    140 VMMR3_INT_DECL(int)  PDMR3QueueCreateInternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
    141                                               PFNPDMQUEUEINT pfnCallback, bool fGCEnabled, const char *pszName, PPDMQUEUE *ppQueue);
    142 VMMR3_INT_DECL(int)  PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
    143                                               PFNPDMQUEUEEXT pfnCallback, void *pvUser, const char *pszName, PPDMQUEUE *ppQueue);
    144 VMMR3_INT_DECL(int)  PDMR3QueueDestroy(PPDMQUEUE pQueue);
     133VMMR3_INT_DECL(int)  PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems,
     134                                            uint32_t cMilliesInterval, PFNPDMQUEUEDEV pfnCallback,
     135                                            bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue);
     136VMMR3_INT_DECL(int)  PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems,
     137                                            uint32_t cMilliesInterval, PFNPDMQUEUEDRV pfnCallback,
     138                                            const char *pszName, PDMQUEUEHANDLE *phQueue);
     139VMMR3_INT_DECL(int)  PDMR3QueueCreateInternal(PVM pVM, size_t cbItem, uint32_t cItems,
     140                                              uint32_t cMilliesInterval, PFNPDMQUEUEINT pfnCallback,
     141                                              bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue);
     142VMMR3DECL(int)       PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
     143                                              PFNPDMQUEUEEXT pfnCallback, void *pvUser, const char *pszName, PDMQUEUEHANDLE *phQueue);
     144VMMR3DECL(int)       PDMR3QueueDestroy(PVM pVM, PDMQUEUEHANDLE hQueue, void *pvOwner);
    145145VMMR3_INT_DECL(int)  PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns);
    146146VMMR3_INT_DECL(int)  PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns);
    147 VMMR3_INT_DECL(void) PDMR3QueueFlushAll(PVM pVM);
     147VMMR3DECL(void)      PDMR3QueueFlushAll(PVM pVM);
    148148#endif /* VBOX_IN_VMM */
    149149
    150 VMMDECL(PPDMQUEUEITEMCORE)    PDMQueueAlloc(PPDMQUEUE pQueue);
    151 VMMDECL(void)                 PDMQueueInsert(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem);
    152 VMMDECL(void)                 PDMQueueInsertEx(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem, uint64_t NanoMaxDelay);
    153 VMMDECL(R0PTRTYPE(PPDMQUEUE)) PDMQueueR0Ptr(PPDMQUEUE pQueue);
    154 VMMDECL(bool)                 PDMQueueFlushIfNecessary(PPDMQUEUE pQueue);
     150VMMDECL(PPDMQUEUEITEMCORE)  PDMQueueAlloc(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner);
     151VMMDECL(int)                PDMQueueInsert(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner, PPDMQUEUEITEMCORE pInsert);
     152VMMDECL(int)                PDMQueueFlushIfNecessary(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner);
    155153
    156154/** @} */
  • trunk/include/VBox/vmm/vm.h

    r93593 r93609  
    13231323        struct PDM s;
    13241324#endif
    1325         uint8_t     padding[8320];      /* multiple of 64 */
     1325        uint8_t     padding[8448];      /* multiple of 64 */
    13261326    } pdm;
    13271327
     
    14581458
    14591459    /** Padding for aligning the structure size on a page boundrary. */
    1460     uint8_t         abAlignment2[6616 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT];
     1460    uint8_t         abAlignment2[6488 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT];
    14611461
    14621462    /* ---- end small stuff ---- */
     
    14681468} VM;
    14691469#ifndef VBOX_FOR_DTRACE_LIB
    1470 AssertCompileSizeAlignment(VM, 16384);
     1470//AssertCompileSizeAlignment(VM, 16384);
    14711471#endif
    14721472
  • trunk/include/VBox/vmm/vm.mac

    r93593 r93609  
    143143    .mm                     resb 192
    144144    alignb 64
    145     .pdm                    resb 8320
     145    .pdm                    resb 8448
    146146    alignb 64
    147147    .iom                    resb 1152
  • trunk/include/VBox/vmm/vmm.h

    r93470 r93609  
    321321    /** Old style device compat: Set ring-0 critical section. */
    322322    VMMR0_DO_PDM_DEVICE_COMPAT_SET_CRITSECT,
     323    /** Call PDMR0QueueCreateReqHandler. */
     324    VMMR0_DO_PDM_QUEUE_CREATE,
    323325
    324326    /** Set a GVMM or GMM configuration value. */
  • trunk/include/VBox/vmm/vmmr3vtable-def.h

    r93470 r93609  
    609609VTABLE_ENTRY(PDMQueueAlloc)
    610610VTABLE_ENTRY(PDMQueueInsert)
    611 VTABLE_ENTRY(PDMQueueInsertEx)
     611VTABLE_RESERVED(pfnPDMR3Reserved11)
    612612
    613613VTABLE_ENTRY(PDMR3ThreadDestroy)
  • trunk/src/VBox/VMM/Makefile.kmk

    r93595 r93609  
    488488        $(if-expr defined(VBOX_WITH_DBGF_TRACING), VMMR0/PDMR0DevHlpTracing.cpp,) \
    489489        VMMR0/PDMR0Driver.cpp \
     490        VMMR0/PDMR0Queue.cpp \
    490491        VMMR0/PGMR0.cpp \
    491492        VMMR0/PGMR0Pool.cpp \
  • trunk/src/VBox/VMM/VMMAll/PDMAll.cpp

    r93115 r93609  
    212212    {
    213213        /* Queue for ring-3 execution. */
    214         PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0);
     214        PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM, pVM->pdm.s.hDevHlpQueue, pVM);
    215215        if (pTask)
    216216        {
     
    218218            pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
    219219            pTask->u.IoApicSetEoi.uVector = uVector;
    220             PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
     220            PDMQueueInsert(pVM, pVM->pdm.s.hDevHlpQueue, pVM, &pTask->Core);
    221221        }
    222222        else
     
    250250    {
    251251        /* Queue for ring-3 execution. */
    252         PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0);
     252        PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM, pVM->pdm.s.hDevHlpQueue, pVM);
    253253        if (pTask)
    254254        {
     
    258258            pTask->u.IoApicSendMsi.Msi       = *pMsi;
    259259            pTask->u.IoApicSendMsi.uTagSrc   = uTagSrc;
    260             PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
     260            PDMQueueInsert(pVM, pVM->pdm.s.hDevHlpQueue, pVM, &pTask->Core);
    261261        }
    262262        else
  • trunk/src/VBox/VMM/VMMAll/PDMAllQueue.cpp

    r93115 r93609  
    3131#include <iprt/asm.h>
    3232#include <iprt/assert.h>
    33 
    34 
    35 /**
    36  * Allocate an item from a queue.
     33#include <iprt/string.h>
     34
     35
     36/*********************************************************************************************************************************
     37*   Defined Constants And Macros                                                                                                 *
     38*********************************************************************************************************************************/
     39/*
     40 * Macros for thoroughly validating a queue handle and ownership.
     41 */
     42#define PDMQUEUE_HANDLE_TO_VARS_RETURN_COMMON(a_cbMax, a_cbTotalMax) \
     43    AssertReturn(cbItem >= sizeof(PDMQUEUEITEMCORE), pQueue->rcOkay = VERR_INTERNAL_ERROR_4); \
     44    AssertReturn(cbItem <= (a_cbMax), pQueue->rcOkay = VERR_INTERNAL_ERROR_4); \
     45    \
     46    /* paranoia^3: */ \
     47    AssertReturn(cItems > 0, pQueue->rcOkay = VERR_INTERNAL_ERROR_4); \
     48    AssertReturn(cItems <= PDMQUEUE_MAX_ITEMS, pQueue->rcOkay = VERR_INTERNAL_ERROR_4); \
     49    AssertReturn(cbItem * cItems <= (a_cbTotalMax), pQueue->rcOkay = VERR_INTERNAL_ERROR_4)
     50
     51#ifdef IN_RING0
     52# define PDMQUEUE_HANDLE_TO_VARS_RETURN(a_pVM, a_hQueue, a_pvOwner) \
     53    AssertPtrReturn((a_pvOwner), VERR_INVALID_PARAMETER); \
     54    \
     55    AssertCompile(RT_ELEMENTS((a_pVM)->pdm.s.apRing0Queues) == RT_ELEMENTS((a_pVM)->pdmr0.s.aQueues)); \
     56    AssertReturn((a_hQueue) < RT_ELEMENTS((a_pVM)->pdmr0.s.aQueues), VERR_INVALID_HANDLE); \
     57    AssertReturn((a_hQueue) < (a_pVM)->pdmr0.s.cQueues, VERR_INVALID_HANDLE); \
     58    AssertReturn((a_pVM)->pdmr0.s.aQueues[(a_hQueue)].pvOwner == (a_pvOwner), VERR_INVALID_HANDLE); \
     59    PPDMQUEUE pQueue = (a_pVM)->pdmr0.s.aQueues[(a_hQueue)].pQueue; \
     60    AssertPtrReturn(pQueue, VERR_INVALID_HANDLE); \
     61    AssertReturn(pQueue->u32Magic == PDMQUEUE_MAGIC, VERR_INVALID_HANDLE); \
     62    AssertReturn(pQueue->rcOkay == VINF_SUCCESS, pQueue->rcOkay); \
     63    \
     64    uint32_t const cbItem   = (a_pVM)->pdmr0.s.aQueues[(a_hQueue)].cbItem; \
     65    uint32_t const cItems   = (a_pVM)->pdmr0.s.aQueues[(a_hQueue)].cItems; \
     66    uint32_t const offItems = (a_pVM)->pdmr0.s.aQueues[(a_hQueue)].offItems; \
     67    \
     68    /* paranoia^2: */ \
     69    AssertReturn(pQueue->cbItem == cbItem, pQueue->rcOkay = VERR_INTERNAL_ERROR_3); \
     70    AssertReturn(pQueue->cItems == cItems, pQueue->rcOkay = VERR_INTERNAL_ERROR_3); \
     71    AssertReturn(pQueue->offItems == offItems, pQueue->rcOkay = VERR_INTERNAL_ERROR_3); \
     72    \
     73    PDMQUEUE_HANDLE_TO_VARS_RETURN_COMMON(PDMQUEUE_MAX_ITEM_SIZE, PDMQUEUE_MAX_TOTAL_SIZE_R0)
     74
     75#else
     76# define PDMQUEUE_HANDLE_TO_VARS_RETURN(a_pVM, a_hQueue, a_pvOwner) \
     77    AssertPtrReturn((a_pvOwner), VERR_INVALID_PARAMETER); \
     78    \
     79    PPDMQUEUE pQueue; \
     80    if ((a_hQueue) < RT_ELEMENTS((a_pVM)->pdm.s.apRing0Queues)) \
     81        pQueue = (a_pVM)->pdm.s.apRing0Queues[(a_hQueue)]; \
     82    else \
     83    { \
     84        (a_hQueue) -= RT_ELEMENTS((a_pVM)->pdm.s.apRing0Queues); \
     85        AssertReturn((a_pVM)->pdm.s.cRing3Queues, VERR_INVALID_HANDLE); \
     86        pQueue = (a_pVM)->pdm.s.papRing3Queues[(a_hQueue)]; \
     87    } \
     88    AssertPtrReturn(pQueue, VERR_INVALID_HANDLE); \
     89    AssertReturn(pQueue->u32Magic == PDMQUEUE_MAGIC, VERR_INVALID_HANDLE); \
     90    AssertReturn(pQueue->u.Gen.pvOwner == (a_pvOwner), VERR_INVALID_HANDLE); \
     91    AssertReturn(pQueue->rcOkay == VINF_SUCCESS, pQueue->rcOkay); \
     92    \
     93    uint32_t const cbItem   = pQueue->cbItem; \
     94    uint32_t const cItems   = pQueue->cItems; \
     95    uint32_t const offItems = pQueue->offItems; \
     96    \
     97    PDMQUEUE_HANDLE_TO_VARS_RETURN_COMMON(PDMQUEUE_MAX_ITEM_SIZE, PDMQUEUE_MAX_TOTAL_SIZE_R3)
     98
     99#endif
     100
     101
     102/**
     103 * Commmon function for initializing the shared queue structure.
     104 */
     105void pdmQueueInit(PPDMQUEUE pQueue, uint32_t cbBitmap, uint32_t cbItem, uint32_t cItems,
     106                  const char *pszName, PDMQUEUETYPE enmType, RTR3PTR pfnCallback, RTR3PTR pvOwner)
     107{
     108    Assert(cbBitmap * 8 >= cItems);
     109
     110    pQueue->u32Magic            = PDMQUEUE_MAGIC;
     111    pQueue->cbItem              = cbItem;
     112    pQueue->cItems              = cItems;
     113    pQueue->offItems            = RT_UOFFSETOF(PDMQUEUE, bmAlloc) + cbBitmap;
     114    pQueue->rcOkay              = VINF_SUCCESS;
     115    pQueue->u32Padding          = 0;
     116    pQueue->hTimer              = NIL_TMTIMERHANDLE;
     117    pQueue->cMilliesInterval    = 0;
     118    pQueue->enmType             = enmType;
     119    pQueue->u.Gen.pfnCallback   = pfnCallback;
     120    pQueue->u.Gen.pvOwner       = pvOwner;
     121    RTStrCopy(pQueue->szName, sizeof(pQueue->szName), pszName);
     122    pQueue->iPending            = UINT32_MAX;
     123    RT_BZERO(pQueue->bmAlloc, cbBitmap);
     124    ASMBitSetRange(pQueue->bmAlloc, 0, cItems);
     125
     126    uint8_t *pbItem = (uint8_t *)&pQueue->bmAlloc[0] + cbBitmap;
     127    while (cItems-- > 0)
     128    {
     129        ((PPDMQUEUEITEMCORE)pbItem)->u64View = UINT64_C(0xfeedfeedfeedfeed);
     130
     131        /* next */
     132        pbItem += cbItem;
     133    }
     134}
     135
     136
     137/**
     138 * Allocate an item from a queue, extended version.
     139 *
    37140 * The allocated item must be handed on to PDMR3QueueInsert() after the
    38141 * data have been filled in.
    39142 *
    40  * @returns Pointer to allocated queue item.
    41  * @returns NULL on failure. The queue is exhausted.
    42  * @param   pQueue      The queue handle.
     143 * @returns VBox status code.
     144 * @param   pVM         Pointer to the cross context VM structure w/ ring-0.
     145 * @param   hQueue      The queue handle.
     146 * @param   pvOwner     The queue owner.
     147 * @param   ppNew       Where to return the item pointer on success.
    43148 * @thread  Any thread.
    44149 */
    45 VMMDECL(PPDMQUEUEITEMCORE) PDMQueueAlloc(PPDMQUEUE pQueue)
    46 {
    47     Assert(RT_VALID_PTR(pQueue) && pQueue->CTX_SUFF(pVM));
    48     PPDMQUEUEITEMCORE pNew;
    49     uint32_t iNext;
    50     uint32_t i;
    51     do
     150VMMDECL(int) PDMQueueAllocEx(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner, PPDMQUEUEITEMCORE *ppNew)
     151{
     152    /*
     153     * Validate and translate input.
     154     */
     155    *ppNew = NULL;
     156    PDMQUEUE_HANDLE_TO_VARS_RETURN(pVM, hQueue, pvOwner);
     157
     158    /*
     159     * Do the allocation.
     160     */
     161    uint32_t cEmptyScans = 0;
     162    for (;;)
    52163    {
    53         i = pQueue->iFreeTail;
    54         if (i == pQueue->iFreeHead)
     164        int32_t iBit = ASMBitFirstSet(pQueue->bmAlloc, cItems);
     165        if (iBit >= 0)
     166        {
     167            if (ASMAtomicBitTestAndClear(pQueue->bmAlloc, iBit))
     168            {
     169                PPDMQUEUEITEMCORE pNew = (PPDMQUEUEITEMCORE)&((uint8_t *)pQueue)[offItems + iBit * cbItem];
     170                pNew->u64View = UINT64_C(0xbeefbeefbeefbeef);
     171                *ppNew = pNew;
     172                return VINF_SUCCESS;
     173            }
     174            cEmptyScans = 0;
     175        }
     176        else if (++cEmptyScans < 16)
     177            ASMNopPause();
     178        else
    55179        {
    56180            STAM_REL_COUNTER_INC(&pQueue->StatAllocFailures);
    57             return NULL;
     181            return VERR_OUT_OF_RESOURCES;
    58182        }
    59         pNew = pQueue->aFreeItems[i].CTX_SUFF(pItem);
    60         iNext = (i + 1) % (pQueue->cItems + PDMQUEUE_FREE_SLACK);
    61     } while (!ASMAtomicCmpXchgU32(&pQueue->iFreeTail, iNext, i));
    62     return pNew;
     183    }
     184}
     185
     186
     187/**
     188 * Allocate an item from a queue.
     189 *
     190 * The allocated item must be handed on to PDMR3QueueInsert() after the
     191 * data have been filled in.
     192 *
     193 * @returns VBox status code.
     194 * @param   pVM         Pointer to the cross context VM structure w/ ring-0.
     195 * @param   hQueue      The queue handle.
     196 * @param   pvOwner     The queue owner.
     197 * @param   ppNew       Where to return the item pointer on success.
     198 * @thread  Any thread.
     199 */
     200VMMDECL(PPDMQUEUEITEMCORE) PDMQueueAlloc(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner)
     201{
     202    PPDMQUEUEITEMCORE pNew = NULL;
     203    int rc = PDMQueueAllocEx(pVM, hQueue, pvOwner, &pNew);
     204    if (RT_SUCCESS(rc))
     205        return pNew;
     206    return NULL;
    63207}
    64208
     
    67211 * Sets the FFs and fQueueFlushed.
    68212 *
    69  * @param   pQueue              The PDM queue.
    70  */
    71 static void pdmQueueSetFF(PPDMQUEUE pQueue)
    72 {
    73     PVM pVM = pQueue->CTX_SUFF(pVM);
     213 * @param   pVM         Pointer to the cross context VM structure w/ ring-0.
     214 */
     215static void pdmQueueSetFF(PVMCC pVM)
     216{
    74217    Log2(("PDMQueueInsert: VM_FF_PDM_QUEUES %d -> 1\n", VM_FF_IS_SET(pVM, VM_FF_PDM_QUEUES)));
    75218    VM_FF_SET(pVM, VM_FF_PDM_QUEUES);
     
    87230 * have been passed to this function it must not be touched!
    88231 *
    89  * @param   pQueue      The queue handle.
    90  * @param   pItem       The item to insert.
     232 * @returns VBox status code.
     233 * @param   pVM         Pointer to the cross context VM structure w/ ring-0.
     234 * @param   hQueue      The queue handle.
     235 * @param   pvOwner     The queue owner.
     236 * @param   pInsert     The item to insert.
    91237 * @thread  Any thread.
    92238 */
    93 VMMDECL(void) PDMQueueInsert(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem)
    94 {
    95     Assert(RT_VALID_PTR(pQueue) && pQueue->CTX_SUFF(pVM));
    96     AssertPtr(pItem);
    97 
    98 #if 0 /* the paranoid android version: */
    99     void *pvNext;
    100     do
     239VMMDECL(int) PDMQueueInsert(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner, PPDMQUEUEITEMCORE pInsert)
     240{
     241    /*
     242     * Validate and translate input.
     243     */
     244    PDMQUEUE_HANDLE_TO_VARS_RETURN(pVM, hQueue, pvOwner);
     245
     246    uint8_t * const pbItems   = (uint8_t *)pQueue + offItems;
     247    uintptr_t const offInsert = (uintptr_t)pInsert - (uintptr_t)pbItems;
     248    uintptr_t const iInsert   = offInsert / cbItem;
     249    AssertReturn(iInsert < cItems, VERR_INVALID_PARAMETER);
     250    AssertReturn(iInsert * cbItem == offInsert, VERR_INVALID_PARAMETER);
     251
     252    AssertReturn(ASMBitTest(pQueue->bmAlloc, iInsert) == false, VERR_INVALID_PARAMETER);
     253
     254    /*
     255     * Append the item to the pending list.
     256     */
     257    for (;;)
    101258    {
    102         pvNext = ASMAtomicUoReadPtr((void * volatile *)&pQueue->CTX_SUFF(pPending));
    103         ASMAtomicUoWritePtr((void * volatile *)&pItem->CTX_SUFF(pNext), pvNext);
    104     } while (!ASMAtomicCmpXchgPtr(&pQueue->CTX_SUFF(pPending), pItem, pvNext));
    105 #else
    106     PPDMQUEUEITEMCORE pNext;
    107     do
    108     {
    109         pNext = pQueue->CTX_SUFF(pPending);
    110         pItem->CTX_SUFF(pNext) = pNext;
    111     } while (!ASMAtomicCmpXchgPtr(&pQueue->CTX_SUFF(pPending), pItem, pNext));
    112 #endif
     259        uint32_t const iOldPending = ASMAtomicUoReadU32(&pQueue->iPending);
     260        pInsert->iNext = iOldPending;
     261        if (ASMAtomicCmpXchgU32(&pQueue->iPending, iInsert, iOldPending))
     262            break;
     263        ASMNopPause();
     264    }
    113265
    114266    if (pQueue->hTimer == NIL_TMTIMERHANDLE)
    115         pdmQueueSetFF(pQueue);
     267        pdmQueueSetFF(pVM);
    116268    STAM_REL_COUNTER_INC(&pQueue->StatInsert);
    117269    STAM_STATS({ ASMAtomicIncU32(&pQueue->cStatPending); });
    118 }
    119 
    120 
    121 /**
    122  * Queue an item.
    123  *
    124  * The item must have been obtained using PDMQueueAlloc(). Once the item
    125  * have been passed to this function it must not be touched!
    126  *
    127  * @param   pQueue          The queue handle.
    128  * @param   pItem           The item to insert.
    129  * @param   NanoMaxDelay    The maximum delay before processing the queue, in nanoseconds.
    130  *                          This applies only to GC.
    131  * @thread  Any thread.
    132  */
    133 VMMDECL(void) PDMQueueInsertEx(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem, uint64_t NanoMaxDelay)
    134 {
    135     NOREF(NanoMaxDelay);
    136     PDMQueueInsert(pQueue, pItem);
    137 #ifdef IN_RC
    138     PVM pVM = pQueue->CTX_SUFF(pVM);
    139     /** @todo figure out where to put this, the next bit should go there too.
    140     if (NanoMaxDelay)
     270
     271    return VINF_SUCCESS;
     272}
     273
     274
     275/**
     276 * Schedule the queue for flushing (processing) if necessary.
     277 *
     278 * @returns VBox status code.
     279 * @retval  VINF_SUCCESS if a flush was necessary.
     280 * @retval  VINF_NO_CHANGE if no flushing needed.
     281 *
     282 * @param   pVM         The cross context VM structure.
     283 * @param   pvOwner     The alleged queue owner.
     284 * @param   hQueue      The queueu to maybe flush.
     285 */
     286VMMDECL(int) PDMQueueFlushIfNecessary(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner)
     287{
     288    /*
     289     * Validate input.
     290     */
     291    PDMQUEUE_HANDLE_TO_VARS_RETURN(pVM, hQueue, pvOwner);
     292    RT_NOREF(offItems);
     293
     294    /*
     295     * Check and maybe flush.
     296     */
     297    if (ASMAtomicUoReadU32(&pQueue->iPending) != UINT32_MAX)
    141298    {
    142 
     299        pdmQueueSetFF(pVM);
     300        return VINF_SUCCESS;
    143301    }
    144     else */
    145     {
    146         VMCPU_FF_SET(VMMGetCpu0(pVM), VMCPU_FF_TO_R3);
    147         Log2(("PDMQueueInsertEx: Setting VMCPU_FF_TO_R3\n"));
    148     }
    149 #endif
    150 }
    151 
    152 
    153 /**
    154  * Gets the ring-0 pointer for the specified queue.
    155  *
    156  * @returns The ring-0 address of the queue.
    157  * @returns NULL if pQueue is invalid.
    158  * @param   pQueue          The queue handle.
    159  */
    160 VMMDECL(R0PTRTYPE(PPDMQUEUE)) PDMQueueR0Ptr(PPDMQUEUE pQueue)
    161 {
    162     AssertPtr(pQueue);
    163     Assert(pQueue->pVMR3);
    164 #ifdef IN_RING0
    165     AssertPtr(pQueue->pVMR0);
    166     return pQueue;
    167 #else
    168     Assert(pQueue->pVMR0 || SUPR3IsDriverless());
    169     return MMHyperCCToR0(pQueue->CTX_SUFF(pVM), pQueue);
    170 #endif
    171 }
    172 
    173 
    174 /**
    175  * Schedule the queue for flushing (processing) if necessary.
    176  *
    177  * @returns @c true if necessary, @c false if not.
    178  * @param   pQueue              The queue.
    179  */
    180 VMMDECL(bool) PDMQueueFlushIfNecessary(PPDMQUEUE pQueue)
    181 {
    182     AssertPtr(pQueue);
    183     if (   pQueue->pPendingR3 != NIL_RTR3PTR
    184         || pQueue->pPendingR0 != NIL_RTR0PTR)
    185     {
    186         pdmQueueSetFF(pQueue);
    187         return false;
    188     }
    189     return false;
    190 }
    191 
     302    return VINF_NO_CHANGE;
     303}
     304
  • trunk/src/VBox/VMM/VMMR0/PDMR0DevHlp.cpp

    r93115 r93609  
    245245
    246246        /* queue for ring-3 execution. */
    247         PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM->pdm.s.pDevHlpQueueR0);
     247        PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM, pGVM->pdm.s.hDevHlpQueue, pGVM);
    248248        AssertReturnVoid(pTask);
    249249
     
    253253        pTask->u.PciSetIrq.iLevel = iLevel;
    254254        pTask->u.PciSetIrq.uTagSrc = uTagSrc;
    255         pTask->u.PciSetIrq.pPciDevR3 = MMHyperR0ToR3(pGVM, pPciDev);
    256 
    257         PDMQueueInsertEx(pGVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
     255        pTask->u.PciSetIrq.idxPciDev = pPciDev->Int.s.idxSubDev;
     256
     257        PDMQueueInsert(pGVM, pGVM->pdm.s.hDevHlpQueue, pGVM, &pTask->Core);
    258258    }
    259259
     
    581581
    582582
    583 /** Converts a queue handle to a ring-0 queue pointer. */
    584 DECLINLINE(PPDMQUEUE)  pdmR0DevHlp_QueueToPtr(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)
    585 {
    586     PDMDEV_ASSERT_DEVINS(pDevIns);
    587     return (PPDMQUEUE)MMHyperR3ToCC(pDevIns->Internal.s.pGVM, hQueue);
    588 }
    589 
    590 
    591583/** @interface_method_impl{PDMDEVHLPR0,pfnQueueAlloc} */
    592584static DECLCALLBACK(PPDMQUEUEITEMCORE) pdmR0DevHlp_QueueAlloc(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)
    593585{
    594     return PDMQueueAlloc(pdmR0DevHlp_QueueToPtr(pDevIns, hQueue));
     586    PDMDEV_ASSERT_DEVINS(pDevIns);
     587    return PDMQueueAlloc(pDevIns->Internal.s.pGVM, hQueue, pDevIns);
    595588}
    596589
    597590
    598591/** @interface_method_impl{PDMDEVHLPR0,pfnQueueInsert} */
    599 static DECLCALLBACK(void) pdmR0DevHlp_QueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
    600 {
    601     return PDMQueueInsert(pdmR0DevHlp_QueueToPtr(pDevIns, hQueue), pItem);
     592static DECLCALLBACK(int) pdmR0DevHlp_QueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
     593{
     594    PDMDEV_ASSERT_DEVINS(pDevIns);
     595    return PDMQueueInsert(pDevIns->Internal.s.pGVM, hQueue, pDevIns, pItem);
    602596}
    603597
     
    606600static DECLCALLBACK(bool) pdmR0DevHlp_QueueFlushIfNecessary(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)
    607601{
    608     return PDMQueueFlushIfNecessary(pdmR0DevHlp_QueueToPtr(pDevIns, hQueue));
     602    PDMDEV_ASSERT_DEVINS(pDevIns);
     603    return PDMQueueFlushIfNecessary(pDevIns->Internal.s.pGVM, hQueue, pDevIns) == VINF_SUCCESS;
    609604}
    610605
     
    17861781    {
    17871782        /* queue for ring-3 execution. */
    1788         PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM->pdm.s.pDevHlpQueueR0);
     1783        PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM, pGVM->pdm.s.hDevHlpQueue, pGVM);
    17891784        if (pTask)
    17901785        {
     
    17961791            pTask->u.IoApicSetIrq.uTagSrc = uTagSrc;
    17971792
    1798             PDMQueueInsertEx(pGVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
     1793            PDMQueueInsert(pGVM, pGVM->pdm.s.hDevHlpQueue, pGVM, &pTask->Core);
    17991794        }
    18001795        else
     
    19751970
    19761971    /* queue for ring-3 execution. */
    1977     PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM->pdm.s.pDevHlpQueueR0);
     1972    PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM, pGVM->pdm.s.hDevHlpQueue, pGVM);
    19781973    AssertReturn(pTask, false);
    19791974
     
    19851980    pTask->u.IsaSetIrq.uTagSrc = uTagSrc;
    19861981
    1987     PDMQueueInsertEx(pGVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
     1982    PDMQueueInsert(pGVM, pGVM->pdm.s.hDevHlpQueue, pGVM, &pTask->Core);
    19881983    return false;
    19891984}
  • trunk/src/VBox/VMM/VMMR0/PDMR0DevHlpTracing.cpp

    r93115 r93609  
    408408
    409409        /* queue for ring-3 execution. */
    410         PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM->pdm.s.pDevHlpQueueR0);
     410        PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM, pGVM->pdm.s.hDevHlpQueue, pGVM);
    411411        AssertReturnVoid(pTask);
    412412
     
    416416        pTask->u.PciSetIrq.iLevel = iLevel;
    417417        pTask->u.PciSetIrq.uTagSrc = uTagSrc;
    418         pTask->u.PciSetIrq.pPciDevR3 = MMHyperR0ToR3(pGVM, pPciDev);
    419 
    420         PDMQueueInsertEx(pGVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
     418        pTask->u.PciSetIrq.idxPciDev = pPciDev->Int.s.idxSubDev;
     419
     420        PDMQueueInsert(pGVM, pGVM->pdm.s.hDevHlpQueue, pGVM, &pTask->Core);
    421421    }
    422422
  • trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp

    r93554 r93609  
    193193        if (pDevIns)
    194194            pdmR0DeviceDestroy(pGVM, pDevIns, i);
     195    }
     196
     197    i = pGVM->pdmr0.s.cQueues;
     198    while (i-- > 0)
     199    {
     200        if (pGVM->pdmr0.s.aQueues[i].pQueue != NULL)
     201            pdmR0QueueDestroy(pGVM, i);
    195202    }
    196203}
  • trunk/src/VBox/VMM/VMMR0/VMMR0.cpp

    r93554 r93609  
    20722072        }
    20732073
     2074        case VMMR0_DO_PDM_QUEUE_CREATE:
     2075        {
     2076            if (!pReqHdr || u64Arg || idCpu != 0)
     2077                return VERR_INVALID_PARAMETER;
     2078            rc = PDMR0QueueCreateReqHandler(pGVM, (PPDMQUEUECREATEREQ)pReqHdr);
     2079            break;
     2080        }
     2081
    20742082        /*
    20752083         * Requests to the internal networking service.
  • trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp

    r93554 r93609  
    27472747    }
    27482748
    2749     PPDMQUEUE pQueue = NULL;
    2750     int rc = PDMR3QueueCreateDevice(pVM, pDevIns, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName, &pQueue);
    2751     *phQueue = (uintptr_t)pQueue;
    2752 
    2753     LogFlow(("pdmR3DevHlp_QueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pDevIns->pReg->szName, pDevIns->iInstance, rc, *phQueue));
     2749    int rc = PDMR3QueueCreateDevice(pVM, pDevIns, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName, phQueue);
     2750
     2751    LogFlow(("pdmR3DevHlp_QueueCreate: caller='%s'/%d: returns %Rrc *phQueue=%p\n",
     2752             pDevIns->pReg->szName, pDevIns->iInstance, rc, *phQueue));
    27542753    return rc;
    27552754}
     
    27702769static DECLCALLBACK(PPDMQUEUEITEMCORE) pdmR3DevHlp_QueueAlloc(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)
    27712770{
    2772     return PDMQueueAlloc(pdmR3DevHlp_QueueToPtr(pDevIns, hQueue));
     2771    PDMDEV_ASSERT_DEVINS(pDevIns);
     2772    return PDMQueueAlloc(pDevIns->Internal.s.pVMR3, hQueue, pDevIns);
    27732773}
    27742774
    27752775
    27762776/** @interface_method_impl{PDMDEVHLPR3,pfnQueueInsert} */
    2777 static DECLCALLBACK(void) pdmR3DevHlp_QueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
    2778 {
    2779     return PDMQueueInsert(pdmR3DevHlp_QueueToPtr(pDevIns, hQueue), pItem);
     2777static DECLCALLBACK(int) pdmR3DevHlp_QueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
     2778{
     2779    return PDMQueueInsert(pDevIns->Internal.s.pVMR3, hQueue, pDevIns, pItem);
    27802780}
    27812781
     
    27842784static DECLCALLBACK(bool) pdmR3DevHlp_QueueFlushIfNecessary(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)
    27852785{
    2786     return PDMQueueFlushIfNecessary(pdmR3DevHlp_QueueToPtr(pDevIns, hQueue));
     2786    return PDMQueueFlushIfNecessary(pDevIns->Internal.s.pVMR3, hQueue, pDevIns) == VINF_SUCCESS;
    27872787}
    27882788
     
    63606360        {
    63616361            /* Same as pdmR3DevHlp_PCISetIrq, except we've got a tag already. */
    6362             PPDMPCIDEV pPciDev = pTask->u.PciSetIrq.pPciDevR3;
     6362            PPDMDEVINSR3 pDevIns = pTask->pDevInsR3;
     6363            PPDMPCIDEV   pPciDev = pTask->u.PciSetIrq.idxPciDev < RT_ELEMENTS(pDevIns->apPciDevs)
     6364                                 ? pDevIns->apPciDevs[pTask->u.PciSetIrq.idxPciDev] : NULL;
    63636365            if (pPciDev)
    63646366            {
     
    63736375            }
    63746376            else
    6375                 AssertReleaseMsgFailed(("No PCI device registered!\n"));
     6377                AssertReleaseMsgFailed(("No PCI device given! (%#x)\n", pPciDev->Int.s.idxSubDev));
    63766378            break;
    63776379        }
  • trunk/src/VBox/VMM/VMMR3/PDMDevice.cpp

    r93115 r93609  
    131131     * Get the RC & R0 devhlps and create the devhlp R3 task queue.
    132132     */
    133     rc = PDMR3QueueCreateInternal(pVM, sizeof(PDMDEVHLPTASK), 8, 0, pdmR3DevHlpQueueConsumer, true, "DevHlp",
    134                                   &pVM->pdm.s.pDevHlpQueueR3);
     133    rc = PDMR3QueueCreateInternal(pVM, sizeof(PDMDEVHLPTASK), pVM->cCpus * 8, 0, pdmR3DevHlpQueueConsumer, true, "DevHlp",
     134                                  &pVM->pdm.s.hDevHlpQueue);
    135135    AssertRCReturn(rc, rc);
    136     pVM->pdm.s.pDevHlpQueueR0 = PDMQueueR0Ptr(pVM->pdm.s.pDevHlpQueueR3);
    137136
    138137    /*
  • trunk/src/VBox/VMM/VMMR3/PDMDriver.cpp

    r93115 r93609  
    12551255
    12561256
    1257 /**
    1258  * Conversion from handle to queue pointer (temporary).
    1259  */
    1260 DECLINLINE(PPDMQUEUE) pdmR3DrvHlp_QueueToPtr(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)
    1261 {
    1262     PDMDRV_ASSERT_DRVINS(pDrvIns);
    1263     RT_NOREF(pDrvIns);
    1264     return (PPDMQUEUE)hQueue;
    1265 }
    1266 
    1267 
    12681257/** @interface_method_impl{PDMDRVHLPR3,pfnQueueCreate} */
    12691258static DECLCALLBACK(int) pdmR3DrvHlp_QueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
     
    12821271    }
    12831272
    1284     PPDMQUEUE pQueue = NULL;
    1285     int rc = PDMR3QueueCreateDriver(pVM, pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, &pQueue);
    1286     *phQueue = (PDMQUEUEHANDLE)pQueue;
     1273    int rc = PDMR3QueueCreateDriver(pVM, pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, phQueue);
    12871274
    12881275    LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *phQueue=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *phQueue));
     
    12941281static DECLCALLBACK(PPDMQUEUEITEMCORE) pdmR3DrvHlp_QueueAlloc(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)
    12951282{
    1296     return PDMQueueAlloc(pdmR3DrvHlp_QueueToPtr(pDrvIns, hQueue));
     1283    return PDMQueueAlloc(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns);
    12971284}
    12981285
    12991286
    13001287/** @interface_method_impl{PDMDRVHLPR3,pfnQueueInsert} */
    1301 static DECLCALLBACK(void) pdmR3DrvHlp_QueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
    1302 {
    1303     return PDMQueueInsert(pdmR3DrvHlp_QueueToPtr(pDrvIns, hQueue), pItem);
     1288static DECLCALLBACK(int) pdmR3DrvHlp_QueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
     1289{
     1290    return PDMQueueInsert(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns, pItem);
    13041291}
    13051292
     
    13081295static DECLCALLBACK(bool) pdmR3DrvHlp_QueueFlushIfNecessary(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)
    13091296{
    1310     return PDMQueueFlushIfNecessary(pdmR3DrvHlp_QueueToPtr(pDrvIns, hQueue));
    1311 }
    1312 
     1297    return PDMQueueFlushIfNecessary(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns) == VINF_SUCCESS;
     1298}
    13131299
    13141300
  • trunk/src/VBox/VMM/VMMR3/PDMQueue.cpp

    r93115 r93609  
    3131#include <iprt/asm.h>
    3232#include <iprt/assert.h>
     33#include <iprt/mem.h>
    3334#include <iprt/thread.h>
    3435
     
    3738*   Internal Functions                                                                                                           *
    3839*********************************************************************************************************************************/
    39 DECLINLINE(void)            pdmR3QueueFreeItem(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem);
    40 static bool                 pdmR3QueueFlush(PPDMQUEUE pQueue);
    4140static DECLCALLBACK(void)   pdmR3QueueTimer(PVM pVM, TMTIMERHANDLE hTimer, void *pvUser);
    4241
     
    5453 * @param   fRZEnabled          Set if the queue will be used from RC/R0 and need to be allocated from the hyper heap.
    5554 * @param   pszName             The queue name. Unique. Not copied.
    56  * @param   ppQueue             Where to store the queue handle.
     55 * @param   enmType             Owner type.
     56 * @param   pvOwner             The queue owner pointer.
     57 * @param   uCallback           Callback function.
     58 * @param   phQueue             Where to store the queue handle.
    5759 */
    5860static int pdmR3QueueCreate(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, bool fRZEnabled,
    59                             const char *pszName, PPDMQUEUE *ppQueue)
    60 {
    61     PUVM pUVM = pVM->pUVM;
    62 
    63     /*
    64      * Validate input.
    65      */
    66     AssertMsgReturn(cbItem >= sizeof(PDMQUEUEITEMCORE) && cbItem < _1M, ("cbItem=%zu\n", cbItem), VERR_OUT_OF_RANGE);
    67     AssertMsgReturn(cItems >= 1 && cItems <= _64K, ("cItems=%u\n", cItems), VERR_OUT_OF_RANGE);
     61                            const char *pszName, PDMQUEUETYPE enmType, void *pvOwner, uintptr_t uCallback,
     62                            PDMQUEUEHANDLE *phQueue)
     63{
     64    /*
     65     * Validate and adjust the input.
     66     */
     67    VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); /* serialization by exclusivity */
     68
     69    cbItem = RT_ALIGN(cbItem, sizeof(uint64_t));
     70    AssertMsgReturn(cbItem >= sizeof(PDMQUEUEITEMCORE) && cbItem < PDMQUEUE_MAX_ITEM_SIZE, ("cbItem=%zu\n", cbItem),
     71                    VERR_OUT_OF_RANGE);
     72    AssertMsgReturn(cItems >= 1 && cItems <= PDMQUEUE_MAX_ITEMS, ("cItems=%u\n", cItems), VERR_OUT_OF_RANGE);
     73    AssertMsgReturn((uint64_t)cbItem * cItems <= (fRZEnabled ? PDMQUEUE_MAX_TOTAL_SIZE_R0 : PDMQUEUE_MAX_TOTAL_SIZE_R3),
     74                    ("cItems=%u cbItem=%#x -> %#RX64, max %'u\n", cItems, cbItem, (uint64_t)cbItem * cItems,
     75                     fRZEnabled ? PDMQUEUE_MAX_TOTAL_SIZE_R0 : PDMQUEUE_MAX_TOTAL_SIZE_R3),
     76                    VERR_OUT_OF_RANGE);
     77    AssertReturn(!fRZEnabled || enmType == PDMQUEUETYPE_INTERNAL || enmType == PDMQUEUETYPE_DEV, VERR_INVALID_PARAMETER);
     78    if (SUPR3IsDriverless())
     79        fRZEnabled = false;
     80
     81    /* Unqiue name that fits within the szName field: */
     82    size_t cchName = strlen(pszName);
     83    AssertReturn(cchName > 0, VERR_INVALID_NAME);
     84    AssertMsgReturn(cchName < RT_SIZEOFMEMB(PDMQUEUE, szName), ("'%s' is too long\n", pszName), VERR_INVALID_NAME);
     85    size_t i = pVM->pdm.s.cRing3Queues;
     86    while (i-- > 0 )
     87        AssertMsgReturn(strcmp(pVM->pdm.s.papRing3Queues[i]->szName, pszName) != 0, ("%s\n", pszName), VERR_DUPLICATE);
     88    i = pVM->pdm.s.cRing0Queues;
     89    while (i-- > 0 )
     90        AssertMsgReturn(strcmp(pVM->pdm.s.apRing0Queues[i]->szName, pszName) != 0, ("%s\n", pszName), VERR_DUPLICATE);
    6891
    6992    /*
    7093     * Align the item size and calculate the structure size.
    7194     */
    72     cbItem = RT_ALIGN(cbItem, sizeof(RTUINTPTR));
    73     size_t cb = cbItem * cItems + RT_ALIGN_Z(RT_UOFFSETOF_DYN(PDMQUEUE, aFreeItems[cItems + PDMQUEUE_FREE_SLACK]), 16);
    74     PPDMQUEUE pQueue;
    75     int rc;
     95    PPDMQUEUE      pQueue;
     96    PDMQUEUEHANDLE hQueue;
    7697    if (fRZEnabled)
    77         rc = MMHyperAlloc(pVM, cb, 0, MM_TAG_PDM_QUEUE, (void **)&pQueue );
     98    {
     99        /* Call ring-0 to allocate and create the queue: */
     100        PDMQUEUECREATEREQ Req;
     101        Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
     102        Req.Hdr.cbReq    = sizeof(Req);
     103        Req.cItems       = cItems;
     104        Req.cbItem       = (uint32_t)cbItem;
     105        Req.enmType      = enmType;
     106        Req.pvOwner      = pvOwner;
     107        Req.pfnCallback  = (RTR3PTR)uCallback;
     108        RTStrCopy(Req.szName, sizeof(Req.szName), pszName);
     109        AssertCompileMembersSameSize(PDMQUEUECREATEREQ, szName, PDMQUEUE, szName);
     110        Req.hQueue       = NIL_PDMQUEUEHANDLE;
     111
     112        int rc = VMMR3CallR0(pVM, VMMR0_DO_PDM_QUEUE_CREATE, 0, &Req.Hdr);
     113        if (RT_FAILURE(rc))
     114            return rc;
     115        hQueue = Req.hQueue;
     116        AssertReturn(hQueue < RT_ELEMENTS(pVM->pdm.s.apRing0Queues), VERR_INTERNAL_ERROR_2);
     117        pQueue = pVM->pdm.s.apRing0Queues[hQueue];
     118        AssertPtrReturn(pQueue, VERR_INTERNAL_ERROR_3);
     119        AssertReturn(pQueue->u32Magic == PDMQUEUE_MAGIC, VERR_INTERNAL_ERROR_4);
     120        AssertReturn(pQueue->cbItem == cbItem, VERR_INTERNAL_ERROR_4);
     121        AssertReturn(pQueue->cItems == cItems, VERR_INTERNAL_ERROR_4);
     122        AssertReturn(pQueue->enmType == enmType, VERR_INTERNAL_ERROR_4);
     123        AssertReturn(pQueue->u.Gen.pvOwner == pvOwner, VERR_INTERNAL_ERROR_4);
     124        AssertReturn(pQueue->u.Gen.pfnCallback == (RTR3PTR)uCallback, VERR_INTERNAL_ERROR_4);
     125    }
    78126    else
    79         rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_QUEUE, cb, (void **)&pQueue);
    80     if (RT_FAILURE(rc))
    81         return rc;
    82 
    83     /*
    84      * Initialize the data fields.
    85      */
    86     pQueue->pVMR3 = pVM;
    87     pQueue->pVMR0 = fRZEnabled ? pVM->pVMR0ForCall : NIL_RTR0PTR;
    88     pQueue->pszName = pszName;
    89     pQueue->cMilliesInterval = cMilliesInterval;
    90     pQueue->hTimer = NIL_TMTIMERHANDLE;
    91     pQueue->cbItem = (uint32_t)cbItem;
    92     pQueue->cItems = cItems;
    93     //pQueue->pPendingR3 = NULL;
    94     //pQueue->pPendingR0 = NULL;
    95     //pQueue->pPendingRC = NULL;
    96     pQueue->iFreeHead = cItems;
    97     //pQueue->iFreeTail = 0;
    98     PPDMQUEUEITEMCORE pItem = (PPDMQUEUEITEMCORE)((char *)pQueue + RT_ALIGN_Z(RT_UOFFSETOF_DYN(PDMQUEUE, aFreeItems[cItems + PDMQUEUE_FREE_SLACK]), 16));
    99     for (unsigned i = 0; i < cItems; i++, pItem = (PPDMQUEUEITEMCORE)((char *)pItem + cbItem))
    100     {
    101         pQueue->aFreeItems[i].pItemR3 = pItem;
    102         if (fRZEnabled)
    103             pQueue->aFreeItems[i].pItemR0 = MMHyperR3ToR0(pVM, pItem);
     127    {
     128        /* Do it here using the paged heap: */
     129        uint32_t const cbBitmap = RT_ALIGN_32(RT_ALIGN_32(cItems, 64) / 8, 64); /* keep bitmap in it's own cacheline  */
     130        uint32_t const cbQueue  = RT_OFFSETOF(PDMQUEUE, bmAlloc)
     131                                + cbBitmap
     132                                + (uint32_t)cbItem * cItems;
     133        pQueue = (PPDMQUEUE)RTMemPageAllocZ(cbQueue);
     134        if (!pQueue)
     135            return VERR_NO_PAGE_MEMORY;
     136        pdmQueueInit(pQueue, cbBitmap, (uint32_t)cbItem, cItems, pszName, enmType, (RTR3PTR)uCallback, pvOwner);
     137
     138        uint32_t iQueue = pVM->pdm.s.cRing3Queues;
     139        if (iQueue >= pVM->pdm.s.cRing3QueuesAlloc)
     140        {
     141            AssertLogRelMsgReturnStmt(iQueue < _16K, ("%#x\n", iQueue), RTMemPageFree(pQueue, cbQueue), VERR_TOO_MANY_OPENS);
     142
     143            uint32_t const cNewAlloc = RT_ALIGN_32(iQueue, 64) + 64;
     144            PPDMQUEUE *papQueuesNew = (PPDMQUEUE *)RTMemAllocZ(cNewAlloc * sizeof(papQueuesNew[0]));
     145            AssertLogRelMsgReturnStmt(papQueuesNew, ("cNewAlloc=%u\n", cNewAlloc), RTMemPageFree(pQueue, cbQueue), VERR_NO_MEMORY);
     146
     147            if (iQueue)
     148                memcpy(papQueuesNew, pVM->pdm.s.papRing3Queues, iQueue * sizeof(papQueuesNew[0]));
     149            PPDMQUEUE *papQueuesOld = ASMAtomicXchgPtrT(&pVM->pdm.s.papRing3Queues, papQueuesNew, PPDMQUEUE *);
     150            pVM->pdm.s.cRing3QueuesAlloc = cNewAlloc;
     151            RTMemFree(papQueuesOld);
     152        }
     153
     154        pVM->pdm.s.papRing3Queues[iQueue] = pQueue;
     155        pVM->pdm.s.cRing3Queues           = iQueue + 1;
     156        hQueue = iQueue + RT_ELEMENTS(pVM->pdm.s.apRing0Queues);
    104157    }
    105158
     
    109162    if (cMilliesInterval)
    110163    {
    111         char szName[32];
    112         RTStrPrintf(szName, sizeof(szName), "Queue %s", pQueue->pszName);
    113         rc = TMR3TimerCreate(pVM, TMCLOCK_REAL, pdmR3QueueTimer, pQueue, TMTIMER_FLAGS_NO_RING0, szName, &pQueue->hTimer);
     164        char szName[48+6];
     165        RTStrPrintf(szName, sizeof(szName), "Que/%s", pQueue->szName);
     166        int rc = TMR3TimerCreate(pVM, TMCLOCK_REAL, pdmR3QueueTimer, pQueue, TMTIMER_FLAGS_NO_RING0, szName, &pQueue->hTimer);
    114167        if (RT_SUCCESS(rc))
    115168        {
    116169            rc = TMTimerSetMillies(pVM, pQueue->hTimer, cMilliesInterval);
    117             if (RT_FAILURE(rc))
     170            if (RT_SUCCESS(rc))
     171                pQueue->cMilliesInterval = cMilliesInterval;
     172            else
    118173            {
    119174                AssertMsgFailed(("TMTimerSetMillies failed rc=%Rrc\n", rc));
    120175                int rc2 = TMR3TimerDestroy(pVM, pQueue->hTimer); AssertRC(rc2);
     176                pQueue->hTimer = NIL_TMTIMERHANDLE;
    121177            }
    122178        }
     
    125181        if (RT_FAILURE(rc))
    126182        {
    127             if (fRZEnabled)
    128                 MMHyperFree(pVM, pQueue);
    129             else
    130                 MMR3HeapFree(pQueue);
     183            if (!fRZEnabled)
     184                PDMR3QueueDestroy(pVM, hQueue, pvOwner);
     185            /* else: will clean up queue when VM is destroyed */
    131186            return rc;
    132187        }
    133 
    134         /*
    135          * Insert into the queue list for timer driven queues.
    136          */
    137         pdmLock(pVM);
    138         pQueue->pNext = pUVM->pdm.s.pQueuesTimer;
    139         pUVM->pdm.s.pQueuesTimer = pQueue;
    140         pdmUnlock(pVM);
    141     }
    142     else
    143     {
    144         /*
    145          * Insert into the queue list for forced action driven queues.
    146          * This is a FIFO, so insert at the end.
    147          */
    148         /** @todo we should add a priority to the queues so we don't have to rely on
    149          * the initialization order to deal with problems like @bugref{1605} (pgm/pcnet
    150          * deadlock caused by the critsect queue to be last in the chain).
    151          * - Update, the critical sections are no longer using queues, so this isn't a real
    152          *   problem any longer. The priority might be a nice feature for later though.
    153          */
    154         pdmLock(pVM);
    155         if (!pUVM->pdm.s.pQueuesForced)
    156             pUVM->pdm.s.pQueuesForced = pQueue;
    157         else
    158         {
    159             PPDMQUEUE pPrev = pUVM->pdm.s.pQueuesForced;
    160             while (pPrev->pNext)
    161                 pPrev = pPrev->pNext;
    162             pPrev->pNext = pQueue;
    163         }
    164         pdmUnlock(pVM);
    165188    }
    166189
     
    168191     * Register the statistics.
    169192     */
    170     STAMR3RegisterF(pVM, &pQueue->cbItem,               STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,        "Item size.",                       "/PDM/Queue/%s/cbItem",         pQueue->pszName);
    171     STAMR3RegisterF(pVM, &pQueue->cItems,               STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,        "Queue size.",                      "/PDM/Queue/%s/cItems",         pQueue->pszName);
    172     STAMR3RegisterF(pVM, &pQueue->StatAllocFailures,    STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,   "PDMQueueAlloc failures.",          "/PDM/Queue/%s/AllocFailures",  pQueue->pszName);
    173     STAMR3RegisterF(pVM, &pQueue->StatInsert,           STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS,        "Calls to PDMQueueInsert.",         "/PDM/Queue/%s/Insert",         pQueue->pszName);
    174     STAMR3RegisterF(pVM, &pQueue->StatFlush,            STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS,        "Calls to pdmR3QueueFlush.",        "/PDM/Queue/%s/Flush",          pQueue->pszName);
    175     STAMR3RegisterF(pVM, &pQueue->StatFlushLeftovers,   STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,   "Left over items after flush.",     "/PDM/Queue/%s/FlushLeftovers", pQueue->pszName);
     193    STAMR3RegisterF(pVM, &pQueue->cbItem,               STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
     194                    "Item size.",                       "/PDM/Queue/%s/cbItem",         pQueue->szName);
     195    STAMR3RegisterF(pVM, &pQueue->cItems,               STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
     196                    "Queue size.",                      "/PDM/Queue/%s/cItems",         pQueue->szName);
     197    STAMR3RegisterF(pVM, &pQueue->rcOkay,               STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
     198                    "Non-zero means queue is busted.",  "/PDM/Queue/%s/rcOkay",         pQueue->szName);
     199    STAMR3RegisterF(pVM, &pQueue->StatAllocFailures,    STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
     200                    "PDMQueueAlloc failures.",          "/PDM/Queue/%s/AllocFailures",  pQueue->szName);
     201    STAMR3RegisterF(pVM, &pQueue->StatInsert,           STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS,
     202                    "Calls to PDMQueueInsert.",         "/PDM/Queue/%s/Insert",         pQueue->szName);
     203    STAMR3RegisterF(pVM, &pQueue->StatFlush,            STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS,
     204                    "Calls to pdmR3QueueFlush.",        "/PDM/Queue/%s/Flush",          pQueue->szName);
     205    STAMR3RegisterF(pVM, &pQueue->StatFlushLeftovers,   STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
     206                    "Left over items after flush.",     "/PDM/Queue/%s/FlushLeftovers", pQueue->szName);
    176207#ifdef VBOX_WITH_STATISTICS
    177     STAMR3RegisterF(pVM, &pQueue->StatFlushPrf,         STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling pdmR3QueueFlush.",     "/PDM/Queue/%s/FlushPrf",       pQueue->pszName);
    178     STAMR3RegisterF(pVM, (void *)&pQueue->cStatPending, STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,        "Pending items.",                   "/PDM/Queue/%s/Pending",        pQueue->pszName);
     208    STAMR3RegisterF(pVM, &pQueue->StatFlushPrf,         STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
     209                    "Profiling pdmR3QueueFlush.",       "/PDM/Queue/%s/FlushPrf",       pQueue->szName);
     210    STAMR3RegisterF(pVM, (void *)&pQueue->cStatPending, STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
     211                    "Pending items.",                   "/PDM/Queue/%s/Pending",        pQueue->szName);
    179212#endif
    180213
    181     *ppQueue = pQueue;
     214    *phQueue = hQueue;
    182215    return VINF_SUCCESS;
    183216}
     
    196229 * @param   pfnCallback         The consumer function.
    197230 * @param   fRZEnabled          Set if the queue must be usable from RC/R0.
    198  * @param   pszName             The queue name. Unique. Not copied.
    199  * @param   ppQueue             Where to store the queue handle on success.
     231 * @param   pszName             The queue name. Unique. Copied.
     232 * @param   phQueue             Where to store the queue handle on success.
    200233 * @thread  Emulation thread only.
    201234 */
    202 VMMR3_INT_DECL(int) PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
    203                                            PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue)
     235VMMR3_INT_DECL(int) PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems,
     236                                           uint32_t cMilliesInterval, PFNPDMQUEUEDEV pfnCallback,
     237                                           bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue)
    204238{
    205239    LogFlow(("PDMR3QueueCreateDevice: pDevIns=%p cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p fRZEnabled=%RTbool pszName=%s\n",
     
    210244     */
    211245    VM_ASSERT_EMT0(pVM);
    212     if (!pfnCallback)
    213     {
    214         AssertMsgFailed(("No consumer callback!\n"));
    215         return VERR_INVALID_PARAMETER;
    216     }
     246    AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
     247    AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
     248
     249    if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_R0_ENABLED))
     250        fRZEnabled = false;
    217251
    218252    /*
    219253     * Create the queue.
    220254     */
    221     PPDMQUEUE pQueue;
    222     int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, fRZEnabled, pszName, &pQueue);
     255    int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, fRZEnabled, pszName,
     256                              PDMQUEUETYPE_DEV, pDevIns, (uintptr_t)pfnCallback, phQueue);
    223257    if (RT_SUCCESS(rc))
    224     {
    225         pQueue->enmType = PDMQUEUETYPE_DEV;
    226         pQueue->u.Dev.pDevIns = pDevIns;
    227         pQueue->u.Dev.pfnCallback = pfnCallback;
    228 
    229         *ppQueue = pQueue;
    230         Log(("PDM: Created device queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pDevIns=%p\n",
    231              pQueue, cbItem, cItems, cMilliesInterval, pfnCallback, pDevIns));
    232     }
     258        Log(("PDM: Created device queue %#RX64; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pDevIns=%p\n",
     259             *phQueue, cbItem, cItems, cMilliesInterval, pfnCallback, pDevIns));
    233260    return rc;
    234261}
     
    246273 *                              If 0 then the emulation thread will be notified whenever an item arrives.
    247274 * @param   pfnCallback         The consumer function.
    248  * @param   pszName             The queue name. Unique. Not copied.
    249  * @param   ppQueue             Where to store the queue handle on success.
     275 * @param   pszName             The queue name. Unique. Copied.
     276 * @param   phQueue             Where to store the queue handle on success.
    250277 * @thread  Emulation thread only.
    251278 */
    252279VMMR3_INT_DECL(int) PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
    253                                            PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
     280                                           PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue)
    254281{
    255282    LogFlow(("PDMR3QueueCreateDriver: pDrvIns=%p cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%s\n",
     
    261288    VM_ASSERT_EMT0(pVM);
    262289    AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
     290    AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
    263291
    264292    /*
    265293     * Create the queue.
    266294     */
    267     PPDMQUEUE pQueue;
    268     int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, false, pszName, &pQueue);
     295    int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, false /*fRZEnabled*/, pszName,
     296                              PDMQUEUETYPE_DRV, pDrvIns, (uintptr_t)pfnCallback, phQueue);
    269297    if (RT_SUCCESS(rc))
    270     {
    271         pQueue->enmType = PDMQUEUETYPE_DRV;
    272         pQueue->u.Drv.pDrvIns = pDrvIns;
    273         pQueue->u.Drv.pfnCallback = pfnCallback;
    274 
    275         *ppQueue = pQueue;
    276         Log(("PDM: Created driver queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pDrvIns=%p\n",
    277              pQueue, cbItem, cItems, cMilliesInterval, pfnCallback, pDrvIns));
    278     }
     298        Log(("PDM: Created driver queue %#RX64; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pDrvIns=%p\n",
     299             *phQueue, cbItem, cItems, cMilliesInterval, pfnCallback, pDrvIns));
    279300    return rc;
    280301}
     
    292313 * @param   pfnCallback         The consumer function.
    293314 * @param   fRZEnabled          Set if the queue must be usable from RC/R0.
    294  * @param   pszName             The queue name. Unique. Not copied.
    295  * @param   ppQueue             Where to store the queue handle on success.
     315 * @param   pszName             The queue name. Unique. Copied.
     316 * @param   phQueue             Where to store the queue handle on success.
    296317 * @thread  Emulation thread only.
    297318 */
    298319VMMR3_INT_DECL(int) PDMR3QueueCreateInternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
    299                                              PFNPDMQUEUEINT pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue)
     320                                             PFNPDMQUEUEINT pfnCallback, bool fRZEnabled,
     321                                             const char *pszName, PDMQUEUEHANDLE *phQueue)
    300322{
    301323    LogFlow(("PDMR3QueueCreateInternal: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p fRZEnabled=%RTbool pszName=%s\n",
     
    311333     * Create the queue.
    312334     */
    313     PPDMQUEUE pQueue;
    314     int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, fRZEnabled, pszName, &pQueue);
     335    int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, fRZEnabled, pszName,
     336                              PDMQUEUETYPE_INTERNAL, pVM, (uintptr_t)pfnCallback, phQueue);
    315337    if (RT_SUCCESS(rc))
    316     {
    317         pQueue->enmType = PDMQUEUETYPE_INTERNAL;
    318         pQueue->u.Int.pfnCallback = pfnCallback;
    319 
    320         *ppQueue = pQueue;
    321338        Log(("PDM: Created internal queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p\n",
    322              pQueue, cbItem, cItems, cMilliesInterval, pfnCallback));
    323     }
     339             *phQueue, cbItem, cItems, cMilliesInterval, pfnCallback));
    324340    return rc;
    325341}
     
    338354 * @param   pvUser              The user argument to the consumer function.
    339355 * @param   pszName             The queue name. Unique. Not copied.
    340  * @param   ppQueue             Where to store the queue handle on success.
     356 * @param   phQueue             Where to store the queue handle on success.
    341357 * @thread  Emulation thread only.
    342358 */
    343 VMMR3_INT_DECL(int) PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
    344                                              PFNPDMQUEUEEXT pfnCallback, void *pvUser, const char *pszName, PPDMQUEUE *ppQueue)
    345 {
    346     LogFlow(("PDMR3QueueCreateExternal: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%s\n", cbItem, cItems, cMilliesInterval, pfnCallback, pszName));
     359VMMR3DECL(int) PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
     360                                        PFNPDMQUEUEEXT pfnCallback, void *pvUser,
     361                                        const char *pszName, PDMQUEUEHANDLE *phQueue)
     362{
     363    LogFlow(("PDMR3QueueCreateExternal: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%s\n",
     364             cbItem, cItems, cMilliesInterval, pfnCallback, pszName));
    347365
    348366    /*
     
    355373     * Create the queue.
    356374     */
     375    int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, false /*fRZEnabled*/, pszName,
     376                              PDMQUEUETYPE_EXTERNAL, pvUser, (uintptr_t)pfnCallback, phQueue);
     377    if (RT_SUCCESS(rc))
     378        Log(("PDM: Created external queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pvUser=%p\n",
     379             *phQueue, cbItem, cItems, cMilliesInterval, pfnCallback, pvUser));
     380    return rc;
     381}
     382
     383
     384/**
     385 * Destroy a queue.
     386 *
     387 * @returns VBox status code.
     388 * @param   pVM         Pointer to the cross context VM structure.
     389 * @param   hQueue      Handle to the queue that should be destroyed.
     390 * @param   pvOwner     The owner address.
     391 * @thread  EMT(0)
     392 * @note    Externally visible mainly for testing purposes.
     393 */
     394VMMR3DECL(int) PDMR3QueueDestroy(PVM pVM, PDMQUEUEHANDLE hQueue, void *pvOwner)
     395{
     396    LogFlow(("PDMR3QueueDestroy: hQueue=%p pvOwner=%p\n", hQueue, pvOwner));
     397
     398    /*
     399     * Validate input.
     400     */
     401    VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); /* serialization */
     402    if (hQueue == NIL_PDMQUEUEHANDLE)
     403        return VINF_SUCCESS;
     404
    357405    PPDMQUEUE pQueue;
    358     int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, false, pszName, &pQueue);
    359     if (RT_SUCCESS(rc))
    360     {
    361         pQueue->enmType = PDMQUEUETYPE_EXTERNAL;
    362         pQueue->u.Ext.pvUser = pvUser;
    363         pQueue->u.Ext.pfnCallback = pfnCallback;
    364 
    365         *ppQueue = pQueue;
    366         Log(("PDM: Created external queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pvUser=%p\n",
    367              pQueue, cbItem, cItems, cMilliesInterval, pfnCallback, pvUser));
    368     }
    369     return rc;
    370 }
    371 
    372 
    373 /**
    374  * Destroy a queue.
    375  *
    376  * @returns VBox status code.
    377  * @param   pQueue      Queue to destroy.
    378  * @thread  Emulation thread only.
    379  */
    380 VMMR3_INT_DECL(int) PDMR3QueueDestroy(PPDMQUEUE pQueue)
    381 {
    382     LogFlow(("PDMR3QueueDestroy: pQueue=%p\n", pQueue));
    383 
    384     /*
    385      * Validate input.
    386      */
    387     if (!pQueue)
    388         return VERR_INVALID_PARAMETER;
    389     Assert(pQueue && pQueue->pVMR3);
    390     PVM     pVM  = pQueue->pVMR3;
    391     PUVM    pUVM = pVM->pUVM;
    392 
    393     pdmLock(pVM);
    394 
    395     /*
    396      * Unlink it.
    397      */
    398     if (pQueue->hTimer != NIL_TMTIMERHANDLE)
    399     {
    400         if (pUVM->pdm.s.pQueuesTimer != pQueue)
    401         {
    402             PPDMQUEUE pCur = pUVM->pdm.s.pQueuesTimer;
    403             while (pCur)
    404             {
    405                 if (pCur->pNext == pQueue)
    406                 {
    407                     pCur->pNext = pQueue->pNext;
    408                     break;
    409                 }
    410                 pCur = pCur->pNext;
    411             }
    412             AssertMsg(pCur, ("Didn't find the queue!\n"));
     406    bool      fRZEnabled = false;
     407    if (hQueue < RT_ELEMENTS(pVM->pdm.s.apRing0Queues))
     408    {
     409        AssertReturn(hQueue < pVM->pdm.s.cRing0Queues, VERR_INVALID_HANDLE);
     410        pQueue = pVM->pdm.s.apRing0Queues[hQueue];
     411        AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
     412        AssertReturn(pQueue->u32Magic == PDMQUEUE_MAGIC, VERR_INVALID_HANDLE);
     413        AssertReturn(pQueue->u.Gen.pvOwner == pvOwner, VERR_INVALID_HANDLE);
     414
     415        /* Lazy bird: Cannot dynamically delete ring-0 capable queues. */
     416        AssertFailedReturn(VERR_NOT_SUPPORTED);
     417    }
     418    else
     419    {
     420        hQueue -= RT_ELEMENTS(pVM->pdm.s.apRing0Queues);
     421        AssertReturn(hQueue < pVM->pdm.s.cRing3Queues, VERR_INVALID_HANDLE);
     422        pQueue = pVM->pdm.s.papRing3Queues[hQueue];
     423        AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
     424        AssertReturn(pQueue->u32Magic == PDMQUEUE_MAGIC, VERR_INVALID_HANDLE);
     425        AssertReturn(pQueue->u.Gen.pvOwner == pvOwner, VERR_INVALID_HANDLE);
     426
     427        /* Enter the lock here to serialize with other EMTs traversing the handles. */
     428        pdmLock(pVM);
     429        pVM->pdm.s.papRing3Queues[hQueue] = NULL;
     430        if (hQueue + 1 == pVM->pdm.s.cRing3Queues)
     431        {
     432            while (hQueue > 0 && pVM->pdm.s.papRing3Queues[hQueue - 1] == NULL)
     433                hQueue--;
     434            pVM->pdm.s.cRing3Queues = hQueue;
    413435        }
    414         else
    415             pUVM->pdm.s.pQueuesTimer = pQueue->pNext;
    416     }
    417     else
    418     {
    419         if (pUVM->pdm.s.pQueuesForced != pQueue)
    420         {
    421             PPDMQUEUE pCur = pUVM->pdm.s.pQueuesForced;
    422             while (pCur)
    423             {
    424                 if (pCur->pNext == pQueue)
    425                 {
    426                     pCur->pNext = pQueue->pNext;
    427                     break;
    428                 }
    429                 pCur = pCur->pNext;
    430             }
    431             AssertMsg(pCur, ("Didn't find the queue!\n"));
    432         }
    433         else
    434             pUVM->pdm.s.pQueuesForced = pQueue->pNext;
    435     }
    436     pQueue->pNext = NULL;
    437     pQueue->pVMR3 = NULL;
    438     pdmUnlock(pVM);
     436        pQueue->u32Magic = PDMQUEUE_MAGIC_DEAD;
     437        pdmUnlock(pVM);
     438    }
    439439
    440440    /*
    441441     * Deregister statistics.
    442442     */
    443     STAMR3DeregisterF(pVM->pUVM, "/PDM/Queue/%s/cbItem", pQueue->pszName);
     443    STAMR3DeregisterF(pVM->pUVM, "/PDM/Queue/%s/*", pQueue->szName);
    444444
    445445    /*
     
    451451        pQueue->hTimer = NIL_TMTIMERHANDLE;
    452452    }
    453     if (pQueue->pVMR0)
    454     {
    455         pQueue->pVMR0 = NIL_RTR0PTR;
    456         MMHyperFree(pVM, pQueue);
    457     }
    458     else
    459         MMR3HeapFree(pQueue);
     453    if (!fRZEnabled)
     454        RTMemPageFree(pQueue, pQueue->offItems + pQueue->cbItem * pQueue->cItems);
     455
     456    return VINF_SUCCESS;
     457}
     458
     459
     460/**
     461 * Destroy a all queues with a given owner.
     462 *
     463 * @returns VBox status code.
     464 * @param   pVM         The cross context VM structure.
     465 * @param   pvOwner     The owner pointer.
     466 * @param   enmType     Owner type.
     467 * @thread  EMT(0)
     468 */
     469static int pdmR3QueueDestroyByOwner(PVM pVM, void *pvOwner, PDMQUEUETYPE enmType)
     470{
     471    LogFlow(("pdmR3QueueDestroyByOwner: pvOwner=%p enmType=%d\n", pvOwner, enmType));
     472
     473    /*
     474     * Validate input.
     475     */
     476    AssertPtrReturn(pvOwner, VERR_INVALID_PARAMETER);
     477    AssertReturn(pvOwner != pVM, VERR_INVALID_PARAMETER);
     478    VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); /* serialization */
     479
     480    /*
     481     * Scan and destroy.
     482     */
     483    uint32_t i = pVM->pdm.s.cRing0Queues;
     484    while (i-- > 0)
     485    {
     486        PPDMQUEUE pQueue = pVM->pdm.s.apRing0Queues[i];
     487        if (   pQueue
     488            && pQueue->u.Gen.pvOwner == pvOwner
     489            && pQueue->enmType == enmType)
     490        {
     491            /* Not supported at runtime. */
     492            VM_ASSERT_STATE_RETURN(pVM, VMSTATE_DESTROYING, VERR_WRONG_ORDER);
     493        }
     494    }
     495
     496    i = pVM->pdm.s.cRing3Queues;
     497    while (i-- > 0)
     498    {
     499        PPDMQUEUE pQueue = pVM->pdm.s.papRing3Queues[i];
     500        if (   pQueue
     501            && pQueue->u.Gen.pvOwner == pvOwner
     502            && pQueue->enmType       == enmType)
     503            PDMR3QueueDestroy(pVM, i + RT_ELEMENTS(pVM->pdm.s.apRing0Queues), pvOwner);
     504    }
    460505
    461506    return VINF_SUCCESS;
     
    469514 * @param   pVM         The cross context VM structure.
    470515 * @param   pDevIns     Device instance.
    471  * @thread  Emulation thread only.
     516 * @thread  EMT(0)
    472517 */
    473518VMMR3_INT_DECL(int) PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns)
    474519{
    475520    LogFlow(("PDMR3QueueDestroyDevice: pDevIns=%p\n", pDevIns));
    476 
    477     /*
    478      * Validate input.
    479      */
    480     if (!pDevIns)
    481         return VERR_INVALID_PARAMETER;
    482 
    483     PUVM pUVM = pVM->pUVM;
    484     pdmLock(pVM);
    485 
    486     /*
    487      * Unlink it.
    488      */
    489     PPDMQUEUE pQueueNext = pUVM->pdm.s.pQueuesTimer;
    490     PPDMQUEUE pQueue     = pUVM->pdm.s.pQueuesForced;
    491     do
    492     {
    493         while (pQueue)
    494         {
    495             if (    pQueue->enmType == PDMQUEUETYPE_DEV
    496                 &&  pQueue->u.Dev.pDevIns == pDevIns)
    497             {
    498                 PPDMQUEUE pQueueDestroy = pQueue;
    499                 pQueue = pQueue->pNext;
    500                 int rc = PDMR3QueueDestroy(pQueueDestroy);
    501                 AssertRC(rc);
    502             }
    503             else
    504                 pQueue = pQueue->pNext;
    505         }
    506 
    507         /* next queue list */
    508         pQueue = pQueueNext;
    509         pQueueNext = NULL;
    510     } while (pQueue);
    511 
    512     pdmUnlock(pVM);
    513     return VINF_SUCCESS;
     521    return pdmR3QueueDestroyByOwner(pVM, pDevIns, PDMQUEUETYPE_DEV);
    514522}
    515523
     
    521529 * @param   pVM         The cross context VM structure.
    522530 * @param   pDrvIns     Driver instance.
    523  * @thread  Emulation thread only.
     531 * @thread  EMT(0)
    524532 */
    525533VMMR3_INT_DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns)
    526534{
    527535    LogFlow(("PDMR3QueueDestroyDriver: pDrvIns=%p\n", pDrvIns));
    528 
    529     /*
    530      * Validate input.
    531      */
    532     if (!pDrvIns)
    533         return VERR_INVALID_PARAMETER;
    534 
    535     PUVM pUVM = pVM->pUVM;
    536     pdmLock(pVM);
    537 
    538     /*
    539      * Unlink it.
    540      */
    541     PPDMQUEUE pQueueNext = pUVM->pdm.s.pQueuesTimer;
    542     PPDMQUEUE pQueue     = pUVM->pdm.s.pQueuesForced;
    543     do
    544     {
    545         while (pQueue)
    546         {
    547             if (    pQueue->enmType == PDMQUEUETYPE_DRV
    548                 &&  pQueue->u.Drv.pDrvIns == pDrvIns)
     536    return pdmR3QueueDestroyByOwner(pVM, pDrvIns, PDMQUEUETYPE_DRV);
     537}
     538
     539
     540/**
     541 * Free an item.
     542 *
     543 * @param   pQueue  The queue.
     544 * @param   pItem   The item.
     545 */
     546DECLINLINE(void) pdmR3QueueFreeItem(PPDMQUEUE pQueue, uint8_t *pbItems, uint32_t cbItem, PPDMQUEUEITEMCORE pItem)
     547{
     548    pItem->u64View = UINT64_C(0xfeedfeedfeedfeed);
     549
     550    uintptr_t const offItem = (uintptr_t)pItem - (uintptr_t)pbItems;
     551    uintptr_t const iItem   = offItem / cbItem;
     552    Assert(!(offItem % cbItem));
     553    Assert(iItem < pQueue->cItems);
     554    AssertReturnVoidStmt(ASMAtomicBitTestAndSet(pQueue->bmAlloc, iItem) == false, pQueue->rcOkay = VERR_INTERNAL_ERROR_4);
     555    STAM_STATS({ ASMAtomicDecU32(&pQueue->cStatPending); });
     556}
     557
     558
     559
     560/**
     561 * Process pending items in one queue.
     562 *
     563 * @returns VBox status code.
     564 * @param   pVM     The cross context VM structure.
     565 * @param   pQueue  The queue needing flushing.
     566 */
     567static int pdmR3QueueFlush(PVM pVM, PPDMQUEUE pQueue)
     568{
     569    STAM_PROFILE_START(&pQueue->StatFlushPrf,p);
     570
     571    uint32_t const  cbItem  = pQueue->cbItem;
     572    uint32_t const  cItems  = pQueue->cItems;
     573    uint8_t * const pbItems = (uint8_t *)pQueue + pQueue->offItems;
     574
     575    /*
     576     * Get the list and reverse it into a pointer list (inserted in LIFO order to avoid locking).
     577     */
     578    uint32_t          cPending = 0;
     579    PPDMQUEUEITEMCORE pHead    = NULL;
     580    {
     581        uint32_t iCur = ASMAtomicXchgU32(&pQueue->iPending, UINT32_MAX);
     582        do
     583        {
     584            AssertMsgReturn(iCur < cItems, ("%#x vs %#x\n", iCur, cItems), pQueue->rcOkay = VERR_INTERNAL_ERROR_5);
     585            AssertReturn(ASMBitTest(pQueue->bmAlloc, iCur) == false, pQueue->rcOkay = VERR_INTERNAL_ERROR_3);
     586            PPDMQUEUEITEMCORE pCur = (PPDMQUEUEITEMCORE)&pbItems[iCur * cbItem];
     587
     588            iCur = pCur->iNext;
     589            ASMCompilerBarrier(); /* paranoia */
     590            pCur->pNext = pHead;
     591            pHead = pCur;
     592            cPending++;
     593        } while (iCur != UINT32_MAX);
     594    }
     595    RT_NOREF(cPending);
     596
     597    /*
     598     * Feed the items to the consumer function.
     599     */
     600    Log2(("pdmR3QueueFlush: pQueue=%p enmType=%d pHead=%p cItems=%u\n", pQueue, pQueue->enmType, pHead, cPending));
     601    switch (pQueue->enmType)
     602    {
     603        case PDMQUEUETYPE_DEV:
     604            while (pHead)
    549605            {
    550                 PPDMQUEUE pQueueDestroy = pQueue;
    551                 pQueue = pQueue->pNext;
    552                 int rc = PDMR3QueueDestroy(pQueueDestroy);
    553                 AssertRC(rc);
     606                if (!pQueue->u.Dev.pfnCallback(pQueue->u.Dev.pDevIns, pHead))
     607                    break;
     608                PPDMQUEUEITEMCORE pFree = pHead;
     609                pHead = pHead->pNext;
     610                ASMCompilerBarrier(); /* paranoia */
     611                pdmR3QueueFreeItem(pQueue, pbItems, cbItem, pFree);
    554612            }
    555             else
    556                 pQueue = pQueue->pNext;
     613            break;
     614
     615        case PDMQUEUETYPE_DRV:
     616            while (pHead)
     617            {
     618                if (!pQueue->u.Drv.pfnCallback(pQueue->u.Drv.pDrvIns, pHead))
     619                    break;
     620                PPDMQUEUEITEMCORE pFree = pHead;
     621                pHead = pHead->pNext;
     622                ASMCompilerBarrier(); /* paranoia */
     623                pdmR3QueueFreeItem(pQueue, pbItems, cbItem, pFree);
     624            }
     625            break;
     626
     627        case PDMQUEUETYPE_INTERNAL:
     628            while (pHead)
     629            {
     630                if (!pQueue->u.Int.pfnCallback(pVM, pHead))
     631                    break;
     632                PPDMQUEUEITEMCORE pFree = pHead;
     633                pHead = pHead->pNext;
     634                ASMCompilerBarrier(); /* paranoia */
     635                pdmR3QueueFreeItem(pQueue, pbItems, cbItem, pFree);
     636            }
     637            break;
     638
     639        case PDMQUEUETYPE_EXTERNAL:
     640            while (pHead)
     641            {
     642                if (!pQueue->u.Ext.pfnCallback(pQueue->u.Ext.pvUser, pHead))
     643                    break;
     644                PPDMQUEUEITEMCORE pFree = pHead;
     645                pHead = pHead->pNext;
     646                ASMCompilerBarrier(); /* paranoia */
     647                pdmR3QueueFreeItem(pQueue, pbItems, cbItem, pFree);
     648            }
     649            break;
     650
     651        default:
     652            AssertMsgFailed(("Invalid queue type %d\n", pQueue->enmType));
     653            break;
     654    }
     655
     656    /*
     657     * Success?
     658     */
     659    if (!pHead)
     660    { /* likely */ }
     661    else
     662    {
     663        /*
     664         * Reverse the list and turn it back into index chain.
     665         */
     666        uint32_t iPendingHead = UINT32_MAX;
     667        do
     668        {
     669            PPDMQUEUEITEMCORE pInsert = pHead;
     670            pHead = pHead->pNext;
     671            ASMCompilerBarrier(); /* paranoia */
     672            pInsert->iNext = iPendingHead;
     673            iPendingHead = ((uintptr_t)pInsert - (uintptr_t)pbItems) / cbItem;
     674        } while (pHead);
     675
     676        /*
     677         * Insert the list at the tail of the pending list.  If someone races
     678         * us there, we have to join the new LIFO with the old.
     679         */
     680        for (;;)
     681        {
     682            if (ASMAtomicCmpXchgU32(&pQueue->iPending, iPendingHead, UINT32_MAX))
     683                break;
     684
     685            uint32_t const iNewPending = ASMAtomicXchgU32(&pQueue->iPending, UINT32_MAX);
     686            if (iNewPending != UINT32_MAX)
     687            {
     688                /* Find the last entry and chain iPendingHead onto it. */
     689                uint32_t iCur = iNewPending;
     690                for (;;)
     691                {
     692                    AssertReturn(iCur < cItems, pQueue->rcOkay = VERR_INTERNAL_ERROR_2);
     693                    AssertReturn(ASMBitTest(pQueue->bmAlloc, iCur) == false, pQueue->rcOkay = VERR_INTERNAL_ERROR_3);
     694                    PPDMQUEUEITEMCORE pCur = (PPDMQUEUEITEMCORE)&pbItems[iCur * cbItem];
     695                    iCur = pCur->iNext;
     696                    if (iCur == UINT32_MAX)
     697                    {
     698                        pCur->iNext = iPendingHead;
     699                        break;
     700                    }
     701                }
     702
     703                iPendingHead = iNewPending;
     704            }
    557705        }
    558706
    559         /* next queue list */
    560         pQueue = pQueueNext;
    561         pQueueNext = NULL;
    562     } while (pQueue);
    563 
    564     pdmUnlock(pVM);
     707        STAM_REL_COUNTER_INC(&pQueue->StatFlushLeftovers);
     708    }
     709
     710    STAM_PROFILE_STOP(&pQueue->StatFlushPrf,p);
    565711    return VINF_SUCCESS;
    566712}
     
    573719 * @param   pVM     The cross context VM structure.
    574720 * @thread  Emulation thread only.
    575  */
    576 VMMR3_INT_DECL(void) PDMR3QueueFlushAll(PVM pVM)
     721 * @note    Internal, but exported for use in the testcase.
     722 */
     723VMMR3DECL(void) PDMR3QueueFlushAll(PVM pVM)
    577724{
    578725    VM_ASSERT_EMT(pVM);
     
    593740        ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT);
    594741
    595         for (PPDMQUEUE pCur = pVM->pUVM->pdm.s.pQueuesForced; pCur; pCur = pCur->pNext)
    596             if (    pCur->pPendingR3
    597                 ||  pCur->pPendingR0)
    598                 pdmR3QueueFlush(pCur);
     742        /* Scan the ring-0 queues: */
     743        size_t i = pVM->pdm.s.cRing0Queues;
     744        while (i-- > 0)
     745        {
     746            PPDMQUEUE pQueue = pVM->pdm.s.apRing0Queues[i];
     747            if (   pQueue
     748                && pQueue->iPending != UINT32_MAX
     749                && pQueue->hTimer == NIL_TMTIMERHANDLE
     750                && pQueue->rcOkay == VINF_SUCCESS)
     751                pdmR3QueueFlush(pVM, pQueue);
     752        }
     753
     754        /* Scan the ring-3 queues: */
     755/** @todo Deal with destroy concurrency issues. */
     756        i = pVM->pdm.s.cRing3Queues;
     757        while (i-- > 0)
     758        {
     759            PPDMQUEUE pQueue = pVM->pdm.s.papRing3Queues[i];
     760            if (   pQueue
     761                && pQueue->iPending != UINT32_MAX
     762                && pQueue->hTimer == NIL_TMTIMERHANDLE
     763                && pQueue->rcOkay == VINF_SUCCESS)
     764                pdmR3QueueFlush(pVM, pQueue);
     765        }
    599766
    600767        ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_ACTIVE_BIT);
     
    609776
    610777
    611 /**
    612  * Process pending items in one queue.
    613  *
    614  * @returns Success indicator.
    615  *          If false the item the consumer said "enough!".
    616  * @param   pQueue  The queue.
    617  */
    618 static bool pdmR3QueueFlush(PPDMQUEUE pQueue)
    619 {
    620     STAM_PROFILE_START(&pQueue->StatFlushPrf,p);
    621 
    622     /*
    623      * Get the lists.
    624      */
    625     PPDMQUEUEITEMCORE pItems   = ASMAtomicXchgPtrT(&pQueue->pPendingR3, NULL, PPDMQUEUEITEMCORE);
    626     RTR0PTR           pItemsR0 = ASMAtomicXchgR0Ptr(&pQueue->pPendingR0, NIL_RTR0PTR);
    627 
    628     AssertMsgReturn(   pItemsR0
    629                     || pItems,
    630                     ("Someone is racing us? This shouldn't happen!\n"),
    631                     true);
    632 
    633     /*
    634      * Reverse the list (it's inserted in LIFO order to avoid semaphores, remember).
    635      */
    636     PPDMQUEUEITEMCORE pCur = pItems;
    637     pItems = NULL;
    638     while (pCur)
    639     {
    640         PPDMQUEUEITEMCORE pInsert = pCur;
    641         pCur = pCur->pNextR3;
    642         pInsert->pNextR3 = pItems;
    643         pItems = pInsert;
    644     }
    645 
    646     /*
    647      * Do the same for any pending R0 items.
    648      */
    649     while (pItemsR0)
    650     {
    651         PPDMQUEUEITEMCORE pInsert = (PPDMQUEUEITEMCORE)MMHyperR0ToR3(pQueue->pVMR3, pItemsR0);
    652         pItemsR0 = pInsert->pNextR0;
    653         pInsert->pNextR0 = NIL_RTR0PTR;
    654         pInsert->pNextR3 = pItems;
    655         pItems = pInsert;
    656     }
    657 
    658     /*
    659      * Feed the items to the consumer function.
    660      */
    661     Log2(("pdmR3QueueFlush: pQueue=%p enmType=%d pItems=%p\n", pQueue, pQueue->enmType, pItems));
    662     switch (pQueue->enmType)
    663     {
    664         case PDMQUEUETYPE_DEV:
    665             while (pItems)
    666             {
    667                 if (!pQueue->u.Dev.pfnCallback(pQueue->u.Dev.pDevIns, pItems))
    668                     break;
    669                 pCur = pItems;
    670                 pItems = pItems->pNextR3;
    671                 pdmR3QueueFreeItem(pQueue, pCur);
    672             }
    673             break;
    674 
    675         case PDMQUEUETYPE_DRV:
    676             while (pItems)
    677             {
    678                 if (!pQueue->u.Drv.pfnCallback(pQueue->u.Drv.pDrvIns, pItems))
    679                     break;
    680                 pCur = pItems;
    681                 pItems = pItems->pNextR3;
    682                 pdmR3QueueFreeItem(pQueue, pCur);
    683             }
    684             break;
    685 
    686         case PDMQUEUETYPE_INTERNAL:
    687             while (pItems)
    688             {
    689                 if (!pQueue->u.Int.pfnCallback(pQueue->pVMR3, pItems))
    690                     break;
    691                 pCur = pItems;
    692                 pItems = pItems->pNextR3;
    693                 pdmR3QueueFreeItem(pQueue, pCur);
    694             }
    695             break;
    696 
    697         case PDMQUEUETYPE_EXTERNAL:
    698             while (pItems)
    699             {
    700                 if (!pQueue->u.Ext.pfnCallback(pQueue->u.Ext.pvUser, pItems))
    701                     break;
    702                 pCur = pItems;
    703                 pItems = pItems->pNextR3;
    704                 pdmR3QueueFreeItem(pQueue, pCur);
    705             }
    706             break;
    707 
    708         default:
    709             AssertMsgFailed(("Invalid queue type %d\n", pQueue->enmType));
    710             break;
    711     }
    712 
    713     /*
    714      * Success?
    715      */
    716     if (pItems)
    717     {
    718         /*
    719          * Reverse the list.
    720          */
    721         pCur = pItems;
    722         pItems = NULL;
    723         while (pCur)
    724         {
    725             PPDMQUEUEITEMCORE pInsert = pCur;
    726             pCur = pInsert->pNextR3;
    727             pInsert->pNextR3 = pItems;
    728             pItems = pInsert;
    729         }
    730 
    731         /*
    732          * Insert the list at the tail of the pending list.
    733          */
    734         for (;;)
    735         {
    736             if (ASMAtomicCmpXchgPtr(&pQueue->pPendingR3, pItems, NULL))
    737                 break;
    738             PPDMQUEUEITEMCORE pPending = ASMAtomicXchgPtrT(&pQueue->pPendingR3, NULL, PPDMQUEUEITEMCORE);
    739             if (pPending)
    740             {
    741                 pCur = pPending;
    742                 while (pCur->pNextR3)
    743                     pCur = pCur->pNextR3;
    744                 pCur->pNextR3 = pItems;
    745                 pItems = pPending;
    746             }
    747         }
    748 
    749         STAM_REL_COUNTER_INC(&pQueue->StatFlushLeftovers);
    750         STAM_PROFILE_STOP(&pQueue->StatFlushPrf,p);
    751         return false;
    752     }
    753 
    754     STAM_PROFILE_STOP(&pQueue->StatFlushPrf,p);
    755     return true;
    756 }
    757 
    758 
    759 /**
    760  * Free an item.
    761  *
    762  * @param   pQueue  The queue.
    763  * @param   pItem   The item.
    764  */
    765 DECLINLINE(void) pdmR3QueueFreeItem(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem)
    766 {
    767     VM_ASSERT_EMT(pQueue->pVMR3);
    768 
    769     int i = pQueue->iFreeHead;
    770     int iNext = (i + 1) % (pQueue->cItems + PDMQUEUE_FREE_SLACK);
    771 
    772     pQueue->aFreeItems[i].pItemR3 = pItem;
    773     if (pQueue->pVMR0)
    774         pQueue->aFreeItems[i].pItemR0 = MMHyperR3ToR0(pQueue->pVMR3, pItem);
    775 
    776     if (!ASMAtomicCmpXchgU32(&pQueue->iFreeHead, iNext, i))
    777         AssertMsgFailed(("huh? i=%d iNext=%d iFreeHead=%d iFreeTail=%d\n", i, iNext, pQueue->iFreeHead, pQueue->iFreeTail));
    778     STAM_STATS({ ASMAtomicDecU32(&pQueue->cStatPending); });
    779 }
    780 
    781778
    782779/**
     
    788785    Assert(hTimer == pQueue->hTimer);
    789786
    790     if (   pQueue->pPendingR3
    791         || pQueue->pPendingR0)
    792         pdmR3QueueFlush(pQueue);
     787    if (pQueue->iPending != UINT32_MAX)
     788        pdmR3QueueFlush(pVM, pQueue);
     789
    793790    int rc = TMTimerSetMillies(pVM, hTimer, pQueue->cMilliesInterval);
    794791    AssertRC(rc);
  • trunk/src/VBox/VMM/include/PDMInternal.h

    r93554 r93609  
    985985
    986986
    987 /** Extra space in the free array. */
    988 #define PDMQUEUE_FREE_SLACK         16
     987/** Max number of items in a queue. */
     988#define PDMQUEUE_MAX_ITEMS          _16K
     989/** Max item size. */
     990#define PDMQUEUE_MAX_ITEM_SIZE      _1M
     991/** Max total queue item size for ring-0 capable queues.  */
     992#define PDMQUEUE_MAX_TOTAL_SIZE_R0  _8M
     993/** Max total queue item size for ring-3 only queues. */
     994#define PDMQUEUE_MAX_TOTAL_SIZE_R3  _32M
    989995
    990996/**
     
    10031009} PDMQUEUETYPE;
    10041010
    1005 /** Pointer to a PDM Queue. */
    1006 typedef struct PDMQUEUE *PPDMQUEUE;
    1007 
    10081011/**
    10091012 * PDM Queue.
     
    10111014typedef struct PDMQUEUE
    10121015{
    1013     /** Pointer to the next queue in the list. */
    1014     R3PTRTYPE(PPDMQUEUE)            pNext;
     1016    /** Magic value (PDMQUEUE_MAGIC). */
     1017    uint32_t                u32Magic;
     1018    /** Item size (bytes). */
     1019    uint32_t                cbItem;
     1020    /** Number of items in the queue. */
     1021    uint32_t                cItems;
     1022    /** Offset of the the queue items relative to the PDMQUEUE structure. */
     1023    uint32_t                offItems;
     1024
     1025    /** Interval timer. Only used if cMilliesInterval is non-zero. */
     1026    TMTIMERHANDLE           hTimer;
     1027    /** The interval between checking the queue for events.
     1028     * The realtime timer below is used to do the waiting.
     1029     * If 0, the queue will use the VM_FF_PDM_QUEUE forced action. */
     1030    uint32_t                cMilliesInterval;
     1031
     1032    /** This is VINF_SUCCESS if the queue is okay, error status if not. */
     1033    int32_t                 rcOkay;
     1034    uint32_t                u32Padding;
     1035
     1036    /** Queue type. */
     1037    PDMQUEUETYPE            enmType;
    10151038    /** Type specific data. */
    10161039    union
     
    10461069            R3PTRTYPE(void *)           pvUser;
    10471070        } Ext;
     1071        struct
     1072        {
     1073            /** Generic callback pointer. */
     1074            RTR3PTR                     pfnCallback;
     1075            /** Generic owner pointer. */
     1076            RTR3PTR                     pvOwner;
     1077        } Gen;
    10481078    } u;
    1049     /** Queue type. */
    1050     PDMQUEUETYPE                    enmType;
    1051     /** The interval between checking the queue for events.
    1052      * The realtime timer below is used to do the waiting.
    1053      * If 0, the queue will use the VM_FF_PDM_QUEUE forced action. */
    1054     uint32_t                        cMilliesInterval;
    1055     /** Interval timer. Only used if cMilliesInterval is non-zero. */
    1056     TMTIMERHANDLE                   hTimer;
    1057     /** Pointer to the VM - R3. */
    1058     PVMR3                           pVMR3;
    1059     /** LIFO of pending items - R3. */
    1060     R3PTRTYPE(PPDMQUEUEITEMCORE) volatile pPendingR3;
    1061     /** Pointer to the VM - R0. */
    1062     PVMR0                           pVMR0;
    1063     /** LIFO of pending items - R0. */
    1064     R0PTRTYPE(PPDMQUEUEITEMCORE) volatile pPendingR0;
    1065 
    1066     /** Item size (bytes). */
    1067     uint32_t                        cbItem;
    1068     /** Number of items in the queue. */
    1069     uint32_t                        cItems;
    1070     /** Index to the free head (where we insert). */
    1071     uint32_t volatile               iFreeHead;
    1072     /** Index to the free tail (where we remove). */
    1073     uint32_t volatile               iFreeTail;
    10741079
    10751080    /** Unique queue name. */
    1076     R3PTRTYPE(const char *)         pszName;
    1077 #if HC_ARCH_BITS == 32
    1078     RTR3PTR                         Alignment1;
    1079 #endif
     1081    char                            szName[40];
     1082
     1083    /** LIFO of pending items (item index), UINT32_MAX if empty. */
     1084    uint32_t volatile               iPending;
     1085
     1086    /** State: Pending items. */
     1087    uint32_t volatile               cStatPending;
    10801088    /** Stat: Times PDMQueueAlloc fails. */
    10811089    STAMCOUNTER                     StatAllocFailures;
     
    10861094    /** Stat: Queue flushes with pending items left over. */
    10871095    STAMCOUNTER                     StatFlushLeftovers;
    1088 #ifdef VBOX_WITH_STATISTICS
    10891096    /** State: Profiling the flushing. */
    10901097    STAMPROFILE                     StatFlushPrf;
    1091     /** State: Pending items. */
    1092     uint32_t volatile               cStatPending;
    1093     uint32_t volatile               cAlignment;
    1094 #endif
    1095 
    1096     /** Array of pointers to free items. Variable size. */
    1097     struct PDMQUEUEFREEITEM
    1098     {
    1099         /** Pointer to the free item - HC Ptr. */
    1100         R3PTRTYPE(PPDMQUEUEITEMCORE) volatile   pItemR3;
    1101         /** Pointer to the free item - HC Ptr. */
    1102         R0PTRTYPE(PPDMQUEUEITEMCORE) volatile   pItemR0;
    1103     }                               aFreeItems[1];
     1098    uint64_t                        au64Padding[3];
     1099
     1100    /** Allocation bitmap: Set bits means free, clear means allocated. */
     1101    RT_FLEXIBLE_ARRAY_EXTENSION
     1102    uint64_t                        bmAlloc[RT_FLEXIBLE_ARRAY];
     1103    /* The items follows after the end of the bitmap */
    11041104} PDMQUEUE;
     1105AssertCompileMemberAlignment(PDMQUEUE, bmAlloc, 64);
     1106/** Pointer to a PDM Queue. */
     1107typedef struct PDMQUEUE *PPDMQUEUE;
     1108
     1109/** Magic value PDMQUEUE::u32Magic (Bud Powell). */
     1110#define PDMQUEUE_MAGIC              UINT32_C(0x19240927)
     1111/** Magic value PDMQUEUE::u32Magic after destroy. */
     1112#define PDMQUEUE_MAGIC_DEAD         UINT32_C(0x19660731)
    11051113
    11061114/** @name PDM::fQueueFlushing
     
    11151123#define PDM_QUEUE_FLUSH_FLAG_PENDING_BIT    1
    11161124/** @}  */
     1125
     1126/**
     1127 * Ring-0 queue
     1128 *
     1129 * @author bird (2022-02-04)
     1130 */
     1131typedef struct PDMQUEUER0
     1132{
     1133    /** Pointer to the shared queue data. */
     1134    R0PTRTYPE(PPDMQUEUE)    pQueue;
     1135    /** The memory allocation. */
     1136    RTR0MEMOBJ              hMemObj;
     1137    /** The ring-3 mapping object. */
     1138    RTR0MEMOBJ              hMapObj;
     1139    /** The owner pointer.  This is NULL if not allocated. */
     1140    RTR0PTR                 pvOwner;
     1141    /** Queue item size. */
     1142    uint32_t                cbItem;
     1143    /** Number of queue items. */
     1144    uint32_t                cItems;
     1145    /** Offset of the the queue items relative to the PDMQUEUE structure. */
     1146    uint32_t                offItems;
     1147    uint32_t                u32Reserved;
     1148} PDMQUEUER0;
    11171149
    11181150
     
    11871219AssertCompileMemberAlignment(PDMTASKSET, fTriggered, 64);
    11881220AssertCompileMemberAlignment(PDMTASKSET, aTasks, 64);
    1189 /** Magic value for PDMTASKSET::u32Magic. */
    1190 #define PDMTASKSET_MAGIC        UINT32_C(0x19320314)
     1221/** Magic value for PDMTASKSET::u32Magic (Quincy Delight Jones Jr.). */
     1222#define PDMTASKSET_MAGIC        UINT32_C(0x19330314)
    11911223/** Pointer to a task set. */
    11921224typedef PDMTASKSET *PPDMTASKSET;
     
    12531285        struct PDMDEVHLPTASKPCISETIRQ
    12541286        {
    1255             /** Pointer to the PCI device (R3 Ptr). */
    1256             R3PTRTYPE(PPDMPCIDEV)   pPciDevR3;
     1287            /** Index of the PCI device (into PDMDEVINSR3::apPciDevs). */
     1288            uint32_t                idxPciDev;
    12571289            /** The IRQ */
    1258             int                     iIrq;
     1290            int32_t                 iIrq;
    12591291            /** The new level. */
    1260             int                     iLevel;
     1292            int32_t                 iLevel;
    12611293            /** The IRQ tag and source. */
    12621294            uint32_t                uTagSrc;
     
    14191451    /** @name Queues
    14201452     * @{ */
    1421     /** Queue in which devhlp tasks are queued for R3 execution - R3 Ptr. */
    1422     R3PTRTYPE(PPDMQUEUE)            pDevHlpQueueR3;
    1423     /** Queue in which devhlp tasks are queued for R3 execution - R0 Ptr. */
    1424     R0PTRTYPE(PPDMQUEUE)            pDevHlpQueueR0;
    1425     /** Pointer to the queue which should be manually flushed - R0 Ptr.
    1426      * Only touched by EMT. */
    1427     R0PTRTYPE(struct PDMQUEUE *)    pQueueFlushR0;
     1453    /** Number of ring-0 capable queues in apQueues. */
     1454    uint32_t                        cRing0Queues;
     1455    uint32_t                        u32Padding1;
     1456    /** Array of ring-0 capable queues running in parallel to PDMR0PERVM::aQueues. */
     1457    R3PTRTYPE(PPDMQUEUE)            apRing0Queues[16];
     1458    /** Number of ring-3 only queues  */
     1459    uint32_t                        cRing3Queues;
     1460    /** The allocation size of the ring-3 queue handle table. */
     1461    uint32_t                        cRing3QueuesAlloc;
     1462    /** Handle table for the ring-3 only queues. */
     1463    R3PTRTYPE(PPDMQUEUE *)          papRing3Queues;
     1464
     1465    /** Queue in which devhlp tasks are queued for R3 execution. */
     1466    PDMQUEUEHANDLE                  hDevHlpQueue;
    14281467    /** Bitmask controlling the queue flushing.
    14291468     * See PDM_QUEUE_FLUSH_FLAG_ACTIVE and PDM_QUEUE_FLUSH_FLAG_PENDING. */
     
    15071546    /** Number of valid ring-0 device instances (apDevInstances). */
    15081547    uint32_t                        cDevInstances;
    1509     uint32_t                        u32Padding;
     1548    uint32_t                        u32Padding1;
    15101549    /** Pointer to ring-0 device instances. */
    15111550    R0PTRTYPE(struct PDMDEVINSR0 *) apDevInstances[190];
     1551    /** Number of valid ring-0 queue instances (aQueues). */
     1552    uint32_t                        cQueues;
     1553    uint32_t                        u32Padding2;
     1554    /** Array of ring-0 queues. */
     1555    PDMQUEUER0                      aQueues[16];
    15121556} PDMR0PERVM;
    15131557
     
    15191563{
    15201564    /** @todo move more stuff over here. */
    1521 
    1522     /** Linked list of timer driven PDM queues.
    1523      * Currently serialized by PDM::CritSect.  */
    1524     R3PTRTYPE(struct PDMQUEUE *)    pQueuesTimer;
    1525     /** Linked list of force action driven PDM queues.
    1526      * Currently serialized by PDM::CritSect. */
    1527     R3PTRTYPE(struct PDMQUEUE *)    pQueuesForced;
    15281565
    15291566    /** Lock protecting the lists below it. */
     
    16601697char       *pdmR3FileR3(const char *pszFile, bool fShared);
    16611698int         pdmR3LoadR3U(PUVM pUVM, const char *pszFilename, const char *pszName);
    1662 
     1699#endif /* IN_RING3 */
     1700
     1701void        pdmQueueInit(PPDMQUEUE pQueue, uint32_t cbBitmap, uint32_t cbItem, uint32_t cItems,
     1702                         const char *pszName, PDMQUEUETYPE enmType, RTR3PTR pfnCallback, RTR3PTR pvOwner);
     1703
     1704#ifdef IN_RING3
    16631705int         pdmR3TaskInit(PVM pVM);
    16641706void        pdmR3TaskTerm(PVM pVM);
     
    16771719int         pdmR3ThreadSuspendAll(PVM pVM);
    16781720
    1679 #ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
     1721# ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
    16801722int         pdmR3AsyncCompletionInit(PVM pVM);
    16811723int         pdmR3AsyncCompletionTerm(PVM pVM);
     
    16881730int         pdmR3AsyncCompletionTemplateDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns);
    16891731int         pdmR3AsyncCompletionTemplateDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns);
    1690 #endif
    1691 
    1692 #ifdef VBOX_WITH_NETSHAPER
     1732# endif
     1733
     1734# ifdef VBOX_WITH_NETSHAPER
    16931735int         pdmR3NetShaperInit(PVM pVM);
    16941736int         pdmR3NetShaperTerm(PVM pVM);
    1695 #endif
     1737# endif
    16961738
    16971739int         pdmR3BlkCacheInit(PVM pVM);
    16981740void        pdmR3BlkCacheTerm(PVM pVM);
    16991741int         pdmR3BlkCacheResume(PVM pVM);
    1700 
    17011742#endif /* IN_RING3 */
    17021743
     
    17261767#ifdef IN_RING0
    17271768DECLHIDDEN(bool)           pdmR0IsaSetIrq(PGVM pGVM, int iIrq, int iLevel, uint32_t uTagSrc);
     1769DECLHIDDEN(void)           pdmR0QueueDestroy(PGVM pGVM, uint32_t iQueue);
     1770
    17281771#endif
    17291772
  • trunk/src/VBox/VMM/testcase/Makefile.kmk

    r93115 r93609  
    6969        tstCompressionBenchmark \
    7070        tstIEMCheckMc \
     71        tstPDMQueue \
    7172        tstSSM \
    7273        tstVMMR0CallHost-1 \
     
    459460 endif
    460461endif
     462
     463#
     464# PDM Queue tests.
     465#
     466tstPDMQueue_TEMPLATE := VBOXR3EXE
     467tstPDMQueue_DEFS     = $(VMM_COMMON_DEFS)
     468tstPDMQueue_SOURCES  := tstPDMQueue.cpp
     469tstPDMQueue_LIBS     := $(LIB_VMM) $(LIB_RUNTIME)
    461470
    462471
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette