VirtualBox

Changeset 39500 in vbox


Ignore:
Timestamp:
Dec 1, 2011 8:26:48 PM (13 years ago)
Author:
vboxsync
Message:

RTReq: More refactoring.

Location:
trunk
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/req.h

    r39498 r39500  
    109109typedef struct RTREQ
    110110{
     111    /** Magic number (RTREQ_MAGIC). */
     112    uint32_t                u32Magic;
     113    /** Set if the event semaphore is clear. */
     114    volatile bool           fEventSemClear;
     115    /** Set if pool, clear if queue. */
     116    volatile bool           fPoolOrQueue;
     117    /** IPRT status code for the completed request. */
     118    volatile int32_t        iStatus;
     119    /** Request state. */
     120    volatile RTREQSTATE     enmState;
     121
    111122    /** Pointer to the next request in the chain. */
    112123    struct RTREQ * volatile pNext;
    113     /** Pointer to the queue this packet belongs to. */
    114     RTREQQUEUE              hQueue;
    115     /** Request state. */
    116     volatile RTREQSTATE     enmState;
    117     /** iprt status code for the completed request. */
    118     volatile int            iStatus;
     124
     125    union
     126    {
     127        /** Pointer to the pool this packet belongs to. */
     128        RTREQPOOL           hPool;
     129        /** Pointer to the queue this packet belongs to. */
     130        RTREQQUEUE          hQueue;
     131    } uOwner;
     132
    119133    /** Requester event sem.
    120134     * The request can use this event semaphore to wait/poll for completion
     
    122136     */
    123137    RTSEMEVENT              EventSem;
    124     /** Set if the event semaphore is clear. */
    125     volatile bool           fEventSemClear;
    126138    /** Flags, RTREQ_FLAGS_*. */
    127     unsigned                fFlags;
     139    uint32_t                fFlags;
    128140    /** Request type. */
    129141    RTREQTYPE               enmType;
     
    137149            PFNRT               pfn;
    138150            /** Number of arguments. */
    139             unsigned            cArgs;
     151            uint32_t            cArgs;
    140152            /** Array of arguments. */
    141153            uintptr_t           aArgs[64];
  • trunk/src/VBox/Runtime/Makefile.kmk

    r39448 r39500  
    321321        common/misc/once.cpp \
    322322        common/misc/req.cpp \
     323        common/misc/reqpool.cpp \
     324        common/misc/reqqueue.cpp \
    323325        common/misc/sanity-c.c \
    324326        common/misc/sanity-cpp.cpp \
  • trunk/src/VBox/Runtime/common/misc/req.cpp

    r39498 r39500  
    55
    66/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4242
    4343#include "internal/req.h"
     44#include "internal/magics.h"
    4445
    4546
     
    4748*   Internal Functions                                                         *
    4849*******************************************************************************/
    49 static int  rtReqProcessOne(PRTREQ pReq);
    50 
    51 
    52 
    53 RTDECL(int) RTReqQueueCreate(RTREQQUEUE *phQueue)
    54 {
    55     PRTREQQUEUEINT pQueue = (PRTREQQUEUEINT)RTMemAllocZ(sizeof(RTREQQUEUEINT));
    56     if (!pQueue)
    57         return VERR_NO_MEMORY;
    58     int rc = RTSemEventCreate(&pQueue->EventSem);
    59     if (RT_SUCCESS(rc))
    60     {
    61         *phQueue = pQueue;
    62         return VINF_SUCCESS;
    63     }
    64 
    65     RTMemFree(pQueue);
    66     return rc;
    67 }
    68 RT_EXPORT_SYMBOL(RTReqQueueCreate);
    69 
    70 
    71 RTDECL(int) RTReqQueueDestroy(RTREQQUEUE hQueue)
    72 {
    73     /*
    74      * Check input.
    75      */
    76     if (hQueue == NIL_RTREQQUEUE)
    77         return VINF_SUCCESS;
    78     PRTREQQUEUEINT pQueue = hQueue;
    79     AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
    80 
    81     RTSemEventDestroy(pQueue->EventSem);
    82     pQueue->EventSem = NIL_RTSEMEVENT;
    83     RTMemFree(pQueue);
    84     return VINF_SUCCESS;
    85 }
    86 RT_EXPORT_SYMBOL(RTReqQueueDestroy);
    87 
    88 
    89 RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies)
    90 {
    91     LogFlow(("RTReqProcess %x\n", hQueue));
    92 
    93     /*
    94      * Check input.
    95      */
    96     PRTREQQUEUEINT pQueue = hQueue;
    97     AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
    98 
    99     /*
    100      * Process loop.
    101      *
    102      * We do not repeat the outer loop if we've got an informational status code
    103      * since that code needs processing by our caller.
    104      */
    105     int rc = VINF_SUCCESS;
    106     while (rc <= VINF_SUCCESS)
    107     {
    108         /*
    109          * Get pending requests.
    110          */
    111         PRTREQ pReqs = ASMAtomicXchgPtrT(&pQueue->pReqs, NULL, PRTREQ);
    112         if (!pReqs)
    113         {
    114             ASMAtomicWriteBool(&pQueue->fBusy, false); /* this aint 100% perfect, but it's good enough for now... */
    115             /** @todo We currently don't care if the entire time wasted here is larger than
    116              *        cMillies */
    117             rc = RTSemEventWait(pQueue->EventSem, cMillies);
    118             if (rc != VINF_SUCCESS)
    119                 break;
    120             continue;
    121         }
    122         ASMAtomicWriteBool(&pQueue->fBusy, true);
    123 
    124         /*
    125          * Reverse the list to process it in FIFO order.
    126          */
    127         PRTREQ pReq = pReqs;
    128         if (pReq->pNext)
    129             Log2(("RTReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
    130         pReqs = NULL;
    131         while (pReq)
    132         {
    133             Assert(pReq->enmState == RTREQSTATE_QUEUED);
    134             Assert(pReq->hQueue == pQueue);
    135             PRTREQ pCur = pReq;
    136             pReq = pReq->pNext;
    137             pCur->pNext = pReqs;
    138             pReqs = pCur;
    139         }
    140 
    141 
    142         /*
    143          * Process the requests.
    144          */
    145         while (pReqs)
    146         {
    147             /* Unchain the first request and advance the list. */
    148             pReq = pReqs;
    149             pReqs = pReqs->pNext;
    150             pReq->pNext = NULL;
    151 
    152             /* Process the request */
    153             rc = rtReqProcessOne(pReq);
    154             AssertRC(rc);
    155             if (rc != VINF_SUCCESS)
    156                 break; /** @todo r=bird: we're dropping requests here! Add 2nd queue that can hold them. (will fix when writing a testcase)  */
    157         }
    158     }
    159 
    160     LogFlow(("RTReqProcess: returns %Rrc\n", rc));
    161     return rc;
    162 }
    163 RT_EXPORT_SYMBOL(RTReqQueueProcess);
    164 
    165 
    166 RTDECL(int) RTReqQueueCall(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
    167 {
    168     va_list va;
    169     va_start(va, cArgs);
    170     int rc = RTReqQueueCallV(hQueue, ppReq, cMillies, RTREQFLAGS_IPRT_STATUS, pfnFunction, cArgs, va);
    171     va_end(va);
    172     return rc;
    173 }
    174 RT_EXPORT_SYMBOL(RTReqQueueCall);
    175 
    176 
    177 RTDECL(int) RTReqQueueCallVoid(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
    178 {
    179     va_list va;
    180     va_start(va, cArgs);
    181     int rc = RTReqQueueCallV(hQueue, ppReq, cMillies, RTREQFLAGS_VOID, pfnFunction, cArgs, va);
    182     va_end(va);
    183     return rc;
    184 }
    185 RT_EXPORT_SYMBOL(RTReqQueueCallVoid);
    186 
    187 
    188 RTDECL(int) RTReqQueueCallEx(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
    189 {
    190     va_list va;
    191     va_start(va, cArgs);
    192     int rc = RTReqQueueCallV(hQueue, ppReq, cMillies, fFlags, pfnFunction, cArgs, va);
    193     va_end(va);
    194     return rc;
    195 }
    196 RT_EXPORT_SYMBOL(RTReqQueueCallEx);
    197 
    198 
    199 RTDECL(int) RTReqQueueCallV(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
    200 {
    201     LogFlow(("RTReqCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs));
    202 
    203     /*
    204      * Check input.
    205      */
    206     PRTREQQUEUEINT pQueue = hQueue;
    207     AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
    208     AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
    209     AssertReturn(!(fFlags & ~(RTREQFLAGS_RETURN_MASK | RTREQFLAGS_NO_WAIT)), VERR_INVALID_PARAMETER);
    210 
    211     if (!(fFlags & RTREQFLAGS_NO_WAIT) || ppReq)
    212     {
    213         AssertPtrReturn(ppReq, VERR_INVALID_POINTER);
    214         *ppReq = NULL;
    215     }
    216 
    217     PRTREQ pReq = NULL;
    218     AssertMsgReturn(cArgs * sizeof(uintptr_t) <= sizeof(pReq->u.Internal.aArgs), ("cArgs=%u\n", cArgs), VERR_TOO_MUCH_DATA);
    219 
    220     /*
    221      * Allocate request
    222      */
    223     int rc = RTReqQueueAlloc(pQueue, &pReq, RTREQTYPE_INTERNAL);
    224     if (rc != VINF_SUCCESS)
    225         return rc;
    226 
    227     /*
    228      * Initialize the request data.
    229      */
    230     pReq->fFlags         = fFlags;
    231     pReq->u.Internal.pfn = pfnFunction;
    232     pReq->u.Internal.cArgs = cArgs;
    233     for (unsigned iArg = 0; iArg < cArgs; iArg++)
    234         pReq->u.Internal.aArgs[iArg] = va_arg(Args, uintptr_t);
    235 
    236     /*
    237      * Queue the request and return.
    238      */
    239     rc = RTReqSubmit(pReq, cMillies);
    240     if (   rc != VINF_SUCCESS
    241         && rc != VERR_TIMEOUT)
    242     {
    243         RTReqFree(pReq);
    244         pReq = NULL;
    245     }
    246     if (!(fFlags & RTREQFLAGS_NO_WAIT))
    247     {
    248         *ppReq = pReq;
    249         LogFlow(("RTReqCallV: returns %Rrc *ppReq=%p\n", rc, pReq));
    250     }
    251     else
    252         LogFlow(("RTReqCallV: returns %Rrc\n", rc));
    253     Assert(rc != VERR_INTERRUPTED);
    254     return rc;
    255 }
    256 RT_EXPORT_SYMBOL(RTReqQueueCallV);
    257 
    258 
    259 RTDECL(bool) RTReqQueueIsBusy(RTREQQUEUE hQueue)
    260 {
    261     PRTREQQUEUEINT pQueue = hQueue;
    262     AssertPtrReturn(pQueue, false);
    263 
    264     if (ASMAtomicReadBool(&pQueue->fBusy))
    265         return true;
    266     if (ASMAtomicReadPtrT(&pQueue->pReqs, PRTREQ) != NULL)
    267         return true;
    268     if (ASMAtomicReadBool(&pQueue->fBusy))
    269         return true;
    270     return false;
    271 }
    272 RT_EXPORT_SYMBOL(RTReqQueueIsBusy);
    273 
    274 
    275 /**
    276  * Joins the list pList with whatever is linked up at *pHead.
    277  */
    278 static void vmr3ReqJoinFreeSub(volatile PRTREQ *ppHead, PRTREQ pList)
    279 {
    280     for (unsigned cIterations = 0;; cIterations++)
    281     {
    282         PRTREQ pHead = ASMAtomicXchgPtrT(ppHead, pList, PRTREQ);
    283         if (!pHead)
    284             return;
    285         PRTREQ pTail = pHead;
    286         while (pTail->pNext)
    287             pTail = pTail->pNext;
    288         pTail->pNext = pList;
    289         if (ASMAtomicCmpXchgPtr(ppHead, pHead, pList))
    290             return;
    291         pTail->pNext = NULL;
    292         if (ASMAtomicCmpXchgPtr(ppHead, pHead, NULL))
    293             return;
    294         pList = pHead;
    295         Assert(cIterations != 32);
    296         Assert(cIterations != 64);
    297     }
    298 }
    299 
    300 
    301 /**
    302  * Joins the list pList with whatever is linked up at *pHead.
    303  */
    304 static void vmr3ReqJoinFree(PRTREQQUEUEINT pQueue, PRTREQ pList)
    305 {
    306     /*
    307      * Split the list if it's too long.
    308      */
    309     unsigned cReqs = 1;
    310     PRTREQ pTail = pList;
    311     while (pTail->pNext)
    312     {
    313         if (cReqs++ > 25)
    314         {
    315             const uint32_t i = pQueue->iReqFree;
    316             vmr3ReqJoinFreeSub(&pQueue->apReqFree[(i + 2) % RT_ELEMENTS(pQueue->apReqFree)], pTail->pNext);
    317 
    318             pTail->pNext = NULL;
    319             vmr3ReqJoinFreeSub(&pQueue->apReqFree[(i + 2 + (i == pQueue->iReqFree)) % RT_ELEMENTS(pQueue->apReqFree)], pTail->pNext);
    320             return;
    321         }
    322         pTail = pTail->pNext;
    323     }
    324     vmr3ReqJoinFreeSub(&pQueue->apReqFree[(pQueue->iReqFree + 2) % RT_ELEMENTS(pQueue->apReqFree)], pList);
    325 }
    326 
    327 
    328 RTDECL(int) RTReqQueueAlloc(RTREQQUEUE hQueue, PRTREQ *ppReq, RTREQTYPE enmType)
    329 {
    330     /*
    331      * Validate input.
    332      */
    333     PRTREQQUEUEINT pQueue = hQueue;
    334     AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
    335     AssertMsgReturn(enmType > RTREQTYPE_INVALID && enmType < RTREQTYPE_MAX, ("%d\n", enmType), VERR_RT_REQUEST_INVALID_TYPE);
    336 
    337     /*
    338      * Try get a recycled packet.
    339      * While this could all be solved with a single list with a lock, it's a sport
    340      * of mine to avoid locks.
    341      */
    342     int cTries = RT_ELEMENTS(pQueue->apReqFree) * 2;
    343     while (--cTries >= 0)
    344     {
    345         PRTREQ volatile *ppHead = &pQueue->apReqFree[ASMAtomicIncU32(&pQueue->iReqFree) % RT_ELEMENTS(pQueue->apReqFree)];
    346 #if 0 /* sad, but this won't work safely because the reading of pReq->pNext. */
    347         PRTREQ pNext = NULL;
    348         PRTREQ pReq = *ppHead;
    349         if (    pReq
    350             &&  !ASMAtomicCmpXchgPtr(ppHead, (pNext = pReq->pNext), pReq)
    351             &&  (pReq = *ppHead)
    352             &&  !ASMAtomicCmpXchgPtr(ppHead, (pNext = pReq->pNext), pReq))
    353             pReq = NULL;
    354         if (pReq)
    355         {
    356             Assert(pReq->pNext == pNext); NOREF(pReq);
    357 #else
    358         PRTREQ pReq = ASMAtomicXchgPtrT(ppHead, NULL, PRTREQ);
    359         if (pReq)
    360         {
    361             PRTREQ pNext = pReq->pNext;
    362             if (    pNext
    363                 &&  !ASMAtomicCmpXchgPtr(ppHead, pNext, NULL))
    364             {
    365                 vmr3ReqJoinFree(pQueue, pReq->pNext);
    366             }
    367 #endif
    368             ASMAtomicDecU32(&pQueue->cReqFree);
    369 
    370             /*
    371              * Make sure the event sem is not signaled.
    372              */
    373             if (!pReq->fEventSemClear)
    374             {
    375                 int rc = RTSemEventWait(pReq->EventSem, 0);
    376                 if (rc != VINF_SUCCESS && rc != VERR_TIMEOUT)
    377                 {
    378                     /*
    379                      * This shall not happen, but if it does we'll just destroy
    380                      * the semaphore and create a new one.
    381                      */
    382                     AssertMsgFailed(("rc=%Rrc from RTSemEventWait(%#x).\n", rc, pReq->EventSem));
    383                     RTSemEventDestroy(pReq->EventSem);
    384                     rc = RTSemEventCreate(&pReq->EventSem);
    385                     AssertRC(rc);
    386                     if (rc != VINF_SUCCESS)
    387                         return rc;
    388                 }
    389                 pReq->fEventSemClear = true;
    390             }
    391             else
    392                 Assert(RTSemEventWait(pReq->EventSem, 0) == VERR_TIMEOUT);
    393 
    394             /*
    395              * Initialize the packet and return it.
    396              */
    397             Assert(pReq->enmType == RTREQTYPE_INVALID);
    398             Assert(pReq->enmState == RTREQSTATE_FREE);
    399             Assert(pReq->hQueue == pQueue);
    400             ASMAtomicXchgSize(&pReq->pNext, NULL);
    401             pReq->enmState = RTREQSTATE_ALLOCATED;
    402             pReq->iStatus  = VERR_RT_REQUEST_STATUS_STILL_PENDING;
    403             pReq->fFlags   = RTREQFLAGS_IPRT_STATUS;
    404             pReq->enmType  = enmType;
    405 
    406             *ppReq = pReq;
    407             LogFlow(("RTReqAlloc: returns VINF_SUCCESS *ppReq=%p recycled\n", pReq));
    408             return VINF_SUCCESS;
    409         }
    410     }
    411 
    412     /*
    413      * Ok allocate one.
    414      */
    415     PRTREQ pReq = (PRTREQ)RTMemAllocZ(sizeof(*pReq));
    416     if (!pReq)
    417         return VERR_NO_MEMORY;
    418 
    419     /*
    420      * Create the semaphore.
    421      */
    422     int rc = RTSemEventCreate(&pReq->EventSem);
    423     AssertRC(rc);
    424     if (rc != VINF_SUCCESS)
    425     {
    426         RTMemFree(pReq);
    427         return rc;
    428     }
    429 
    430     /*
    431      * Initialize the packet and return it.
    432      */
    433     pReq->pNext    = NULL;
    434     pReq->hQueue   = pQueue;
    435     pReq->enmState = RTREQSTATE_ALLOCATED;
    436     pReq->iStatus  = VERR_RT_REQUEST_STATUS_STILL_PENDING;
    437     pReq->fEventSemClear = true;
    438     pReq->fFlags   = RTREQFLAGS_IPRT_STATUS;
    439     pReq->enmType  = enmType;
    440 
    441     *ppReq = pReq;
    442     LogFlow(("RTReqAlloc: returns VINF_SUCCESS *ppReq=%p new\n", pReq));
    443     return VINF_SUCCESS;
    444 }
    445 RT_EXPORT_SYMBOL(RTReqQueueAlloc);
     50
    44651
    44752
     
    45358    if (!pReq)
    45459        return VINF_SUCCESS;
    455 
     60    AssertPtrReturn(pReq, VERR_INVALID_POINTER);
     61    AssertReturn(pReq->u32Magic == RTREQ_MAGIC, VERR_INVALID_PARAMETER);
    45662
    45763    /*
     
    47581    pReq->enmType  = RTREQTYPE_INVALID;
    47682
    477     PRTREQQUEUEINT pQueue = pReq->hQueue;
     83    PRTREQQUEUEINT pQueue = pReq->uOwner.hQueue;
    47884    if (pQueue->cReqFree < 128)
    47985    {
     
    508114        return VERR_RT_REQUEST_STATE;
    509115    }
    510     if (   !pReq->hQueue
     116    if (   !pReq->uOwner.hQueue
    511117        ||  pReq->pNext
    512118        ||  !pReq->EventSem)
     
    527133     * Insert it.
    528134     */
    529     PRTREQQUEUEINT pQueue = ((RTREQ volatile *)pReq)->hQueue;              /* volatile paranoia */
     135    PRTREQQUEUEINT pQueue = ((RTREQ volatile *)pReq)->uOwner.hQueue;       /* volatile paranoia */
    530136    unsigned fFlags = ((RTREQ volatile *)pReq)->fFlags;                    /* volatile paranoia */
    531137    pReq->enmState = RTREQSTATE_QUEUED;
     
    568174        return VERR_RT_REQUEST_STATE;
    569175    }
    570     if (    !pReq->hQueue
     176    if (    !pReq->uOwner.hQueue
    571177        ||  !pReq->EventSem)
    572178    {
     
    614220 * @param   pReq        Request packet to process.
    615221 */
    616 static int rtReqProcessOne(PRTREQ pReq)
     222DECLHIDDEN(int) rtReqProcessOne(PRTREQ pReq)
    617223{
    618224    LogFlow(("rtReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags));
  • trunk/src/VBox/Runtime/include/internal/magics.h

    r37396 r39500  
    111111/** RTRANDINT::u32Magic. (Alan Moore) */
    112112#define RTRANDINT_MAGIC                 UINT32_C(0x19531118)
     113/** The value of RTREQ::u32Magic. */
     114#define RTREQ_MAGIC                     UINT32_C(0xfeed0001) /**< @todo find a value */
     115/** The value of RTREQ::u32Magic of a freed request. */
     116#define RTREQ_MAGIC_DEAD                (~RTREQ_MAGIC)
     117/** The value of RTREQPOOLINT::u32Magic. */
     118#define RTREQPOOL_MAGIC                 UINT32_C(0xfeed0002)/**< @todo find a value */
     119/** The value of RTREQPOOLINT::u32Magic after destruction. */
     120#define RTREQPOOL_MAGIC_DEAD           (~RTREQPOOL_MAGIC)
     121/** The value of RTREQQUEUEINT::u32Magic. */
     122#define RTREQQUEUE_MAGIC                UINT32_C(0xfeed0003)/**< @todo find a value */
     123/** The value of RTREQQUEUEINT::u32Magic after destruction. */
     124#define RTREQQUEUE_MAGIC_DEAD           (~RTREQQUEUE_MAGIC)
    113125/** The value of RTS3::u32Magic. (Edgar Wallace) */
    114126#define RTS3_MAGIC                      UINT32_C(0x18750401)
  • trunk/src/VBox/Runtime/include/internal/req.h

    r39499 r39500  
    3737typedef struct RTREQQUEUEINT
    3838{
    39     /** @todo magic  */
     39    /** Magic value (RTREQQUEUE_MAGIC). */
     40    uint32_t                u32Magic;
     41    /** Set if busy (pending or processing requests). */
     42    bool volatile           fBusy;
    4043    /** Head of the request queue. Atomic. */
    4144    volatile PRTREQ         pReqs;
     
    5053     */
    5154    RTSEMEVENT              EventSem;
    52     /** Set if busy (pending or processing requests). */
    53     bool volatile           fBusy;
    5455} RTREQQUEUEINT;
    5556
     
    5859
    5960
     61
     62DECLHIDDEN(int) rtReqProcessOne(PRTREQ pReq);
     63
    6064RT_C_DECLS_END
    6165
Note: See TracChangeset for help on using the changeset viewer.

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