VirtualBox

Changeset 92779 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Dec 7, 2021 9:45:53 AM (3 years ago)
Author:
vboxsync
Message:

IPRT/semevent*-linux: Share some common bits between the single-release and multiple-release linux event sempahore code. Freshened up the latter a bit. bugref:10138

Location:
trunk/src/VBox/Runtime/r3/linux
Files:
1 added
2 edited

Legend:

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

    r92777 r92779  
    6565#include <sys/time.h>
    6666#include <sys/syscall.h>
    67 #if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
    68 # include <linux/futex.h>
    69 #else
    70 # define FUTEX_WAIT 0
    71 # define FUTEX_WAKE 1
    72 # define FUTEX_WAIT_BITSET 9 /**< @since 2.6.25 - uses absolute timeout. */
    73 #endif
     67
     68#include "semwait-linux.h"
    7469
    7570
     
    10499*   Global Variables                                                                                                             *
    105100*********************************************************************************************************************************/
     101/** Whether we can use FUTEX_WAIT_BITSET. */
    106102static int volatile g_fCanUseWaitBitSet = -1;
    107103
    108 
    109 /**
    110  * Wrapper for the futex syscall.
    111  */
    112 static long sys_futex(uint32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
    113 {
    114     errno = 0;
    115     long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
    116     if (rc < 0)
    117     {
    118         Assert(rc == -1);
    119         rc = -errno;
    120     }
    121     return rc;
    122 }
    123 
    124 
    125 DECLINLINE(void) rtSemLinuxCheckForFutexWaitBitSetSlow(int volatile *pfCanUseWaitBitSet)
    126 {
    127     uint32_t uTestVar = UINT32_MAX;
    128     long rc = sys_futex(&uTestVar, FUTEX_WAIT_BITSET, UINT32_C(0xf0f0f0f0), NULL, NULL, UINT32_MAX);
    129     *pfCanUseWaitBitSet = rc == -EAGAIN;
    130     AssertMsg(rc == -ENOSYS || rc == -EAGAIN, ("%d\n", rc));
    131 }
    132 
    133 
    134 DECLINLINE(void) rtSemLinuxCheckForFutexWaitBitSet(int volatile *pfCanUseWaitBitSet)
    135 {
    136     if (*pfCanUseWaitBitSet != -1)
    137     { /* likely */ }
    138     else
    139         rtSemLinuxCheckForFutexWaitBitSetSlow(pfCanUseWaitBitSet);
    140 }
    141104
    142105
  • trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp

    r90789 r92779  
    6767#include <sys/time.h>
    6868#include <sys/syscall.h>
    69 #if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
    70 # include <linux/futex.h>
    71 #else
    72 # define FUTEX_WAIT 0
    73 # define FUTEX_WAKE 1
    74 #endif
     69
     70#include "semwait-linux.h"
    7571
    7672
     
    8581    /** Magic value. */
    8682    uint32_t volatile   u32Magic;
    87     /** The futex state variable.
    88      * -1 means signaled.
    89      *  0 means not signaled, no waiters.
    90      *  1 means not signaled and that someone is waiting.
    91      */
    92     int32_t volatile    iState;
     83    /** The futex state variable, see RTSEMEVENTMULTI_LNX_XXX. */
     84    uint32_t volatile   uState;
     85#ifdef RT_STRICT
     86    /** Increased on every signalling call. */
     87    uint32_t volatile   uSignalSerialNo;
     88#endif
    9389#ifdef RTSEMEVENTMULTI_STRICT
    9490    /** Signallers. */
     
    10096
    10197
    102 /**
    103  * Wrapper for the futex syscall.
    104  */
    105 static long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
    106 {
    107     errno = 0;
    108     long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
    109     if (rc < 0)
    110     {
    111         Assert(rc == -1);
    112         rc = -errno;
    113     }
    114     return rc;
    115 }
     98/*********************************************************************************************************************************
     99*   Defined Constants And Macros                                                                                                 *
     100*********************************************************************************************************************************/
     101/** @name RTSEMEVENTMULTI_LNX_XXX - state
     102 * @{ */
     103#define RTSEMEVENTMULTI_LNX_NOT_SIGNALED            UINT32_C(0x00000000)
     104#define RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS    UINT32_C(0x00000001)
     105#define RTSEMEVENTMULTI_LNX_SIGNALED                UINT32_C(0x00000003)
     106/** @} */
     107
     108#define ASSERT_VALID_STATE(a_uState) \
     109    AssertMsg(   (a_uState) == RTSEMEVENTMULTI_LNX_NOT_SIGNALED \
     110              || (a_uState) == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS \
     111              || (a_uState) == RTSEMEVENTMULTI_LNX_SIGNALED, \
     112              (#a_uState "=%s\n", a_uState))
     113
     114
     115/*********************************************************************************************************************************
     116*   Global Variables                                                                                                             *
     117*********************************************************************************************************************************/
     118/** Whether we can use FUTEX_WAIT_BITSET. */
     119static int volatile g_fCanUseWaitBitSet = -1;
    116120
    117121
     
    128132
    129133    /*
     134     * Make sure we know whether FUTEX_WAIT_BITSET works.
     135     */
     136    rtSemLinuxCheckForFutexWaitBitSet(&g_fCanUseWaitBitSet);
     137#if defined(DEBUG_bird) && !defined(IN_GUEST)
     138    Assert(g_fCanUseWaitBitSet == true);
     139#endif
     140
     141    /*
    130142     * Allocate semaphore handle.
    131143     */
     
    133145    if (pThis)
    134146    {
    135         pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
    136         pThis->iState   = 0;
     147        pThis->u32Magic        = RTSEMEVENTMULTI_MAGIC;
     148        pThis->uState          = RTSEMEVENTMULTI_LNX_NOT_SIGNALED;
     149#ifdef RT_STRICT
     150        pThis->uSignalSerialNo = 0;
     151#endif
    137152#ifdef RTSEMEVENTMULTI_STRICT
    138153        if (!pszNameFmt)
     
    179194     */
    180195    ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC + 1);
    181     if (ASMAtomicXchgS32(&pThis->iState, -1) == 1)
    182     {
    183         sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
     196    if (ASMAtomicXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_SIGNALED) == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS)
     197    {
     198        sys_futex(&pThis->uState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    184199        usleep(1000);
    185200    }
     
    214229#endif
    215230
    216 
    217231    /*
    218232     * Signal it.
    219233     */
    220     int32_t iOld = ASMAtomicXchgS32(&pThis->iState, -1);
    221     if (iOld > 0)
     234#ifdef RT_STRICT
     235    ASMAtomicIncU32(&pThis->uSignalSerialNo);
     236#endif
     237    uint32_t uOld = ASMAtomicXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_SIGNALED);
     238    if (uOld == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS)
    222239    {
    223240        /* wake up sleeping threads. */
    224         long cWoken = sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
     241        long cWoken = sys_futex(&pThis->uState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    225242        AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken);
    226243    }
    227     Assert(iOld == 0 || iOld == -1 || iOld == 1);
     244    ASSERT_VALID_STATE(uOld);
    228245    return VINF_SUCCESS;
    229246}
     
    239256    AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
    240257#ifdef RT_STRICT
    241     int32_t i = pThis->iState;
    242     Assert(i == 0 || i == -1 || i == 1);
     258    uint32_t const uState = pThis->uState;
     259    ASSERT_VALID_STATE(uState);
    243260#endif
    244261
     
    246263     * Reset it.
    247264     */
    248     ASMAtomicCmpXchgS32(&pThis->iState, 0, -1);
     265    ASMAtomicCmpXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_NOT_SIGNALED, RTSEMEVENTMULTI_LNX_SIGNALED);
    249266    return VINF_SUCCESS;
    250267}
     
    267284     * Quickly check whether it's signaled.
    268285     */
    269     int32_t iCur = ASMAtomicUoReadS32(&pThis->iState);
    270     Assert(iCur == 0 || iCur == -1 || iCur == 1);
    271     if (iCur == -1)
     286    uint32_t uState = ASMAtomicUoReadU32(&pThis->uState);
     287    if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
    272288        return VINF_SUCCESS;
     289    ASSERT_VALID_STATE(uState);
    273290
    274291    /*
     
    325342         * threads waiting on the semaphore to keep things simple.
    326343         */
    327         iCur = ASMAtomicUoReadS32(&pThis->iState);
    328         Assert(iCur == 0 || iCur == -1 || iCur == 1);
    329         if (    iCur == 1
    330             ||  ASMAtomicCmpXchgS32(&pThis->iState, 1, 0))
     344        uState = ASMAtomicUoReadU32(&pThis->uState);
     345        if (   uState == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS
     346            || (   uState == RTSEMEVENTMULTI_LNX_NOT_SIGNALED
     347                && ASMAtomicCmpXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS,
     348                                       RTSEMEVENTMULTI_LNX_NOT_SIGNALED)))
    331349        {
    332350            /* adjust the relative timeout */
     
    348366            }
    349367#endif
     368#ifdef RT_STRICT
     369            uint32_t const uPrevSignalSerialNo = ASMAtomicReadU32(&pThis->uSignalSerialNo);
     370#endif
    350371            RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
    351             long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
     372            long rc = sys_futex(&pThis->uState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
    352373            RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
    353374            if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
    354375                return VERR_SEM_DESTROYED;
    355376            if (rc == 0)
     377            {
     378                Assert(uPrevSignalSerialNo != ASMAtomicReadU32(&pThis->uSignalSerialNo));
    356379                return VINF_SUCCESS;
     380            }
    357381
    358382            /*
     
    381405            }
    382406        }
    383         else if (iCur == -1)
     407        else if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
    384408            return VINF_SUCCESS;
     409        else
     410            ASSERT_VALID_STATE(uState);
    385411    }
    386412}
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