⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atomic_functions.h

📁 用STL的方式封装了WindowsAPI、COM调用、ACE、ATL、MFC、WTL等多种组件
💻 H
📖 第 1 页 / 共 4 页
字号:
 */
WINSTL_ATOMIC_FNS_IMPL_(void) atomic_decrement_up(ws_sint32_t volatile * /* pl */)
{
    _asm
    {
#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack

        mov ecx, dword ptr [esp + 4]
#else
# error Need to define calling convention
#endif /* call-conv */

        sub dword ptr [ecx], 1

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        ret 4
#endif /* call-conv */
    }
}

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_read_up(ws_sint32_t volatile const * /* pl */)
{
    _asm
    {
        mov eax, 0
#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl

#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack
        mov ecx, dword ptr [esp + 4]
#else
# error Need to define calling convention
#endif /* call-conv */

        // pop 0 into eax, which can then be atomically added into *pl (held
        // in ecx), leaving the value unchanged.
        xadd dword ptr [ecx], eax

        // Since it's an xadd it exchanges the previous value into eax, which
        // is exactly what's required

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        ret 4
#endif /* call-conv */
    }
}

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_write_up(ws_sint32_t volatile * /* pl */, ws_sint32_t /* n */)
{
    _asm
    {
#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl, edx is n

        // Just exchange *pl and n
        xchg dword ptr [ecx], edx

        // The previous value goes into edx, so me move it into eax for return
        mov eax, edx

        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack: pl in esp+4, pl in esp+8
        mov ecx, dword ptr [esp + 4]    // Load the address of pl into ecx
        mov eax, dword ptr [esp + 8]    // Load the value into eax, so the return value will be there waiting

        xchg dword ptr [ecx], eax

        ret 8
#else
# error Need to define calling convention
#endif /* call-conv */
    }
}


/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_postadd_up(ws_sint32_t volatile * /* pl */, ws_sint32_t /* n */)
{
    // Thanks to Eugene Gershnik for the fast-call implementation
    __asm
    {
#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl, edx is n

        // Simply atomically add them, which will leave the previous value
        // in edx
        xadd dword ptr [ecx], edx

        // Just need to move adx into eax to return it
        mov eax, edx

        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack: pl in esp+4, pl in esp+8

        // Simply atomically add them, which will leave the previous value
        // in edx
        mov ecx, dword ptr [esp + 4]    // Load the address of pl into ecx
        mov eax, dword ptr [esp + 8]    // Load the value into eax, so the return value will be there waiting

        xadd dword ptr [ecx], eax

        // Just need to move adx into eax to return it

        ret 8
#else
# error Need to define calling convention
#endif /* call-conv */
    }
}

// Symmetric multi-processor

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_preincrement_smp(ws_sint32_t volatile * /* pl */)
{
    _asm
    {
        // pop 1 into eax, which can then be atomically added into *pl (held
        // in ecx). Since it's an xadd it exchanges the previous value into eax
        mov eax, 1

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack

        mov ecx, dword ptr [esp + 4]
#else
# error Need to define calling convention
#endif /* call-conv */

        lock xadd dword ptr [ecx], eax

        // Since this is pre-increment, we need to inc eax to catch up with the
        // real value
        inc eax

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        ret 4
#endif /* call-conv */
    }
}

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_predecrement_smp(ws_sint32_t volatile * /* pl */)
{
    _asm
    {
        // pop 1 into eax, which can then be atomically added into *pl (held
        // in ecx). Since it's an xadd it exchanges the previous value into eax
        mov eax, -1

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack

        mov ecx, dword ptr [esp + 4]
#else
# error Need to define calling convention
#endif /* call-conv */

        lock xadd dword ptr [ecx], eax

        // Since this is pre-decrement, we need to inc eax to catch up with the
        // real value
        dec eax

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        ret 4
#endif /* call-conv */
    }
}

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_postincrement_smp(ws_sint32_t volatile * /* pl */)
{
    _asm
    {
        // pop 1 into eax, which can then be atomically added into *pl (held
        // in ecx). Since it's an xadd it exchanges the previous value into eax
        mov eax, 1

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack

        mov ecx, dword ptr [esp + 4]
#else
# error Need to define calling convention
#endif /* call-conv */

        lock xadd dword ptr [ecx], eax

        // Since this is post-increment, we need do nothing, since the previous
        // value is in eax

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        ret 4
#endif /* call-conv */
    }
}

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_postdecrement_smp(ws_sint32_t volatile * /* pl */)
{
    _asm
    {
        // pop 1 into eax, which can then be atomically added into *pl (held
        // in ecx). Since it's an xadd it exchanges the previous value into eax
        mov eax, -1

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack

        mov ecx, dword ptr [esp + 4]
#else
# error Need to define calling convention
#endif /* call-conv */

        lock xadd dword ptr [ecx], eax

        // Since this is post-decrement, we need do nothing, since the previous
        // value is in eax

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        ret 4
#endif /* call-conv */
    }
}

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_read_smp(ws_sint32_t volatile const * /* pl */)
{
    _asm
    {
        mov eax, 0
#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl

#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack
        mov ecx, dword ptr [esp + 4]
#else
# error Need to define calling convention
#endif /* call-conv */

        // pop 0 into eax, which can then be atomically added into *pl (held
        // in ecx), leaving the value unchanged.
        lock xadd dword ptr [ecx], eax

        // Since it's an xadd it exchanges the previous value into eax, which
        // is exactly what's required

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        ret 4
#endif /* call-conv */
    }
}

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_write_smp(ws_sint32_t volatile * /* pl */, ws_sint32_t /* n */)
{
    _asm
    {
#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl, edx is n

        // Just exchange *pl and n
        /* lock */ xchg dword ptr [ecx], edx

        // The previous value goes into edx, so me move it into eax for return
        mov eax, edx

        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack: pl in esp+4, pl in esp+8
        mov ecx, dword ptr [esp + 4]    // Load the address of pl into ecx
        mov eax, dword ptr [esp + 8]    // Load the value into eax, so the return value will be there waiting

        /* lock */ xchg dword ptr [ecx], eax

        ret 8
#else
# error Need to define calling convention
#endif /* call-conv */
    }
}


/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_postadd_smp(ws_sint32_t volatile * /* pl */, ws_sint32_t /* n */)
{
    // Thanks to Eugene Gershnik for the fast-call implementation
    __asm
    {
#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
        // __fastcall: ecx is pl, edx is n

        // Simply atomically add them, which will leave the previous value
        // in edx
        lock xadd dword ptr [ecx], edx

        // Just need to move adx into eax to return it
        mov eax, edx

        ret
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)
        // __stdcall: arguments are on the stack: pl in esp+4, pl in esp+8

        // Simply atomically add them, which will leave the previous value
        // in edx
        mov ecx, dword ptr [esp + 4]    // Load the address of pl into ecx
        mov eax, dword ptr [esp + 8]    // Load the value into eax, so the return value will be there waiting

        lock xadd dword ptr [ecx], eax

        // Just need to move adx into eax to return it

        ret 8
#else
# error Need to define calling convention
#endif /* call-conv */
    }
}

// Processor detection

namespace
{
    inline ws_bool_t is_host_up()
    {
        // All these statics are guaranteed to be zero as a result of the module/process loading
        static ws_sint32_t  s_spin; // The spin variable
        static ws_bool_t    s_init; // This is guaranteed to be zero
        static ws_bool_t    s_up;   // This is the flag variably, also guaranteed to be zero

        // Simple spin lock
        if(!s_init) // Low cost pre-test. In the unlikely event that another thread does come in and
        {           // also see this as false, the dual initialisation of all three statics is benign
            spin_mutex  smx(&s_spin);

            smx.lock();
            if(!s_init)
            {
                SYSTEM_INFO sys_info;

                ::GetSystemInfo(&sys_info);

                s_init = true;

                s_up = 1 == sys_info.dwNumberOfProcessors;
            }
            smx.unlock();
        }

        return s_up;
    }

    // s_up is guaranteed to be zero at load time.
    //
    // There is a race condition with all static variables, since multiple threads
    // can come in and one can have set the hidden flag variable without prior to
    // setting the static variable itself, just at the time that an arbitrary number
    // of other threads pick up the pre-initialised value.
    //
    // However, because the test here is whether to skip the lock, the pathological
    // case is benign. The only cost in the very rare case where it happens is that
    // the thread(s) will use bus locking until such time as the static is fully
    // initialised.
    static ws_bool_t    s_up = is_host_up();
}

/** \brief 
 *
 * \ingroup group__library__synch
 */
WINSTL_ATOMIC_FNS_IMPL_(ws_sint32_t) atomic_preincrement(ws_sint32_t volatile * /* pl */)
{
    if(s_up)
    {
        _asm
        {
            // pop 1 into eax, which can then be atomically added into *pl (held
            // in ecx). Since it's an xadd it exchanges the previous value into eax
            mov eax, 1

#if defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_FASTCALL)
            // __fastcall: ecx is pl
#elif defined(WINSTL_ATOMIC_FNS_CALLCONV_IS_STDCALL)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -