PDMQueue.cpp revision c647bac94d46aebf0bcf05d87cea81d048dc2675
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/* $Id$ */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/** @file
cbaf00194b28ee57e4aeee473f66f91f1be4e022vboxsync * PDM Queue - Transport data and tasks to EMT and R3.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync/*
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * Copyright (C) 2006-2013 Oracle Corporation
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync *
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * available from http://www.virtualbox.org. This file is free software;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * you can redistribute it and/or modify it under the terms of the GNU
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * General Public License (GPL) as published by the Free Software
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/*******************************************************************************
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync* Header Files *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync*******************************************************************************/
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define LOG_GROUP LOG_GROUP_PDM_QUEUE
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include "PDMInternal.h"
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <VBox/vmm/pdm.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <VBox/vmm/mm.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#ifdef VBOX_WITH_REM
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync# include <VBox/vmm/rem.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#endif
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/vm.h>
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync#include <VBox/vmm/uvm.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <VBox/err.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync#include <VBox/log.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/asm.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <iprt/assert.h>
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#include <iprt/thread.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/*******************************************************************************
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync* Internal Functions *
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync*******************************************************************************/
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncDECLINLINE(void) pdmR3QueueFreeItem(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem);
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic bool pdmR3QueueFlush(PPDMQUEUE pQueue);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void) pdmR3QueueTimer(PVM pVM, PTMTIMER pTimer, void *pvUser);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Internal worker for the queue creation apis.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @returns VBox status.
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * @param pVM Pointer to the VM.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cbItem Item size.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cItems Number of items.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cMilliesInterval Number of milliseconds between polling the queue.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * If 0 then the emulation thread will be notified whenever an item arrives.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param fRZEnabled Set if the queue will be used from RC/R0 and need to be allocated from the hyper heap.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pszName The queue name. Unique. Not copied.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param ppQueue Where to store the queue handle.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic int pdmR3QueueCreate(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, bool fRZEnabled,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync const char *pszName, PPDMQUEUE *ppQueue)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PUVM pUVM = pVM->pUVM;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Validate input.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync AssertMsgReturn(cbItem >= sizeof(PDMQUEUEITEMCORE) && cbItem < _1M, ("cbItem=%zu\n", cbItem), VERR_OUT_OF_RANGE);
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync AssertMsgReturn(cItems >= 1 && cItems <= _64K, ("cItems=%u\n", cItems), VERR_OUT_OF_RANGE);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /*
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * Align the item size and calculate the structure size.
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync */
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync cbItem = RT_ALIGN(cbItem, sizeof(RTUINTPTR));
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync size_t cb = cbItem * cItems + RT_ALIGN_Z(RT_OFFSETOF(PDMQUEUE, aFreeItems[cItems + PDMQUEUE_FREE_SLACK]), 16);
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync PPDMQUEUE pQueue;
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync int rc;
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync if (fRZEnabled)
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync rc = MMHyperAlloc(pVM, cb, 0, MM_TAG_PDM_QUEUE, (void **)&pQueue );
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else
fa033b734cf3b131680f290326ccbbd23c42946bvboxsync rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_QUEUE, cb, (void **)&pQueue);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (RT_FAILURE(rc))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return rc;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Initialize the data fields.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->pVMR3 = pVM;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pQueue->pVMR0 = fRZEnabled ? pVM->pVMR0 : NIL_RTR0PTR;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->pVMRC = fRZEnabled ? pVM->pVMRC : NIL_RTRCPTR;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pQueue->pszName = pszName;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->cMilliesInterval = cMilliesInterval;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync //pQueue->pTimer = NULL;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pQueue->cbItem = (uint32_t)cbItem;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pQueue->cItems = cItems;
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync //pQueue->pPendingR3 = NULL;
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync //pQueue->pPendingR0 = NULL;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync //pQueue->pPendingRC = NULL;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->iFreeHead = cItems;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync //pQueue->iFreeTail = 0;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMQUEUEITEMCORE pItem = (PPDMQUEUEITEMCORE)((char *)pQueue + RT_ALIGN_Z(RT_OFFSETOF(PDMQUEUE, aFreeItems[cItems + PDMQUEUE_FREE_SLACK]), 16));
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync for (unsigned i = 0; i < cItems; i++, pItem = (PPDMQUEUEITEMCORE)((char *)pItem + cbItem))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pQueue->aFreeItems[i].pItemR3 = pItem;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync if (fRZEnabled)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pQueue->aFreeItems[i].pItemR0 = MMHyperR3ToR0(pVM, pItem);
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync pQueue->aFreeItems[i].pItemRC = MMHyperR3ToRC(pVM, pItem);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Create timer?
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync */
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync if (cMilliesInterval)
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync {
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync rc = TMR3TimerCreateInternal(pVM, TMCLOCK_REAL, pdmR3QueueTimer, pQueue, "Queue timer", &pQueue->pTimer);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync if (RT_SUCCESS(rc))
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync {
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync rc = TMTimerSetMillies(pQueue->pTimer, cMilliesInterval);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync if (RT_FAILURE(rc))
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync {
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync AssertMsgFailed(("TMTimerSetMillies failed rc=%Rrc\n", rc));
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync int rc2 = TMR3TimerDestroy(pQueue->pTimer); AssertRC(rc2);
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync }
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync else
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync AssertMsgFailed(("TMR3TimerCreateInternal failed rc=%Rrc\n", rc));
e3f5c51715cbf77ae2d2e9d05bafd00d69b1bec9vboxsync if (RT_FAILURE(rc))
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync {
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync if (fRZEnabled)
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync MMHyperFree(pVM, pQueue);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync else
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync MMR3HeapFree(pQueue);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return rc;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync }
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /*
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * Insert into the queue list for timer driven queues.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pdmLock(pVM);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pQueue->pNext = pUVM->pdm.s.pQueuesTimer;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pUVM->pdm.s.pQueuesTimer = pQueue;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pdmUnlock(pVM);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync }
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync else
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync {
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync /*
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * Insert into the queue list for forced action driven queues.
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * This is a FIFO, so insert at the end.
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync */
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync /** @todo we should add a priority to the queues so we don't have to rely on
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * the initialization order to deal with problems like @bugref{1605} (pgm/pcnet
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * deadlock caused by the critsect queue to be last in the chain).
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * - Update, the critical sections are no longer using queues, so this isn't a real
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * problem any longer. The priority might be a nice feature for later though.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pdmLock(pVM);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (!pUVM->pdm.s.pQueuesForced)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pUVM->pdm.s.pQueuesForced = pQueue;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync else
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync {
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync PPDMQUEUE pPrev = pUVM->pdm.s.pQueuesForced;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync while (pPrev->pNext)
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync pPrev = pPrev->pNext;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync pPrev->pNext = pQueue;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync pdmUnlock(pVM);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync }
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync /*
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * Register the statistics.
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync */
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync STAMR3RegisterF(pVM, &pQueue->cbItem, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Item size.", "/PDM/Queue/%s/cbItem", pQueue->pszName);
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync STAMR3RegisterF(pVM, &pQueue->cItems, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Queue size.", "/PDM/Queue/%s/cItems", pQueue->pszName);
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync STAMR3RegisterF(pVM, &pQueue->StatAllocFailures, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "PDMQueueAlloc failures.", "/PDM/Queue/%s/AllocFailures", pQueue->pszName);
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync STAMR3RegisterF(pVM, &pQueue->StatInsert, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Calls to PDMQueueInsert.", "/PDM/Queue/%s/Insert", pQueue->pszName);
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync STAMR3RegisterF(pVM, &pQueue->StatFlush, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Calls to pdmR3QueueFlush.", "/PDM/Queue/%s/Flush", pQueue->pszName);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync STAMR3RegisterF(pVM, &pQueue->StatFlushLeftovers, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Left over items after flush.", "/PDM/Queue/%s/FlushLeftovers", pQueue->pszName);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync#ifdef VBOX_WITH_STATISTICS
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync STAMR3RegisterF(pVM, &pQueue->StatFlushPrf, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Profiling pdmR3QueueFlush.", "/PDM/Queue/%s/FlushPrf", pQueue->pszName);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync STAMR3RegisterF(pVM, (void *)&pQueue->cStatPending, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Pending items.", "/PDM/Queue/%s/Pending", pQueue->pszName);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync#endif
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *ppQueue = pQueue;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return VINF_SUCCESS;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Create a queue with a device owner.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @returns VBox status code.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pVM Pointer to the VM.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pDevIns Device instance.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cbItem Size a queue item.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cItems Number of items in the queue.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cMilliesInterval Number of milliseconds between polling the queue.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * If 0 then the emulation thread will be notified whenever an item arrives.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pfnCallback The consumer function.
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync * @param fRZEnabled Set if the queue must be usable from RC/R0.
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync * @param pszName The queue name. Unique. Not copied.
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync * @param ppQueue Where to store the queue handle on success.
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync * @thread Emulation thread only.
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncVMMR3_INT_DECL(int) PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync LogFlow(("PDMR3QueueCreateDevice: pDevIns=%p cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p fRZEnabled=%RTbool pszName=%s\n",
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pDevIns, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Validate input.
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync */
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync VMCPU_ASSERT_EMT(&pVM->aCpus[0]);
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync if (!pfnCallback)
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync {
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync AssertMsgFailed(("No consumer callback!\n"));
fe813b3594039ba864493438e78ee0e7132bc445vboxsync return VERR_INVALID_PARAMETER;
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync }
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Create the queue.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMQUEUE pQueue;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, fRZEnabled, pszName, &pQueue);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (RT_SUCCESS(rc))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync pQueue->enmType = PDMQUEUETYPE_DEV;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync pQueue->u.Dev.pDevIns = pDevIns;
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync pQueue->u.Dev.pfnCallback = pfnCallback;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *ppQueue = pQueue;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync Log(("PDM: Created device queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pDevIns=%p\n",
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync cbItem, cItems, cMilliesInterval, pfnCallback, pDevIns));
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return rc;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Create a queue with a driver owner.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @returns VBox status code.
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync * @param pVM Pointer to the VM.
fe813b3594039ba864493438e78ee0e7132bc445vboxsync * @param pDrvIns Driver instance.
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync * @param cbItem Size a queue item.
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync * @param cItems Number of items in the queue.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cMilliesInterval Number of milliseconds between polling the queue.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * If 0 then the emulation thread will be notified whenever an item arrives.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pfnCallback The consumer function.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pszName The queue name. Unique. Not copied.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param ppQueue Where to store the queue handle on success.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @thread Emulation thread only.
362838d79d234a41380be42aae9118850cc3c929vboxsync */
362838d79d234a41380be42aae9118850cc3c929vboxsyncVMMR3_INT_DECL(int) PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
362838d79d234a41380be42aae9118850cc3c929vboxsync PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
362838d79d234a41380be42aae9118850cc3c929vboxsync{
362838d79d234a41380be42aae9118850cc3c929vboxsync LogFlow(("PDMR3QueueCreateDriver: pDrvIns=%p cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%s\n",
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName));
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync
362838d79d234a41380be42aae9118850cc3c929vboxsync /*
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * Validate input.
362838d79d234a41380be42aae9118850cc3c929vboxsync */
362838d79d234a41380be42aae9118850cc3c929vboxsync VMCPU_ASSERT_EMT(&pVM->aCpus[0]);
362838d79d234a41380be42aae9118850cc3c929vboxsync AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
362838d79d234a41380be42aae9118850cc3c929vboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * Create the queue.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync */
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync PPDMQUEUE pQueue;
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, false, pszName, &pQueue);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync if (RT_SUCCESS(rc))
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync {
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync pQueue->enmType = PDMQUEUETYPE_DRV;
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync pQueue->u.Drv.pDrvIns = pDrvIns;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pQueue->u.Drv.pfnCallback = pfnCallback;
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync *ppQueue = pQueue;
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync Log(("PDM: Created driver queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pDrvIns=%p\n",
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync cbItem, cItems, cMilliesInterval, pfnCallback, pDrvIns));
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return rc;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync/**
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Create a queue with an internal owner.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync *
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @returns VBox status code.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param pVM Pointer to the VM.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param cbItem Size a queue item.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param cItems Number of items in the queue.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param cMilliesInterval Number of milliseconds between polling the queue.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * If 0 then the emulation thread will be notified whenever an item arrives.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param pfnCallback The consumer function.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param fRZEnabled Set if the queue must be usable from RC/R0.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param pszName The queue name. Unique. Not copied.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * @param ppQueue Where to store the queue handle on success.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * @thread Emulation thread only.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsyncVMMR3_INT_DECL(int) PDMR3QueueCreateInternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync PFNPDMQUEUEINT pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync{
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync LogFlow(("PDMR3QueueCreateInternal: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p fRZEnabled=%RTbool pszName=%s\n",
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName));
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync /*
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Validate input.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync VMCPU_ASSERT_EMT(&pVM->aCpus[0]);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync /*
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * Create the queue.
cbaf00194b28ee57e4aeee473f66f91f1be4e022vboxsync */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync PPDMQUEUE pQueue;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, fRZEnabled, pszName, &pQueue);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (RT_SUCCESS(rc))
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync {
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pQueue->enmType = PDMQUEUETYPE_INTERNAL;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pQueue->u.Int.pfnCallback = pfnCallback;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync *ppQueue = pQueue;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync Log(("PDM: Created internal queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p\n",
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync cbItem, cItems, cMilliesInterval, pfnCallback));
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync }
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync return rc;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync}
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync/**
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Create a queue with an external owner.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @returns VBox status code.
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync * @param pVM Pointer to the VM.
cba6719bd64ec749967bbe931230452664109857vboxsync * @param cbItem Size a queue item.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cItems Number of items in the queue.
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync * @param cMilliesInterval Number of milliseconds between polling the queue.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * If 0 then the emulation thread will be notified whenever an item arrives.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @param pfnCallback The consumer function.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pvUser The user argument to the consumer function.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param pszName The queue name. Unique. Not copied.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param ppQueue Where to store the queue handle on success.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @thread Emulation thread only.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncVMMR3_INT_DECL(int) PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PFNPDMQUEUEEXT pfnCallback, void *pvUser, const char *pszName, PPDMQUEUE *ppQueue)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync{
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync LogFlow(("PDMR3QueueCreateExternal: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%s\n", cbItem, cItems, cMilliesInterval, pfnCallback, pszName));
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Validate input.
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync VMCPU_ASSERT_EMT(&pVM->aCpus[0]);
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Create the queue.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMQUEUE pQueue;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, false, pszName, &pQueue);
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync if (RT_SUCCESS(rc))
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->enmType = PDMQUEUETYPE_EXTERNAL;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->u.Ext.pvUser = pvUser;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->u.Ext.pfnCallback = pfnCallback;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *ppQueue = pQueue;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync Log(("PDM: Created external queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pvUser=%p\n",
cba6719bd64ec749967bbe931230452664109857vboxsync cbItem, cItems, cMilliesInterval, pfnCallback, pvUser));
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync }
30adc6dd25ed9fef4d800a6d9f1ab7e765b4c340vboxsync return rc;
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync}
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync * Destroy a queue.
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync *
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * @returns VBox status code.
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * @param pQueue Queue to destroy.
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * @thread Emulation thread only.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsyncVMMR3_INT_DECL(int) PDMR3QueueDestroy(PPDMQUEUE pQueue)
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync{
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync LogFlow(("PDMR3QueueDestroy: pQueue=%p\n", pQueue));
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * Validate input.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync if (!pQueue)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync return VERR_INVALID_PARAMETER;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync Assert(pQueue && pQueue->pVMR3);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync PVM pVM = pQueue->pVMR3;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync PUVM pUVM = pVM->pUVM;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync pdmLock(pVM);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync /*
e3f5c51715cbf77ae2d2e9d05bafd00d69b1bec9vboxsync * Unlink it.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (pQueue->pTimer)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (pUVM->pdm.s.pQueuesTimer != pQueue)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMQUEUE pCur = pUVM->pdm.s.pQueuesTimer;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync while (pCur)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (pCur->pNext == pQueue)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pCur->pNext = pQueue->pNext;
5b465a7c1237993faf8bb50120d247f3f0319adavboxsync break;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync pCur = pCur->pNext;
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync }
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync AssertMsg(pCur, ("Didn't find the queue!\n"));
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pUVM->pdm.s.pQueuesTimer = pQueue->pNext;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (pUVM->pdm.s.pQueuesForced != pQueue)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMQUEUE pCur = pUVM->pdm.s.pQueuesForced;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync while (pCur)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (pCur->pNext == pQueue)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pCur->pNext = pQueue->pNext;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync break;
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync }
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync pCur = pCur->pNext;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync AssertMsg(pCur, ("Didn't find the queue!\n"));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pUVM->pdm.s.pQueuesForced = pQueue->pNext;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->pNext = NULL;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pQueue->pVMR3 = NULL;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pdmUnlock(pVM);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
cba6719bd64ec749967bbe931230452664109857vboxsync /*
cba6719bd64ec749967bbe931230452664109857vboxsync * Deregister statistics.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync STAMR3DeregisterF(pVM->pUVM, "/PDM/Queue/%s/cbItem", pQueue->pszName);
cba6719bd64ec749967bbe931230452664109857vboxsync
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /*
cba6719bd64ec749967bbe931230452664109857vboxsync * Destroy the timer and free it.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
cba6719bd64ec749967bbe931230452664109857vboxsync if (pQueue->pTimer)
cba6719bd64ec749967bbe931230452664109857vboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync TMR3TimerDestroy(pQueue->pTimer);
pQueue->pTimer = NULL;
}
if (pQueue->pVMRC)
{
pQueue->pVMRC = NIL_RTRCPTR;
pQueue->pVMR0 = NIL_RTR0PTR;
MMHyperFree(pVM, pQueue);
}
else
MMR3HeapFree(pQueue);
return VINF_SUCCESS;
}
/**
* Destroy a all queues owned by the specified device.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pDevIns Device instance.
* @thread Emulation thread only.
*/
VMMR3_INT_DECL(int) PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns)
{
LogFlow(("PDMR3QueueDestroyDevice: pDevIns=%p\n", pDevIns));
/*
* Validate input.
*/
if (!pDevIns)
return VERR_INVALID_PARAMETER;
PUVM pUVM = pVM->pUVM;
pdmLock(pVM);
/*
* Unlink it.
*/
PPDMQUEUE pQueueNext = pUVM->pdm.s.pQueuesTimer;
PPDMQUEUE pQueue = pUVM->pdm.s.pQueuesForced;
do
{
while (pQueue)
{
if ( pQueue->enmType == PDMQUEUETYPE_DEV
&& pQueue->u.Dev.pDevIns == pDevIns)
{
PPDMQUEUE pQueueDestroy = pQueue;
pQueue = pQueue->pNext;
int rc = PDMR3QueueDestroy(pQueueDestroy);
AssertRC(rc);
}
else
pQueue = pQueue->pNext;
}
/* next queue list */
pQueue = pQueueNext;
pQueueNext = NULL;
} while (pQueue);
pdmUnlock(pVM);
return VINF_SUCCESS;
}
/**
* Destroy a all queues owned by the specified driver.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pDrvIns Driver instance.
* @thread Emulation thread only.
*/
VMMR3_INT_DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns)
{
LogFlow(("PDMR3QueueDestroyDriver: pDrvIns=%p\n", pDrvIns));
/*
* Validate input.
*/
if (!pDrvIns)
return VERR_INVALID_PARAMETER;
PUVM pUVM = pVM->pUVM;
pdmLock(pVM);
/*
* Unlink it.
*/
PPDMQUEUE pQueueNext = pUVM->pdm.s.pQueuesTimer;
PPDMQUEUE pQueue = pUVM->pdm.s.pQueuesForced;
do
{
while (pQueue)
{
if ( pQueue->enmType == PDMQUEUETYPE_DRV
&& pQueue->u.Drv.pDrvIns == pDrvIns)
{
PPDMQUEUE pQueueDestroy = pQueue;
pQueue = pQueue->pNext;
int rc = PDMR3QueueDestroy(pQueueDestroy);
AssertRC(rc);
}
else
pQueue = pQueue->pNext;
}
/* next queue list */
pQueue = pQueueNext;
pQueueNext = NULL;
} while (pQueue);
pdmUnlock(pVM);
return VINF_SUCCESS;
}
/**
* Relocate the queues.
*
* @param pVM Pointer to the VM.
* @param offDelta The relocation delta.
*/
void pdmR3QueueRelocate(PVM pVM, RTGCINTPTR offDelta)
{
/*
* Process the queues.
*/
PUVM pUVM = pVM->pUVM;
PPDMQUEUE pQueueNext = pUVM->pdm.s.pQueuesTimer;
PPDMQUEUE pQueue = pUVM->pdm.s.pQueuesForced;
do
{
while (pQueue)
{
if (pQueue->pVMRC)
{
pQueue->pVMRC = pVM->pVMRC;
/* Pending RC items. */
if (pQueue->pPendingRC)
{
pQueue->pPendingRC += offDelta;
PPDMQUEUEITEMCORE pCur = (PPDMQUEUEITEMCORE)MMHyperRCToR3(pVM, pQueue->pPendingRC);
while (pCur->pNextRC)
{
pCur->pNextRC += offDelta;
pCur = (PPDMQUEUEITEMCORE)MMHyperRCToR3(pVM, pCur->pNextRC);
}
}
/* The free items. */
uint32_t i = pQueue->iFreeTail;
while (i != pQueue->iFreeHead)
{
pQueue->aFreeItems[i].pItemRC = MMHyperR3ToRC(pVM, pQueue->aFreeItems[i].pItemR3);
i = (i + 1) % (pQueue->cItems + PDMQUEUE_FREE_SLACK);
}
}
/* next queue */
pQueue = pQueue->pNext;
}
/* next queue list */
pQueue = pQueueNext;
pQueueNext = NULL;
} while (pQueue);
}
/**
* Flush pending queues.
* This is a forced action callback.
*
* @param pVM Pointer to the VM.
* @thread Emulation thread only.
*/
VMMR3_INT_DECL(void) PDMR3QueueFlushAll(PVM pVM)
{
VM_ASSERT_EMT(pVM);
LogFlow(("PDMR3QueuesFlush:\n"));
/*
* Only let one EMT flushing queues at any one time to preserve the order
* and to avoid wasting time. The FF is always cleared here, because it's
* only used to get someones attention. Queue inserts occurring during the
* flush are caught using the pending bit.
*
* Note! We must check the force action and pending flags after clearing
* the active bit!
*/
VM_FF_CLEAR(pVM, VM_FF_PDM_QUEUES);
while (!ASMAtomicBitTestAndSet(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_ACTIVE_BIT))
{
ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT);
for (PPDMQUEUE pCur = pVM->pUVM->pdm.s.pQueuesForced; pCur; pCur = pCur->pNext)
if ( pCur->pPendingR3
|| pCur->pPendingR0
|| pCur->pPendingRC)
pdmR3QueueFlush(pCur);
ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_ACTIVE_BIT);
/* We're done if there were no inserts while we were busy. */
if ( !ASMBitTest(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT)
&& !VM_FF_IS_PENDING(pVM, VM_FF_PDM_QUEUES))
break;
VM_FF_CLEAR(pVM, VM_FF_PDM_QUEUES);
}
}
/**
* Process pending items in one queue.
*
* @returns Success indicator.
* If false the item the consumer said "enough!".
* @param pQueue The queue.
*/
static bool pdmR3QueueFlush(PPDMQUEUE pQueue)
{
STAM_PROFILE_START(&pQueue->StatFlushPrf,p);
/*
* Get the lists.
*/
PPDMQUEUEITEMCORE pItems = ASMAtomicXchgPtrT(&pQueue->pPendingR3, NULL, PPDMQUEUEITEMCORE);
RTRCPTR pItemsRC = ASMAtomicXchgRCPtr(&pQueue->pPendingRC, NIL_RTRCPTR);
RTR0PTR pItemsR0 = ASMAtomicXchgR0Ptr(&pQueue->pPendingR0, NIL_RTR0PTR);
AssertMsgReturn( pItemsR0
|| pItemsRC
|| pItems,
("Someone is racing us? This shouldn't happen!\n"),
true);
/*
* Reverse the list (it's inserted in LIFO order to avoid semaphores, remember).
*/
PPDMQUEUEITEMCORE pCur = pItems;
pItems = NULL;
while (pCur)
{
PPDMQUEUEITEMCORE pInsert = pCur;
pCur = pCur->pNextR3;
pInsert->pNextR3 = pItems;
pItems = pInsert;
}
/*
* Do the same for any pending RC items.
*/
while (pItemsRC)
{
PPDMQUEUEITEMCORE pInsert = (PPDMQUEUEITEMCORE)MMHyperRCToR3(pQueue->pVMR3, pItemsRC);
pItemsRC = pInsert->pNextRC;
pInsert->pNextRC = NIL_RTRCPTR;
pInsert->pNextR3 = pItems;
pItems = pInsert;
}
/*
* Do the same for any pending R0 items.
*/
while (pItemsR0)
{
PPDMQUEUEITEMCORE pInsert = (PPDMQUEUEITEMCORE)MMHyperR0ToR3(pQueue->pVMR3, pItemsR0);
pItemsR0 = pInsert->pNextR0;
pInsert->pNextR0 = NIL_RTR0PTR;
pInsert->pNextR3 = pItems;
pItems = pInsert;
}
/*
* Feed the items to the consumer function.
*/
Log2(("pdmR3QueueFlush: pQueue=%p enmType=%d pItems=%p\n", pQueue, pQueue->enmType, pItems));
switch (pQueue->enmType)
{
case PDMQUEUETYPE_DEV:
while (pItems)
{
if (!pQueue->u.Dev.pfnCallback(pQueue->u.Dev.pDevIns, pItems))
break;
pCur = pItems;
pItems = pItems->pNextR3;
pdmR3QueueFreeItem(pQueue, pCur);
}
break;
case PDMQUEUETYPE_DRV:
while (pItems)
{
if (!pQueue->u.Drv.pfnCallback(pQueue->u.Drv.pDrvIns, pItems))
break;
pCur = pItems;
pItems = pItems->pNextR3;
pdmR3QueueFreeItem(pQueue, pCur);
}
break;
case PDMQUEUETYPE_INTERNAL:
while (pItems)
{
if (!pQueue->u.Int.pfnCallback(pQueue->pVMR3, pItems))
break;
pCur = pItems;
pItems = pItems->pNextR3;
pdmR3QueueFreeItem(pQueue, pCur);
}
break;
case PDMQUEUETYPE_EXTERNAL:
while (pItems)
{
if (!pQueue->u.Ext.pfnCallback(pQueue->u.Ext.pvUser, pItems))
break;
pCur = pItems;
pItems = pItems->pNextR3;
pdmR3QueueFreeItem(pQueue, pCur);
}
break;
default:
AssertMsgFailed(("Invalid queue type %d\n", pQueue->enmType));
break;
}
/*
* Success?
*/
if (pItems)
{
/*
* Reverse the list.
*/
pCur = pItems;
pItems = NULL;
while (pCur)
{
PPDMQUEUEITEMCORE pInsert = pCur;
pCur = pInsert->pNextR3;
pInsert->pNextR3 = pItems;
pItems = pInsert;
}
/*
* Insert the list at the tail of the pending list.
*/
for (;;)
{
if (ASMAtomicCmpXchgPtr(&pQueue->pPendingR3, pItems, NULL))
break;
PPDMQUEUEITEMCORE pPending = ASMAtomicXchgPtrT(&pQueue->pPendingR3, NULL, PPDMQUEUEITEMCORE);
if (pPending)
{
pCur = pPending;
while (pCur->pNextR3)
pCur = pCur->pNextR3;
pCur->pNextR3 = pItems;
pItems = pPending;
}
}
STAM_REL_COUNTER_INC(&pQueue->StatFlushLeftovers);
STAM_PROFILE_STOP(&pQueue->StatFlushPrf,p);
return false;
}
STAM_PROFILE_STOP(&pQueue->StatFlushPrf,p);
return true;
}
/**
* Free an item.
*
* @param pQueue The queue.
* @param pItem The item.
*/
DECLINLINE(void) pdmR3QueueFreeItem(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem)
{
VM_ASSERT_EMT(pQueue->pVMR3);
int i = pQueue->iFreeHead;
int iNext = (i + 1) % (pQueue->cItems + PDMQUEUE_FREE_SLACK);
pQueue->aFreeItems[i].pItemR3 = pItem;
if (pQueue->pVMRC)
{
pQueue->aFreeItems[i].pItemRC = MMHyperR3ToRC(pQueue->pVMR3, pItem);
pQueue->aFreeItems[i].pItemR0 = MMHyperR3ToR0(pQueue->pVMR3, pItem);
}
if (!ASMAtomicCmpXchgU32(&pQueue->iFreeHead, iNext, i))
AssertMsgFailed(("huh? i=%d iNext=%d iFreeHead=%d iFreeTail=%d\n", i, iNext, pQueue->iFreeHead, pQueue->iFreeTail));
STAM_STATS({ ASMAtomicDecU32(&pQueue->cStatPending); });
}
/**
* Timer handler for PDM queues.
* This is called by for a single queue.
*
* @param pVM Pointer to the VM.
* @param pTimer Pointer to timer.
* @param pvUser Pointer to the queue.
*/
static DECLCALLBACK(void) pdmR3QueueTimer(PVM pVM, PTMTIMER pTimer, void *pvUser)
{
PPDMQUEUE pQueue = (PPDMQUEUE)pvUser;
Assert(pTimer == pQueue->pTimer); NOREF(pTimer); NOREF(pVM);
if ( pQueue->pPendingR3
|| pQueue->pPendingR0
|| pQueue->pPendingRC)
pdmR3QueueFlush(pQueue);
int rc = TMTimerSetMillies(pQueue->pTimer, pQueue->cMilliesInterval);
AssertRC(rc);
}