req.cpp revision 52f16f53a955f5b24bc2132c418a5fffb700f089
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * IPRT - Request packets
cce0c6096dee0c5353bb74431dc47b05f87a1c6dvboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The contents of this file may alternatively be used under the terms
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of the Common Development and Distribution License Version 1.0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VirtualBox OSE distribution, in which case the provisions of the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * CDDL are applicable instead of those of the GPL.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * You may elect to license modified versions of this file under the
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * terms and conditions of either the GPL or the CDDL or both.
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * additional information or have any questions.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Header Files *
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Internal Functions *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Create a request packet queueu
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns iprt status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param ppQueue Where to store the request queue pointer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTREQQUEUE pQueue = (PRTREQQUEUE)RTMemAllocZ(sizeof(RTREQQUEUE));
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Destroy a request packet queueu
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @returns iprt status code.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @param pQueue The request queue.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Check input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Process one or more request packets
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @returns iprt status code.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @returns VERR_TIMEOUT if cMillies was reached without the packet being added.
38b70b2dcb1783801f7580cba797a0c8af4b5326vboxsync * @param pQueue The request queue.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @param cMillies Number of milliseconds to wait for a pending request.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Use RT_INDEFINITE_WAIT to only wait till one is added.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsyncRTDECL(int) RTReqProcess(PRTREQQUEUE pQueue, RTMSINTERVAL cMillies)
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Check input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Process loop.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * We do not repeat the outer loop if we've got an informationtional status code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * since that code needs processing by our caller.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Get pending requests.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync PRTREQ pReqs = (PRTREQ)ASMAtomicXchgPtr((void * volatile *)&pQueue->pReqs, NULL);
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync ASMAtomicWriteBool(&pQueue->fBusy, false); /* this aint 100% perfect, but it's good enough for now... */
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync /** @todo We currently don't care if the entire time wasted here is larger than
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * cMillies */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Reverse the list to process it in FIFO order.
17c6e5e8177d068d1bc6af875d1610718efcfdb4vboxsync Log2(("RTReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * Process the requests.
b1c3cdef473df2fbc621d5da81acc82dbfb8a11avboxsync /* Unchain the first request and advance the list. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Process the request */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break; /** @todo r=bird: we're dropping requests here! Add 2nd queue that can hold them. (will fix when writing a testcase) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Allocate and queue a call request.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If it's desired to poll on the completion of the request set cMillies
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * to 0 and use RTReqWait() to check for completation. In the other case
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * use RT_INDEFINITE_WAIT.
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * The returned request packet must be freed using RTReqFree().
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * @returns iprt statuscode.
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * Will not return VERR_INTERRUPTED.
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * @param pQueue The request queue.
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * @param ppReq Where to store the pointer to the request.
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * This will be NULL or a valid request pointer not matter what happens.
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * @param cMillies Number of milliseconds to wait for the request to
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * be completed. Use RT_INDEFINITE_WAIT to only
8b43c87d70eb66ea6a484c18d7c23f2bc733e134vboxsync * wait till it's completed.
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * @param pfnFunction Pointer to the function to call.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cArgs Number of arguments following in the ellipsis.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param ... Function arguments.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @remarks See remarks on RTReqCallV.
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsyncRTDECL(int) RTReqCall(PRTREQQUEUE pQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = RTReqCallV(pQueue, ppReq, cMillies, RTREQFLAGS_IPRT_STATUS, pfnFunction, cArgs, va);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Allocate and queue a call request to a void function.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If it's desired to poll on the completion of the request set cMillies
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * to 0 and use RTReqWait() to check for completation. In the other case
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * use RT_INDEFINITE_WAIT.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * The returned request packet must be freed using RTReqFree().
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * @returns iprt status code.
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * Will not return VERR_INTERRUPTED.
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * @param pQueue The request queue.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * @param ppReq Where to store the pointer to the request.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * This will be NULL or a valid request pointer not matter what happends.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * @param cMillies Number of milliseconds to wait for the request to
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * be completed. Use RT_INDEFINITE_WAIT to only
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * wait till it's completed.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * @param pfnFunction Pointer to the function to call.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * @param cArgs Number of arguments following in the ellipsis.
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * @param ... Function arguments.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * @remarks See remarks on RTReqCallV.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsyncRTDECL(int) RTReqCallVoid(PRTREQQUEUE pQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = RTReqCallV(pQueue, ppReq, cMillies, RTREQFLAGS_VOID, pfnFunction, cArgs, va);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Allocate and queue a call request to a void function.
5cd35366dd244ca8c8c583904fc6ff2a0c60fa0fvboxsync * If it's desired to poll on the completion of the request set cMillies
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * to 0 and use RTReqWait() to check for completation. In the other case
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsync * use RT_INDEFINITE_WAIT.
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsync * The returned request packet must be freed using RTReqFree().
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsync * @returns iprt status code.
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsync * Will not return VERR_INTERRUPTED.
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsync * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
43d3e60a2bcef646da0887a845e67c3a47759158vboxsync * @param pQueue The request queue.
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * @param ppReq Where to store the pointer to the request.
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * This will be NULL or a valid request pointer not matter what happends, unless fFlags
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * contains RTREQFLAGS_NO_WAIT when it will be optional and always NULL.
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * @param cMillies Number of milliseconds to wait for the request to
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * be completed. Use RT_INDEFINITE_WAIT to only
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * wait till it's completed.
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * @param fFlags A combination of the RTREQFLAGS values.
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * @param pfnFunction Pointer to the function to call.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cArgs Number of arguments following in the ellipsis.
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * @param ... Function arguments.
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * @remarks See remarks on RTReqCallV.
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsyncRTDECL(int) RTReqCallEx(PRTREQQUEUE pQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync int rc = RTReqCallV(pQueue, ppReq, cMillies, fFlags, pfnFunction, cArgs, va);
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * Allocate and queue a call request.
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * If it's desired to poll on the completion of the request set cMillies
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * to 0 and use RTReqWait() to check for completation. In the other case
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * use RT_INDEFINITE_WAIT.
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * The returned request packet must be freed using RTReqFree().
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * @returns iprt status code.
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * Will not return VERR_INTERRUPTED.
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * @param pQueue The request queue.
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * @param ppReq Where to store the pointer to the request.
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * This will be NULL or a valid request pointer not matter what happends, unless fFlags
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * contains RTREQFLAGS_NO_WAIT when it will be optional and always NULL.
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * @param cMillies Number of milliseconds to wait for the request to
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * be completed. Use RT_INDEFINITE_WAIT to only
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * wait till it's completed.
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * @param fFlags A combination of the RTREQFLAGS values.
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * @param pfnFunction Pointer to the function to call.
a1d83f29ade4c8f9fe95fc75d3fb2642f36081c1vboxsync * @param cArgs Number of arguments following in the ellipsis.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @param Args Variable argument vector.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @remarks Caveats:
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * - Do not pass anything which is larger than an uintptr_t.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * - 64-bit integers are larger than uintptr_t on 32-bit hosts.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Pass integers > 32-bit by reference (pointers).
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * - Don't use NULL since it should be the integer 0 in C++ and may
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * therefore end up with garbage in the bits 63:32 on 64-bit
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * hosts because 'int' is 32-bit.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Use (void *)NULL or (uintptr_t)0 instead of NULL.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsyncRTDECL(int) RTReqCallV(PRTREQQUEUE pQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync LogFlow(("RTReqCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Check input.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (!pfnFunction || !pQueue || (fFlags & ~(RTREQFLAGS_RETURN_MASK | RTREQFLAGS_NO_WAIT)))
c3ad1c4d80999dbb6c9c3e6ff44a35f70566c306vboxsync if (cArgs * sizeof(uintptr_t) > sizeof(pReq->u.Internal.aArgs))
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Allocate request
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync int rc = RTReqAlloc(pQueue, &pReq, RTREQTYPE_INTERNAL);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Initialize the request data.
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync pReq->u.Internal.aArgs[iArg] = va_arg(Args, uintptr_t);
447f830b91e4e0a6702f578f2c0babfd812a5d74vboxsync * Queue the request and return.
da2ac963e5567d049d02bad0ad7783a0b9181637vboxsync LogFlow(("RTReqCallV: returns %Rrc *ppReq=%p\n", rc, pReq));
447f830b91e4e0a6702f578f2c0babfd812a5d74vboxsync * Joins the list pList with whatever is linked up at *pHead.
447f830b91e4e0a6702f578f2c0babfd812a5d74vboxsyncstatic void vmr3ReqJoinFreeSub(volatile PRTREQ *ppHead, PRTREQ pList)
447f830b91e4e0a6702f578f2c0babfd812a5d74vboxsync PRTREQ pHead = (PRTREQ)ASMAtomicXchgPtr((void * volatile *)ppHead, pList);
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync if (ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pHead, pList))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pHead, NULL))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Joins the list pList with whatever is linked up at *pHead.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void vmr3ReqJoinFree(PRTREQQUEUE pQueue, PRTREQ pList)
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync * Split the list if it's too long.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync vmr3ReqJoinFreeSub(&pQueue->apReqFree[(i + 2) % RT_ELEMENTS(pQueue->apReqFree)], pTail->pNext);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync vmr3ReqJoinFreeSub(&pQueue->apReqFree[(i + 2 + (i == pQueue->iReqFree)) % RT_ELEMENTS(pQueue->apReqFree)], pTail->pNext);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync vmr3ReqJoinFreeSub(&pQueue->apReqFree[(pQueue->iReqFree + 2) % RT_ELEMENTS(pQueue->apReqFree)], pList);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Allocates a request packet.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * The caller allocates a request packet, fills in the request data
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * union and queues the request.
1f67f03c498fb10dfaa104a3698a1e149b7e9eb5vboxsync * @returns iprt status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pQueue The request queue.
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync * @param ppReq Where to store the pointer to the allocated packet.
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync * @param enmType Package type.
e17f587595bd5d3a7be56a892e3fd3a0ef83d268vboxsyncRTDECL(int) RTReqAlloc(PRTREQQUEUE pQueue, PRTREQ *ppReq, RTREQTYPE enmType)
1f67f03c498fb10dfaa104a3698a1e149b7e9eb5vboxsync * Validate input.
6a2b7cefae549318ba64aee5d6f40d0aae28f1a3vboxsync AssertMsgFailed(("Invalid package type %d valid range %d-%d inclusivly.\n",
6a2b7cefae549318ba64aee5d6f40d0aae28f1a3vboxsync enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1));
6a2b7cefae549318ba64aee5d6f40d0aae28f1a3vboxsync * Try get a recycled packet.
3c292c68aeb0a95090706381edf33b886c81afd1vboxsync * While this could all be solved with a single list with a lock, it's a sport
3c292c68aeb0a95090706381edf33b886c81afd1vboxsync * of mine to avoid locks.
6a2b7cefae549318ba64aee5d6f40d0aae28f1a3vboxsync while (--cTries >= 0)
1f67f03c498fb10dfaa104a3698a1e149b7e9eb5vboxsync PRTREQ volatile *ppHead = &pQueue->apReqFree[ASMAtomicIncU32(&pQueue->iReqFree) % RT_ELEMENTS(pQueue->apReqFree)];
8809400ad2407593d3471b82d5caf0c24cbcdf8avboxsync#if 0 /* sad, but this won't work safely because the reading of pReq->pNext. */
6a2b7cefae549318ba64aee5d6f40d0aae28f1a3vboxsync && !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (pNext = pReq->pNext), pReq)
960d1f2d42faa8d833309114e5adc46a6a658c27vboxsync && !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (pNext = pReq->pNext), pReq))
960d1f2d42faa8d833309114e5adc46a6a658c27vboxsync PRTREQ pReq = (PRTREQ)ASMAtomicXchgPtr((void * volatile *)ppHead, NULL);
8809400ad2407593d3471b82d5caf0c24cbcdf8avboxsync && !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, pNext, NULL))
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync * Make sure the event sem is not signaled.
09b36b509b761f9ce006fa9c25cb86d12757b937vboxsync * This shall not happen, but if it does we'll just destroy
09b36b509b761f9ce006fa9c25cb86d12757b937vboxsync * the semaphore and create a new one.
09b36b509b761f9ce006fa9c25cb86d12757b937vboxsync AssertMsgFailed(("rc=%Rrc from RTSemEventWait(%#x).\n", rc, pReq->EventSem));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(RTSemEventWait(pReq->EventSem, 0) == VERR_TIMEOUT);
0c5d6027e582baa247e987e184f93d44623e7443vboxsync * Initialize the packet and return it.
0c5d6027e582baa247e987e184f93d44623e7443vboxsync pReq->iStatus = VERR_RT_REQUEST_STATUS_STILL_PENDING;
0c5d6027e582baa247e987e184f93d44623e7443vboxsync LogFlow(("RTReqAlloc: returns VINF_SUCCESS *ppReq=%p recycled\n", pReq));
0c5d6027e582baa247e987e184f93d44623e7443vboxsync * Ok allocate one.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Create the semaphore.
b0d29fd0a868929a608ff72658aac997cc95319avboxsync * Initialize the packet and return it.
b0d29fd0a868929a608ff72658aac997cc95319avboxsync pReq->iStatus = VERR_RT_REQUEST_STATUS_STILL_PENDING;
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync LogFlow(("RTReqAlloc: returns VINF_SUCCESS *ppReq=%p new\n", pReq));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Free a request packet.
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * @returns iprt status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pReq Package to free.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @remark The request packet must be in allocated or completed state!
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * Ignore NULL (all free functions should do this imho).
2da513a7caa29822c9991d7e8615658a194c0cf8vboxsync * Check packet state.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertMsgFailed(("Invalid state %d!\n", pReq->enmState));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Make it a free packet and put it into one of the free packet lists.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PRTREQ volatile *ppHead = &pQueue->apReqFree[ASMAtomicIncU32(&pQueue->iReqFree) % RT_ELEMENTS(pQueue->apReqFree)];
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync ASMAtomicXchgPtr((void * volatile *)&pReq->pNext, pNext);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } while (!ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pReq, (void *)pNext));
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * Queue a request.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The quest must be allocated using RTReqAlloc() and contain
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * all the required data.
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync * If it's disired to poll on the completion of the request set cMillies
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * to 0 and use RTReqWait() to check for completation. In the other case
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * use RT_INDEFINITE_WAIT.
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync * @returns iprt status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Will not return VERR_INTERRUPTED.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync * @param pReq The request to queue.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cMillies Number of milliseconds to wait for the request to
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * be completed. Use RT_INDEFINITE_WAIT to only
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * wait till it's completed.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsyncRTDECL(int) RTReqQueue(PRTREQ pReq, RTMSINTERVAL cMillies)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync LogFlow(("RTReqQueue: pReq=%p cMillies=%d\n", pReq, cMillies));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Verify the supplied package.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertMsgFailed(("Invalid state %d\n", pReq->enmState));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgFailed(("Invalid request package! Anyone cooking their own packages???\n"));
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync AssertMsgFailed(("Invalid package type %d valid range %d-%d inclusivly. This was verified on alloc too...\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1));
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Insert it.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTREQQUEUE pQueue = ((RTREQ volatile *)pReq)->pQueue; /* volatile paranoia */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync unsigned fFlags = ((RTREQ volatile *)pReq)->fFlags; /* volatile paranoia */
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync } while (!ASMAtomicCmpXchgPtr((void * volatile *)&pQueue->pReqs, (void *)pReq, (void *)pNext));
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Notify queue thread.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Wait and return.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Wait for a request to be completed.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @returns iprt status code.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Will not return VERR_INTERRUPTED.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pReq The request to wait for.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @param cMillies Number of milliseconds to wait.
f1f55b6ac890efaabca0ff940f58aa8df1dc84c8vboxsync * Use RT_INDEFINITE_WAIT to only wait till it's completed.
f1f55b6ac890efaabca0ff940f58aa8df1dc84c8vboxsyncRTDECL(int) RTReqWait(PRTREQ pReq, RTMSINTERVAL cMillies)
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync LogFlow(("RTReqWait: pReq=%p cMillies=%d\n", pReq, cMillies));
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Verify the supplied package.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync AssertMsgFailed(("Invalid state %d\n", pReq->enmState));
ce666b71b4eb6477625b0057689a08aaa7c11b64vboxsync AssertMsgFailed(("Invalid request package! Anyone cooking their own packages???\n"));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgFailed(("Invalid package type %d valid range %d-%d inclusivly. This was verified on alloc and queue too...\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1));
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync * Wait on the package.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync rc = RTSemEventWait(pReq->EventSem, RT_INDEFINITE_WAIT);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Process one request.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @returns IPRT status code.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param pReq Request packet to process.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync LogFlow(("rtReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Process the request.
11923fc977be1686f5428c3e790c04d0701a074cvboxsync int rcRet = VINF_SUCCESS; /* the return code of this function. */
11923fc977be1686f5428c3e790c04d0701a074cvboxsync int rcReq = VERR_NOT_IMPLEMENTED; /* the request status. */
11923fc977be1686f5428c3e790c04d0701a074cvboxsync * A packed down call frame.
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn02)(uintptr_t, uintptr_t);
cce0c6096dee0c5353bb74431dc47b05f87a1c6dvboxsync DECLCALLBACKMEMBER(int, pfn03)(uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn04)(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn05)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn06)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn07)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn08)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn09)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn10)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn11)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync DECLCALLBACKMEMBER(int, pfn12)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 2: rcRet = u.pfn02(pauArgs[0], pauArgs[1]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 3: rcRet = u.pfn03(pauArgs[0], pauArgs[1], pauArgs[2]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 4: rcRet = u.pfn04(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 5: rcRet = u.pfn05(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 6: rcRet = u.pfn06(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 7: rcRet = u.pfn07(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 8: rcRet = u.pfn08(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 9: rcRet = u.pfn09(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 10: rcRet = u.pfn10(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 11: rcRet = u.pfn11(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync case 12: rcRet = u.pfn12(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10], pauArgs[11]); break;
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync AssertReleaseMsgFailed(("cArgs=%d\n", pReq->u.Internal.cArgs));
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync#else /* x86: */
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync size_t cbArgs = pReq->u.Internal.cArgs * sizeof(uintptr_t);
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync "subl %2, %%esp\n\t"
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync "andl $0xfffffff0, %%esp\n\t"
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync "shrl $2, %2\n\t"
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync "movl %%esp, %%edi\n\t"
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync "rep movsl\n\t"
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync "movl %%edx, %%edi\n\t"
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync "call *%%eax\n\t"
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync "mov %%edi, %%esp\n\t"
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync#endif /* x86 */
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync if ((pReq->fFlags & (RTREQFLAGS_RETURN_MASK)) == RTREQFLAGS_VOID)
af86e71b7cb472cb35c26e2d78c0152fad35e0e7vboxsync AssertMsgFailed(("pReq->enmType=%d\n", pReq->enmType));
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync * Complete the request.
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync /* Free the packet, nobody is waiting. */
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc - freeing it\n",
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync /* Notify the waiter and him free up the packet. */
06dc6eb95cf33b2b83f0d07c602d1ca20a575663vboxsync LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc - notifying waiting thread\n",
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * Checks if the queue is busy or not.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * The caller is responsible for dealing with any concurrent submitts.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @returns true if busy, false if idle.
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync * @param pQueue The queue.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (ASMAtomicReadPtr((void * volatile *)&pQueue->pReqs) != NULL)
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync return true;
377f1df8d6ec248927bcdf0efabf87ab55c4a615vboxsync return true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return false;