VirtualBox

Changeset 28436 in vbox


Ignore:
Timestamp:
Apr 17, 2010 9:40:51 PM (15 years ago)
Author:
vboxsync
Message:

IPRT: Reimplemented RTSemMutex for ring-0 linux - untested.

Location:
trunk/src/VBox/Runtime/r0drv/linux
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c

    r25724 r28436  
    55
    66/*
    7  * Copyright (C) 2006-2007 Sun Microsystems, Inc.
     7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3636#include "internal/iprt.h"
    3737#include <iprt/semaphore.h>
    38 #include <iprt/alloc.h>
     38
    3939#include <iprt/assert.h>
    4040#include <iprt/asm.h>
     41#include <iprt/mem.h>
    4142#include <iprt/err.h>
     43#include <iprt/list.h>
    4244
    4345#include "internal/magics.h"
     
    4749*   Structures and Typedefs                                                    *
    4850*******************************************************************************/
     51typedef struct RTSEMMUTEXLNXWAITER
     52{
     53    /** The list entry. */
     54    RTLISTNODE                  ListEntry;
     55    /** The waiting task. */
     56    struct task_struct         *pTask;
     57    /** Why did we wake up? */
     58    enum
     59    {
     60        /** Wakeup to take the semaphore. */
     61        RTSEMMUTEXLNXWAITER_WAKEUP,
     62        /** Mutex is being destroyed. */
     63        RTSEMMUTEXLNXWAITER_DESTROYED,
     64        /** Some other reason. */
     65        RTSEMMUTEXLNXWAITER_OTHER
     66    } volatile                  enmReason;
     67} RTSEMMUTEXLNXWAITER, *PRTSEMMUTEXLNXWAITER;
     68
    4969/**
    50  * Linux mutex semaphore.
     70 * Wrapper for the linux semaphore structure.
    5171 */
    5272typedef struct RTSEMMUTEXINTERNAL
    5373{
    5474    /** Magic value (RTSEMMUTEX_MAGIC). */
    55     uint32_t volatile   u32Magic;
    56     /** Number of recursive locks - 0 if not owned by anyone, > 0 if owned. */
    57     uint32_t volatile   cRecursion;
    58     /** The wait queue. */
    59     wait_queue_head_t   Head;
    60     /** The current owner. */
    61     void * volatile     pOwner;
     75    uint32_t                    u32Magic;
     76    /** The number of recursions. */
     77    uint32_t                    cRecursions;
     78    /** The list of waiting threads. */
     79    RTLISTNODE                  WaiterList;
     80    /** The current owner, NULL if none. */
     81    struct task_struct         *pOwnerTask;
     82    /** The number of references to this piece of memory.  This is used to
     83     *  prevent it from being kicked from underneath us while waiting. */
     84    uint32_t volatile           cRefs;
     85    /** The spinlock protecting the members and falling asleep. */
     86    spinlock_t                  Spinlock;
    6287} RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
    6388
    6489
    65 
    66 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
    67 {
    68     return RTSemMutexCreateEx(phMutexSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
    69 }
    70 
    71 
    72 RTDECL(int)  RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
    73                                 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
    74 {
     90RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMtx)
     91{
     92    /*
     93     * Allocate.
     94     */
    7595    PRTSEMMUTEXINTERNAL pThis;
    76 
    77     AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
    78 
    7996    pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
    80     if (pThis)
    81     {
    82         pThis->u32Magic   = RTSEMMUTEX_MAGIC;
    83         pThis->cRecursion = 0;
    84         pThis->pOwner     = NULL;
    85         init_waitqueue_head(&pThis->Head);
    86 
    87         *phMutexSem = pThis;
    88 AssertReleaseMsgFailed(("This mutex implementation is buggy, fix it!\n"));
    89         return VINF_SUCCESS;
    90     }
    91     return VERR_NO_MEMORY;
     97    if (!pThis)
     98        return VERR_NO_MEMORY;
     99
     100    /*
     101     * Initialize.
     102     */
     103    pThis->u32Magic     = RTSEMMUTEX_MAGIC;
     104    pThis->cRecursions  = 0;
     105    pThis->pOwnerTask   = NULL;
     106    pThis->cRefs        = 1;
     107    RTListInit(&pThis->WaiterList);
     108    spin_lock_init(&pThis->Spinlock);
     109
     110    *phMtx = pThis;
     111    return VINF_SUCCESS;
    92112}
    93113RT_EXPORT_SYMBOL(RTSemMutexCreate);
    94114
    95115
    96 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
    97 {
    98     /*
    99      * Validate input.
    100      */
    101     PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
     116RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMtx)
     117{
     118    PRTSEMMUTEXINTERNAL     pThis = hMtx;
     119    PRTSEMMUTEXLNXWAITER    pCur;
     120    unsigned long           fSavedIrq;
     121
     122    /*
     123     * Validate.
     124     */
    102125    if (pThis == NIL_RTSEMMUTEX)
    103126        return VINF_SUCCESS;
    104127    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    105     AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
    106 
    107     /*
    108      * Invalidate it and signal the object just in case.
     128    AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
     129
     130    /*
     131     * Kill it, kick waiters and release it.
    109132     */
    110133    AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
    111     ASMAtomicWriteU32(&pThis->cRecursion, 0);
    112     Assert(!waitqueue_active(&pThis->Head));
    113     wake_up_all(&pThis->Head);
    114 
    115     RTMemFree(pThis);
     134
     135    spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
     136    RTListForEach(&pThis->WaiterList, pCur, RTSEMMUTEXLNXWAITER, ListEntry)
     137    {
     138        pCur->enmReason = RTSEMMUTEXLNXWAITER_DESTROYED;
     139        wake_up_process(pCur->pTask);
     140    }
     141
     142    if (ASMAtomicDecU32(&pThis->cRefs) != 0)
     143        spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
     144    else
     145    {
     146        spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
     147        RTMemFree(pThis);
     148    }
     149
    116150    return VINF_SUCCESS;
    117151}
     
    119153
    120154
     155/**
     156 * Worker for rtSemMutexLinuxRequest that handles the case where we go to sleep.
     157 *
     158 * @returns VINF_SUCCESS, VERR_INTERRUPTED, VERR_TIMEOUT or VERR_SEM_DESTROYED.
     159 *          Returns without owning the spinlock.
     160 * @param   pThis           The mutex instance.
     161 * @param   cMillies        The timeout.
     162 * @param   fInterruptible  The wait type.
     163 * @param   fSavedIrq       The saved IRQ flags.
     164 */
     165static int rtSemMutexLinuxRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL cMillies,
     166                                       bool fInterruptible, unsigned long fSavedIrq)
     167{
     168    struct task_struct *pSelf    = current;
     169    int                 rc       = VERR_TIMEOUT;
     170    long                lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
     171    RTSEMMUTEXLNXWAITER Waiter;
     172
     173    IPRT_DEBUG_SEMS_STATE(pThis, 'm');
     174
     175    /*
     176     * Grab a reference to the mutex and add ourselves to the waiter list.
     177     */
     178    ASMAtomicIncU32(&pThis->cRefs);
     179
     180    Waiter.pTask     = pSelf;
     181    Waiter.enmReason = RTSEMMUTEXLNXWAITER_OTHER;
     182    RTListAppend(&pThis->WaiterList, &Waiter.ListEntry);
     183
     184    /*
     185     * Do the waiting.
     186     */
     187    for (;;)
     188    {
     189        /* Check signal and timeout conditions. */
     190        if (    fInterruptible
     191            &&  signal_pending(pSelf))
     192        {
     193            rc = VERR_INTERRUPTED;
     194            break;
     195        }
     196
     197        if (!lTimeout)
     198            break;
     199
     200        /* Go to sleep. */
     201        set_task_state(pSelf, fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
     202        spin_unlock_irq(&pThis->Spinlock);
     203
     204        lTimeout = schedule_timeout(lTimeout);
     205
     206        spin_lock_irq(&pThis->Spinlock);
     207        set_current_state(TASK_RUNNING);
     208
     209        /* Did someone wake us up? */
     210        if (Waiter.enmReason == RTSEMMUTEXLNXWAITER_WAKEUP)
     211        {
     212            Assert(pThis->cRecursions == 0);
     213            pThis->cRecursions = 1;
     214            pThis->pOwnerTask  = NULL;
     215            rc = VINF_SUCCESS;
     216            break;
     217        }
     218
     219        /* Is the mutex being destroyed? */
     220        if (RT_UNLIKELY(   Waiter.enmReason == RTSEMMUTEXLNXWAITER_DESTROYED
     221                        || pThis->u32Magic != RTSEMMUTEX_MAGIC))
     222        {
     223            rc = VERR_SEM_DESTROYED;
     224            break;
     225        }
     226    }
     227
     228    /*
     229     * Unlink ourself from the waiter list, dereference the mutex and exit the
     230     * lock.  We might have to free the mutex if it was the destroyed.
     231     */
     232    RTListNodeRemove(&Waiter.ListEntry);
     233    IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc);
     234
     235    if (RT_LIKELY(ASMAtomicDecU32(&pThis->cRefs) != 0))
     236        spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
     237    else
     238    {
     239        Assert(RT_FAILURE_NP(rc));
     240        spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
     241        RTMemFree(pThis);
     242    }
     243    return rc;
     244}
     245
     246
     247/**
     248 * Internal worker.
     249 */
     250DECLINLINE(int) rtSemMutexLinuxRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, bool fInterruptible)
     251{
     252    PRTSEMMUTEXINTERNAL pThis = hMutexSem;
     253    struct task_struct *pSelf = current;
     254    unsigned long       fSavedIrq;
     255    int                 rc;
     256
     257    /*
     258     * Validate.
     259     */
     260    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     261    AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
     262    Assert(pThis->cRefs >= 1);
     263
     264    /*
     265     * Lock it and check if it's a recursion.
     266     */
     267    spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
     268    if (pThis->pOwnerTask == pSelf)
     269    {
     270        pThis->cRecursions++;
     271        Assert(pThis->cRecursions > 1);
     272        Assert(pThis->cRecursions < 256);
     273        rc = VINF_SUCCESS;
     274    }
     275    /*
     276     * Not a recursion, maybe it's not owned by anyone then?
     277     */
     278    else if (pThis->pOwnerTask == NULL)
     279    {
     280        Assert(pThis->cRecursions == 0);
     281        pThis->cRecursions = 1;
     282        pThis->pOwnerTask  = pSelf;
     283        rc = VINF_SUCCESS;
     284    }
     285    /*
     286     * Was it a polling call?
     287     */
     288    else if (cMillies == 0)
     289        rc = VERR_TIMEOUT;
     290    /*
     291     * No, so go to sleep.
     292     */
     293    else
     294        return rtSemMutexLinuxRequestSleep(pThis, cMillies, fInterruptible, fSavedIrq);
     295
     296    IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc);
     297    spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
     298    return rc;
     299}
     300
     301
    121302#undef RTSemMutexRequest
    122 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
    123 {
    124     int                 rc    = VINF_SUCCESS;
    125     PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
    126 
    127     /*
    128      * Validate input.
     303RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
     304{
     305    return rtSemMutexLinuxRequest(hMutexSem, cMillies, false /*fInterruptible*/);
     306}
     307RT_EXPORT_SYMBOL(RTSemMutexRequest);
     308
     309
     310RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
     311{
     312    return RTSemMutexRequest(hMutexSem, cMillies);
     313}
     314RT_EXPORT_SYMBOL(RTSemMutexRequestDebug);
     315
     316
     317#undef RTSemMutexRequestNoResume
     318RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
     319{
     320    return rtSemMutexLinuxRequest(hMutexSem, cMillies, true /*fInterruptible*/);
     321}
     322RT_EXPORT_SYMBOL(RTSemMutexRequest);
     323
     324
     325RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
     326{
     327    return RTSemMutexRequestNoResume(hMutexSem, cMillies);
     328}
     329RT_EXPORT_SYMBOL(RTSemMutexRequestNoResumeDebug);
     330
     331
     332RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMtx)
     333{
     334    PRTSEMMUTEXINTERNAL pThis = hMtx;
     335    struct task_struct *pSelf = current;
     336    unsigned long       fSavedIrq;
     337    int                 rc;
     338
     339    /*
     340     * Validate.
    129341     */
    130342    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    131     AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
    132 
    133     /*
    134      * Check for recursive request.
    135      */
    136     if (pThis->pOwner == current)
    137     {
    138         Assert(pThis->cRecursion < 1000);
    139         ASMAtomicIncU32(&pThis->cRecursion);
    140         return VINF_SUCCESS;
    141     }
    142 
    143     /*
    144      * Try aquire it.
    145      */
    146     if (ASMAtomicCmpXchgU32(&pThis->cRecursion, 1, 0))
    147         ASMAtomicWritePtr(&pThis->pOwner, current);
     343    AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
     344    Assert(pThis->cRefs >= 1);
     345
     346    /*
     347     * Take the lock and release one recursion.
     348     */
     349    spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
     350    if (pThis->pOwnerTask == pSelf)
     351    {
     352        Assert(pThis->cRecursions > 0);
     353        if (--pThis->cRecursions == 0)
     354        {
     355            pThis->pOwnerTask = NULL;
     356
     357            /* anyone to wake up? */
     358            if (!RTListIsEmpty(&pThis->WaiterList))
     359            {
     360                PRTSEMMUTEXLNXWAITER pWaiter = RTListNodeGetFirst(&pThis->WaiterList, RTSEMMUTEXLNXWAITER, ListEntry);
     361                pWaiter->enmReason = RTSEMMUTEXLNXWAITER_WAKEUP;
     362                wake_up_process(pWaiter->pTask);
     363            }
     364            IPRT_DEBUG_SEMS_STATE(pThis, 'u');
     365        }
     366    }
    148367    else
    149     {
    150         /*
    151          * Ok wait for it.
    152          */
    153         DEFINE_WAIT(Wait);
    154         long    lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
    155         for (;;)
    156         {
    157             /* make everything thru schedule() atomic scheduling wise. */
    158             prepare_to_wait(&pThis->Head, &Wait, TASK_INTERRUPTIBLE);
    159 
    160             /* check the condition. */
    161             if (ASMAtomicCmpXchgU32(&pThis->cRecursion, 1, 0))
    162             {
    163                 ASMAtomicWritePtr(&pThis->pOwner, current);
    164                 break;
    165             }
    166 
    167             /* check for pending signals. */
    168             if (signal_pending(current))
    169             {
    170                 rc = VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */
    171                 break;
    172             }
    173 
    174             /* wait */
    175             lTimeout = schedule_timeout(lTimeout);
    176 
    177             after_wait(&Wait);
    178 
    179             /* Check if someone destroyed the semaphore while we was waiting. */
    180             if (pThis->u32Magic != RTSEMMUTEX_MAGIC)
    181             {
    182                 rc = VERR_SEM_DESTROYED;
    183                 break;
    184             }
    185 
    186             /* check for timeout. */
    187             if (!lTimeout)
    188             {
    189                 rc = VERR_TIMEOUT;
    190                 break;
    191             }
    192         }
    193         finish_wait(&pThis->Head, &Wait);
    194     }
     368        rc = VERR_NOT_OWNER;
     369    spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
     370
     371    AssertRC(rc);
    195372    return rc;
    196373}
    197 RT_EXPORT_SYMBOL(RTSemMutexRequest);
    198 
    199 
    200 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX hMutexSem)
    201 {
    202     /*
    203      * Validate input.
    204      */
    205     PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
    206     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    207     AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
    208 
    209     AssertReturn(pThis->pOwner == current, VERR_NOT_OWNER);
    210 
    211     /*
    212      * Release the mutex.
    213      */
    214     if (pThis->cRecursion == 1)
    215     {
    216         ASMAtomicWritePtr(&pThis->pOwner, NULL);
    217         ASMAtomicWriteU32(&pThis->cRecursion, 0);
    218         wake_up(&pThis->Head);
    219     }
    220     else
    221         ASMAtomicDecU32(&pThis->cRecursion);
    222 
    223     return VINF_SUCCESS;
    224 }
    225374RT_EXPORT_SYMBOL(RTSemMutexRelease);
    226375
     376
     377RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
     378{
     379    PRTSEMMUTEXINTERNAL pThis = hMutexSem;
     380    unsigned long       fSavedIrq;
     381    bool                fOwned;
     382
     383    /*
     384     * Validate.
     385     */
     386    AssertPtrReturn(pThis, false);
     387    AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), false);
     388    Assert(pThis->cRefs >= 1);
     389
     390    /*
     391     * Take the lock and release one recursion.
     392     */
     393    spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
     394    fOwned = pThis->pOwnerTask != NULL;
     395    spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
     396
     397    return fOwned;
     398
     399}
     400RT_EXPORT_SYMBOL(RTSemMutexIsOwned);
     401
  • trunk/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h

    r25591 r28436  
    320320#endif
    321321
     322/**
     323 * Puts semaphore info into the task_struct::comm field if IPRT_DEBUG_SEMS is
     324 * defined.
     325 */
     326#ifdef IPRT_DEBUG_SEMS
     327# define IPRT_DEBUG_SEMS_STATE(pThis, chState) \
     328    snprintf(current->comm, TASK_COMM_LEN, "%c%lx", (chState), IPRT_DEBUG_SEMS_ADDRESS(pThis));
     329#else
     330# define IPRT_DEBUG_SEMS_STATE(pThis, chState)  do {  } while (0)
     331#endif
     332
     333/**
     334 * Puts semaphore info into the task_struct::comm field if IPRT_DEBUG_SEMS is
     335 * defined.
     336 */
     337#ifdef IPRT_DEBUG_SEMS
     338# define IPRT_DEBUG_SEMS_STATE_RC(pThis, chState, rc) \
     339    snprintf(current->comm, TASK_COMM_LEN, "%c%lx:%d", (chState), IPRT_DEBUG_SEMS_ADDRESS(pThis), rc);
     340#else
     341# define IPRT_DEBUG_SEMS_STATE_RC(pThis, chState, rc)  do {  } while (0)
     342#endif
     343
    322344/*
    323345 * There are some conflicting defines in iprt/param.h, sort them out here.
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