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

📄 atomic_functions.h

📁 新版本TR1的stl
💻 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

⌨️ 快捷键说明

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