Changeset 93609 in vbox for trunk/src/VBox/VMM/VMMR3
- Timestamp:
- Feb 5, 2022 7:03:08 PM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 149754
- Location:
- trunk/src/VBox/VMM/VMMR3
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
r93554 r93609 2747 2747 } 2748 2748 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)); 2754 2753 return rc; 2755 2754 } … … 2770 2769 static DECLCALLBACK(PPDMQUEUEITEMCORE) pdmR3DevHlp_QueueAlloc(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue) 2771 2770 { 2772 return PDMQueueAlloc(pdmR3DevHlp_QueueToPtr(pDevIns, hQueue)); 2771 PDMDEV_ASSERT_DEVINS(pDevIns); 2772 return PDMQueueAlloc(pDevIns->Internal.s.pVMR3, hQueue, pDevIns); 2773 2773 } 2774 2774 2775 2775 2776 2776 /** @interface_method_impl{PDMDEVHLPR3,pfnQueueInsert} */ 2777 static DECLCALLBACK( void) pdmR3DevHlp_QueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)2778 { 2779 return PDMQueueInsert(p dmR3DevHlp_QueueToPtr(pDevIns, hQueue), pItem);2777 static DECLCALLBACK(int) pdmR3DevHlp_QueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem) 2778 { 2779 return PDMQueueInsert(pDevIns->Internal.s.pVMR3, hQueue, pDevIns, pItem); 2780 2780 } 2781 2781 … … 2784 2784 static DECLCALLBACK(bool) pdmR3DevHlp_QueueFlushIfNecessary(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue) 2785 2785 { 2786 return PDMQueueFlushIfNecessary(p dmR3DevHlp_QueueToPtr(pDevIns, hQueue));2786 return PDMQueueFlushIfNecessary(pDevIns->Internal.s.pVMR3, hQueue, pDevIns) == VINF_SUCCESS; 2787 2787 } 2788 2788 … … 6360 6360 { 6361 6361 /* 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; 6363 6365 if (pPciDev) 6364 6366 { … … 6373 6375 } 6374 6376 else 6375 AssertReleaseMsgFailed(("No PCI device registered!\n"));6377 AssertReleaseMsgFailed(("No PCI device given! (%#x)\n", pPciDev->Int.s.idxSubDev)); 6376 6378 break; 6377 6379 } -
trunk/src/VBox/VMM/VMMR3/PDMDevice.cpp
r93115 r93609 131 131 * Get the RC & R0 devhlps and create the devhlp R3 task queue. 132 132 */ 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); 135 135 AssertRCReturn(rc, rc); 136 pVM->pdm.s.pDevHlpQueueR0 = PDMQueueR0Ptr(pVM->pdm.s.pDevHlpQueueR3);137 136 138 137 /* -
trunk/src/VBox/VMM/VMMR3/PDMDriver.cpp
r93115 r93609 1255 1255 1256 1256 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 1268 1257 /** @interface_method_impl{PDMDRVHLPR3,pfnQueueCreate} */ 1269 1258 static DECLCALLBACK(int) pdmR3DrvHlp_QueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, … … 1282 1271 } 1283 1272 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); 1287 1274 1288 1275 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *phQueue=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *phQueue)); … … 1294 1281 static DECLCALLBACK(PPDMQUEUEITEMCORE) pdmR3DrvHlp_QueueAlloc(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue) 1295 1282 { 1296 return PDMQueueAlloc(p dmR3DrvHlp_QueueToPtr(pDrvIns, hQueue));1283 return PDMQueueAlloc(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns); 1297 1284 } 1298 1285 1299 1286 1300 1287 /** @interface_method_impl{PDMDRVHLPR3,pfnQueueInsert} */ 1301 static DECLCALLBACK( void) pdmR3DrvHlp_QueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)1302 { 1303 return PDMQueueInsert(p dmR3DrvHlp_QueueToPtr(pDrvIns, hQueue), pItem);1288 static DECLCALLBACK(int) pdmR3DrvHlp_QueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem) 1289 { 1290 return PDMQueueInsert(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns, pItem); 1304 1291 } 1305 1292 … … 1308 1295 static DECLCALLBACK(bool) pdmR3DrvHlp_QueueFlushIfNecessary(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue) 1309 1296 { 1310 return PDMQueueFlushIfNecessary(pdmR3DrvHlp_QueueToPtr(pDrvIns, hQueue)); 1311 } 1312 1297 return PDMQueueFlushIfNecessary(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns) == VINF_SUCCESS; 1298 } 1313 1299 1314 1300 -
trunk/src/VBox/VMM/VMMR3/PDMQueue.cpp
r93115 r93609 31 31 #include <iprt/asm.h> 32 32 #include <iprt/assert.h> 33 #include <iprt/mem.h> 33 34 #include <iprt/thread.h> 34 35 … … 37 38 * Internal Functions * 38 39 *********************************************************************************************************************************/ 39 DECLINLINE(void) pdmR3QueueFreeItem(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem);40 static bool pdmR3QueueFlush(PPDMQUEUE pQueue);41 40 static DECLCALLBACK(void) pdmR3QueueTimer(PVM pVM, TMTIMERHANDLE hTimer, void *pvUser); 42 41 … … 54 53 * @param fRZEnabled Set if the queue will be used from RC/R0 and need to be allocated from the hyper heap. 55 54 * @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. 57 59 */ 58 60 static 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); 68 91 69 92 /* 70 93 * Align the item size and calculate the structure size. 71 94 */ 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; 76 97 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 } 78 126 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); 104 157 } 105 158 … … 109 162 if (cMilliesInterval) 110 163 { 111 char szName[ 32];112 RTStrPrintf(szName, sizeof(szName), "Que ue %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); 114 167 if (RT_SUCCESS(rc)) 115 168 { 116 169 rc = TMTimerSetMillies(pVM, pQueue->hTimer, cMilliesInterval); 117 if (RT_FAILURE(rc)) 170 if (RT_SUCCESS(rc)) 171 pQueue->cMilliesInterval = cMilliesInterval; 172 else 118 173 { 119 174 AssertMsgFailed(("TMTimerSetMillies failed rc=%Rrc\n", rc)); 120 175 int rc2 = TMR3TimerDestroy(pVM, pQueue->hTimer); AssertRC(rc2); 176 pQueue->hTimer = NIL_TMTIMERHANDLE; 121 177 } 122 178 } … … 125 181 if (RT_FAILURE(rc)) 126 182 { 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 */ 131 186 return rc; 132 187 } 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 else143 {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 on149 * the initialization order to deal with problems like @bugref{1605} (pgm/pcnet150 * 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 real152 * 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 else158 {159 PPDMQUEUE pPrev = pUVM->pdm.s.pQueuesForced;160 while (pPrev->pNext)161 pPrev = pPrev->pNext;162 pPrev->pNext = pQueue;163 }164 pdmUnlock(pVM);165 188 } 166 189 … … 168 191 * Register the statistics. 169 192 */ 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); 176 207 #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); 179 212 #endif 180 213 181 *p pQueue = pQueue;214 *phQueue = hQueue; 182 215 return VINF_SUCCESS; 183 216 } … … 196 229 * @param pfnCallback The consumer function. 197 230 * @param fRZEnabled Set if the queue must be usable from RC/R0. 198 * @param pszName The queue name. Unique. Not copied.199 * @param p pQueue 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. 200 233 * @thread Emulation thread only. 201 234 */ 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) 235 VMMR3_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) 204 238 { 205 239 LogFlow(("PDMR3QueueCreateDevice: pDevIns=%p cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p fRZEnabled=%RTbool pszName=%s\n", … … 210 244 */ 211 245 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; 217 251 218 252 /* 219 253 * Create the queue. 220 254 */ 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); 223 257 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)); 233 260 return rc; 234 261 } … … 246 273 * If 0 then the emulation thread will be notified whenever an item arrives. 247 274 * @param pfnCallback The consumer function. 248 * @param pszName The queue name. Unique. Not copied.249 * @param p pQueue 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. 250 277 * @thread Emulation thread only. 251 278 */ 252 279 VMMR3_INT_DECL(int) PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, 253 PFNPDMQUEUEDRV pfnCallback, const char *pszName, P PDMQUEUE *ppQueue)280 PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue) 254 281 { 255 282 LogFlow(("PDMR3QueueCreateDriver: pDrvIns=%p cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%s\n", … … 261 288 VM_ASSERT_EMT0(pVM); 262 289 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER); 290 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER); 263 291 264 292 /* 265 293 * Create the queue. 266 294 */ 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); 269 297 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)); 279 300 return rc; 280 301 } … … 292 313 * @param pfnCallback The consumer function. 293 314 * @param fRZEnabled Set if the queue must be usable from RC/R0. 294 * @param pszName The queue name. Unique. Not copied.295 * @param p pQueue 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. 296 317 * @thread Emulation thread only. 297 318 */ 298 319 VMMR3_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) 300 322 { 301 323 LogFlow(("PDMR3QueueCreateInternal: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p fRZEnabled=%RTbool pszName=%s\n", … … 311 333 * Create the queue. 312 334 */ 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); 315 337 if (RT_SUCCESS(rc)) 316 {317 pQueue->enmType = PDMQUEUETYPE_INTERNAL;318 pQueue->u.Int.pfnCallback = pfnCallback;319 320 *ppQueue = pQueue;321 338 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)); 324 340 return rc; 325 341 } … … 338 354 * @param pvUser The user argument to the consumer function. 339 355 * @param pszName The queue name. Unique. Not copied. 340 * @param p pQueue Where to store the queue handle on success.356 * @param phQueue Where to store the queue handle on success. 341 357 * @thread Emulation thread only. 342 358 */ 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)); 359 VMMR3DECL(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)); 347 365 348 366 /* … … 355 373 * Create the queue. 356 374 */ 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 */ 394 VMMR3DECL(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 357 405 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; 413 435 } 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 } 439 439 440 440 /* 441 441 * Deregister statistics. 442 442 */ 443 STAMR3DeregisterF(pVM->pUVM, "/PDM/Queue/%s/ cbItem", pQueue->pszName);443 STAMR3DeregisterF(pVM->pUVM, "/PDM/Queue/%s/*", pQueue->szName); 444 444 445 445 /* … … 451 451 pQueue->hTimer = NIL_TMTIMERHANDLE; 452 452 } 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 */ 469 static 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 } 460 505 461 506 return VINF_SUCCESS; … … 469 514 * @param pVM The cross context VM structure. 470 515 * @param pDevIns Device instance. 471 * @thread E mulation thread only.516 * @thread EMT(0) 472 517 */ 473 518 VMMR3_INT_DECL(int) PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns) 474 519 { 475 520 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); 514 522 } 515 523 … … 521 529 * @param pVM The cross context VM structure. 522 530 * @param pDrvIns Driver instance. 523 * @thread E mulation thread only.531 * @thread EMT(0) 524 532 */ 525 533 VMMR3_INT_DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns) 526 534 { 527 535 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 */ 546 DECLINLINE(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 */ 567 static 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) 549 605 { 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); 554 612 } 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 } 557 705 } 558 706 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); 565 711 return VINF_SUCCESS; 566 712 } … … 573 719 * @param pVM The cross context VM structure. 574 720 * @thread Emulation thread only. 575 */ 576 VMMR3_INT_DECL(void) PDMR3QueueFlushAll(PVM pVM) 721 * @note Internal, but exported for use in the testcase. 722 */ 723 VMMR3DECL(void) PDMR3QueueFlushAll(PVM pVM) 577 724 { 578 725 VM_ASSERT_EMT(pVM); … … 593 740 ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT); 594 741 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 } 599 766 600 767 ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_ACTIVE_BIT); … … 609 776 610 777 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( pItemsR0629 || 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 781 778 782 779 /** … … 788 785 Assert(hTimer == pQueue->hTimer); 789 786 790 if ( pQueue->pPendingR3791 || pQueue->pPendingR0)792 pdmR3QueueFlush(pQueue); 787 if (pQueue->iPending != UINT32_MAX) 788 pdmR3QueueFlush(pVM, pQueue); 789 793 790 int rc = TMTimerSetMillies(pVM, hTimer, pQueue->cMilliesInterval); 794 791 AssertRC(rc);
Note:
See TracChangeset
for help on using the changeset viewer.