VirtualBox

Changeset 19126 in vbox for trunk/src/VBox/Runtime/r3/linux


Ignore:
Timestamp:
Apr 22, 2009 10:52:02 PM (16 years ago)
Author:
vboxsync
Message:

Runtime/Aio: * Move the validation macros to a new header because they are used in

the other implmenetations as well.

  • Fix two bugs in the linux implementation:
    1. If a request is canceled the request count is not decremented making it impossible to destroy a context.
    2. Fix a race in the wakeup method which could lead to a nil thread handle.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/linux/fileaio-linux.cpp

    r19054 r19126  
    6161#include <iprt/log.h>
    6262#include <iprt/thread.h>
    63 #include "internal/magics.h"
     63#include "internal/fileaio.h"
    6464
    6565#include <linux/aio_abi.h>
     
    159159
    160160/**
    161  * Async I/O request state.
    162  */
    163 typedef struct RTFILEAIOREQINTERNAL
    164 {
    165     /** The aio control block. This must be the FIRST elment in
    166      *  the structure! (see notes below) */
    167     LNXKAIOIOCB     AioCB;
    168     /** The I/O context this request is associated with. */
    169     aio_context_t   AioContext;
    170     /** Return code the request completed with. */
    171     int             Rc;
    172     /** Flag whether the request is in process or not. */
    173     bool            fFinished;
    174     /** Number of bytes actually trasnfered. */
    175     size_t          cbTransfered;
    176     /** Magic value  (RTFILEAIOREQ_MAGIC). */
    177     uint32_t        u32Magic;
    178 } RTFILEAIOREQINTERNAL;
    179 /** Pointer to an internal request structure. */
    180 typedef RTFILEAIOREQINTERNAL *PRTFILEAIOREQINTERNAL;
    181 
    182 /**
    183161 * Async I/O completion context state.
    184162 */
     
    203181typedef RTFILEAIOCTXINTERNAL *PRTFILEAIOCTXINTERNAL;
    204182
     183/**
     184 * Async I/O request state.
     185 */
     186typedef struct RTFILEAIOREQINTERNAL
     187{
     188    /** The aio control block. This must be the FIRST elment in
     189     *  the structure! (see notes below) */
     190    LNXKAIOIOCB           AioCB;
     191    /** The I/O context this request is associated with. */
     192    aio_context_t         AioContext;
     193    /** Return code the request completed with. */
     194    int                   Rc;
     195    /** Flag whether the request is in process or not. */
     196    bool                  fFinished;
     197    /** Number of bytes actually trasnfered. */
     198    size_t                cbTransfered;
     199    /** Completion context we are assigned to. */
     200    PRTFILEAIOCTXINTERNAL pCtxInt;
     201    /** Magic value  (RTFILEAIOREQ_MAGIC). */
     202    uint32_t              u32Magic;
     203} RTFILEAIOREQINTERNAL;
     204/** Pointer to an internal request structure. */
     205typedef RTFILEAIOREQINTERNAL *PRTFILEAIOREQINTERNAL;
     206
    205207
    206208/*******************************************************************************
     
    210212#define AIO_MAXIMUM_REQUESTS_PER_CONTEXT 64
    211213
    212 /** Validates a context handle and returns VERR_INVALID_HANDLE if not valid. */
    213 #define RTFILEAIOREQ_VALID_RETURN_RC(pReq, rc) \
    214     do { \
    215         AssertPtrReturn((pReq), (rc)); \
    216         AssertReturn((pReq)->u32Magic == RTFILEAIOREQ_MAGIC, (rc)); \
    217     } while (0)
    218 
    219 /** Validates a context handle and returns VERR_INVALID_HANDLE if not valid. */
    220 #define RTFILEAIOREQ_VALID_RETURN(pReq) RTFILEAIOREQ_VALID_RETURN_RC((pReq), VERR_INVALID_HANDLE)
    221 
    222 /** Validates a context handle and returns (void) if not valid. */
    223 #define RTFILEAIOREQ_VALID_RETURN_VOID(pReq) \
    224     do { \
    225         AssertPtrReturnVoid(pReq); \
    226         AssertReturnVoid((pReq)->u32Magic == RTFILEAIOREQ_MAGIC); \
    227     } while (0)
    228 
    229 /** Validates a context handle and returns the specified rc if not valid. */
    230 #define RTFILEAIOCTX_VALID_RETURN_RC(pCtx, rc) \
    231     do { \
    232         AssertPtrReturn((pCtx), (rc)); \
    233         AssertReturn((pCtx)->u32Magic == RTFILEAIOCTX_MAGIC, (rc)); \
    234     } while (0)
    235 
    236 /** Validates a context handle and returns VERR_INVALID_HANDLE if not valid. */
    237 #define RTFILEAIOCTX_VALID_RETURN(pCtx) RTFILEAIOCTX_VALID_RETURN_RC((pCtx), VERR_INVALID_HANDLE)
    238 
    239214
    240215/**
     
    300275}
    301276
    302 
    303277RTR3DECL(int) RTFileAioReqCreate(PRTFILEAIOREQ phReq)
    304278{
     
    313287
    314288    pReqInt->fFinished = false;
    315     pReqInt->u32Magic = RTFILEAIOREQ_MAGIC;
     289    pReqInt->pCtxInt   = NULL;
     290    pReqInt->u32Magic  = RTFILEAIOREQ_MAGIC;
    316291
    317292    *phReq = (RTFILEAIOREQ)pReqInt;
     
    367342
    368343    pReqInt->fFinished         = false;
     344    pReqInt->pCtxInt           = NULL;
    369345
    370346    return VINF_SUCCESS;
     
    425401    if (RT_SUCCESS(rc))
    426402    {
    427         /* Examine rc in the event structure. */
     403        /*
     404         * Decrement request count because the request will never arrive at the
     405         * completion port.
     406         */
     407        AssertMsg(VALID_PTR(pReqInt->pCtxInt),
     408                  ("Invalid state. Request was canceled but wasn't submitted\n"));
     409
     410        ASMAtomicDecS32(&pReqInt->pCtxInt->cRequests);
    428411        return VINF_SUCCESS;
    429412    }
     
    528511    AssertPtrReturn(pahReqs, VERR_INVALID_POINTER);
    529512    uint32_t i = cReqs;
     513
     514    /*
     515     * Vaildate requests and associate with the context.
     516     */
    530517    while (i-- > 0)
    531518    {
    532519        PRTFILEAIOREQINTERNAL pReqInt = pahReqs[i];
    533520        RTFILEAIOREQ_VALID_RETURN(pReqInt);
     521
     522        pReqInt->AioContext = pCtxInt->AioContext;
     523        pReqInt->pCtxInt    = pCtxInt;
    534524    }
    535525
    536526    /*
    537      * Add descriptive comment.
    538      */
    539     /** @todo r=bird: Why this particular order?
    540      *  Perhaps combine the AioContext initialization with the validation? */
     527     * Add the submitted requests to the counter
     528     * to prevent destroying the context while
     529     * it is still used.
     530     */
    541531    ASMAtomicAddS32(&pCtxInt->cRequests, cReqs);
    542 
    543     for (unsigned i = 0; i < cReqs; i++)
    544     {
    545         PRTFILEAIOREQINTERNAL pReqInt = pahReqs[i];
    546         pReqInt->AioContext = pCtxInt->AioContext;
    547     }
    548532
    549533    /*
     
    600584    /* For the wakeup call. */
    601585    Assert(pCtxInt->hThreadWait == NIL_RTTHREAD);
    602     pCtxInt->hThreadWait = RTThreadSelf();
     586    ASMAtomicWriteHandle(&pCtxInt->hThreadWait, RTThreadSelf());
    603587
    604588    /*
     
    683667    ASMAtomicSubS32(&pCtxInt->cRequests, cRequestsCompleted);
    684668    Assert(pCtxInt->hThreadWait == RTThreadSelf());
    685     pCtxInt->hThreadWait = NIL_RTTHREAD;
     669    ASMAtomicWriteHandle(&pCtxInt->hThreadWait, NIL_RTTHREAD);
    686670
    687671    /*
     
    707691     *        this function. */
    708692
    709     bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUp, true);
     693    bool fWokenUp    = ASMAtomicXchgBool(&pCtxInt->fWokenUp, true);
     694
     695    /*
     696     * Read the thread handle before the status flag.
     697     * If we read the handle after the flag we might
     698     * end up with an invalid handle because the thread
     699     * waiting in RTFileAioCtxWakeup() might get scheduled
     700     * before we read the flag and returns.
     701     * We can ensure that the handle is valid if fWaiting is true
     702     * when reading the handle before the status flag.
     703     */
     704    RTTHREAD hThread;
     705    ASMAtomicReadHandle(&pCtxInt->hThreadWait, &hThread);
     706    bool fWaiting    = ASMAtomicReadBool(&pCtxInt->fWaiting);
    710707    if (    !fWokenUp
    711         &&  pCtxInt->fWaiting)
    712         RTThreadPoke(pCtxInt->hThreadWait);
     708        &&  fWaiting)
     709    {
     710        /*
     711         * If a thread waits the handle must be valid.
     712         * It is possible that the thread returns from
     713         * rtFileAsyncIoLinuxGetEvents() before the signal
     714         * is send.
     715         * This is no problem because we already set fWokenUp
     716         * to true which will let the thread return VERR_INTERRUPTED
     717         * and the next call to RTFileAioCtxWait() will not
     718         * return VERR_INTERRUPTED because signals are not saved
     719         * and will simply vanish if the destination thread can't
     720         * receive it.
     721         */
     722        Assert(hThread != NIL_RTTHREAD);
     723        RTThreadPoke(hThread);
     724    }
    713725
    714726    return VINF_SUCCESS;
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