From: Piotr Caban Subject: [PATCH 1/2] msvcp120: Added _Call_once implementation Message-Id: <555CEC32.7080807@codeweavers.com> Date: Wed, 20 May 2015 22:18:58 +0200 --- dlls/msvcp110/msvcp110.spec | 4 +-- dlls/msvcp120/msvcp120.spec | 4 +-- dlls/msvcp120/tests/msvcp120.c | 55 +++++++++++++++++++++++++++++++++++++ dlls/msvcp120_app/msvcp120_app.spec | 4 +-- dlls/msvcp90/misc.c | 35 +++++++++++++++++++++++ 5 files changed, 96 insertions(+), 6 deletions(-) diff --git a/dlls/msvcp110/msvcp110.spec b/dlls/msvcp110/msvcp110.spec index 3be4944..c87eb66 100644 --- a/dlls/msvcp110/msvcp110.spec +++ b/dlls/msvcp110/msvcp110.spec @@ -3727,8 +3727,8 @@ @ cdecl -ret64 -arch=arm ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MAA_JPB_W_J@Z(ptr wstr int64) basic_streambuf_wchar_xsputn @ thiscall -ret64 -arch=i386 ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MAE_JPB_W_J@Z(ptr wstr int64) basic_streambuf_wchar_xsputn @ cdecl -arch=win64 ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MEAA_JPEB_W_J@Z(ptr ptr long) basic_streambuf_wchar_xsputn -@ stub _Call_once -@ stub _Call_onceEx +@ cdecl _Call_once(ptr ptr) +@ cdecl _Call_onceEx(ptr ptr ptr) @ stub _Cnd_broadcast @ stub _Cnd_destroy @ stub _Cnd_do_broadcast_at_thread_exit diff --git a/dlls/msvcp120/msvcp120.spec b/dlls/msvcp120/msvcp120.spec index d8187d5..b84a380 100644 --- a/dlls/msvcp120/msvcp120.spec +++ b/dlls/msvcp120/msvcp120.spec @@ -3668,8 +3668,8 @@ @ cdecl -ret64 -arch=arm ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MAA_JPB_W_J@Z(ptr wstr int64) basic_streambuf_wchar_xsputn @ thiscall -ret64 -arch=i386 ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MAE_JPB_W_J@Z(ptr wstr int64) basic_streambuf_wchar_xsputn @ cdecl -arch=win64 ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MEAA_JPEB_W_J@Z(ptr ptr long) basic_streambuf_wchar_xsputn -@ stub _Call_once -@ stub _Call_onceEx +@ cdecl _Call_once(ptr ptr) +@ cdecl _Call_onceEx(ptr ptr ptr) @ stub _Cnd_broadcast @ stub _Cnd_destroy @ stub _Cnd_do_broadcast_at_thread_exit diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c index 32ca437..f89543f 100644 --- a/dlls/msvcp120/tests/msvcp120.c +++ b/dlls/msvcp120/tests/msvcp120.c @@ -43,6 +43,8 @@ static int (__cdecl *p_isleadbyte)(int); static MSVCRT_long (__cdecl *p__Xtime_diff_to_millis2)(const xtime*, const xtime*); static int (__cdecl *p_xtime_get)(xtime*, int); static _Cvtvec* (__cdecl *p__Getcvt)(_Cvtvec*); +static void (CDECL *p__Call_once)(int *once, void (CDECL *func)(void)); +static void (CDECL *p__Call_onceEx)(int *once, void (CDECL *func)(void*), void *argv); static HMODULE msvcp; @@ -60,6 +62,8 @@ static BOOL init(void) p__Xtime_diff_to_millis2 = (void*)GetProcAddress(msvcp, "_Xtime_diff_to_millis2"); p_xtime_get = (void*)GetProcAddress(msvcp, "xtime_get"); p__Getcvt = (void*)GetProcAddress(msvcp, "_Getcvt"); + p__Call_once = (void*)GetProcAddress(msvcp, "_Call_once"); + p__Call_onceEx = (void*)GetProcAddress(msvcp, "_Call_onceEx"); msvcr = GetModuleHandleA("msvcr120.dll"); p_setlocale = (void*)GetProcAddress(msvcr, "setlocale"); @@ -190,12 +194,63 @@ static void test__Getcvt(void) } } +static int cnt; +static int once; + +static void __cdecl call_once_func(void) +{ + ok(!once, "once != 0\n"); + cnt += 0x10000; +} + +static void __cdecl call_once_ex_func(void *arg) +{ + int *i = arg; + + ok(!once, "once != 0\n"); + (*i)++; +} + +DWORD WINAPI call_once_thread(void *arg) +{ + p__Call_once(&once, call_once_func); + return 0; +} + +DWORD WINAPI call_once_ex_thread(void *arg) +{ + p__Call_onceEx(&once, call_once_ex_func, &cnt); + return 0; +} + +static void test__Call_once(void) +{ + HANDLE h[4]; + int i; + + for(i=0; i<4; i++) + h[i] = CreateThread(NULL, 0, call_once_thread, &once, 0, NULL); + ok(WaitForMultipleObjects(4, h, TRUE, INFINITE) == WAIT_OBJECT_0, + "error waiting for all threads to finish\n"); + ok(cnt == 0x10000, "cnt = %x\n", cnt); + ok(once == 1, "once = %x\n", once); + + once = cnt = 0; + for(i=0; i<4; i++) + h[i] = CreateThread(NULL, 0, call_once_ex_thread, &once, 0, NULL); + ok(WaitForMultipleObjects(4, h, TRUE, INFINITE) == WAIT_OBJECT_0, + "error waiting for all threads to finish\n"); + ok(cnt == 1, "cnt = %x\n", cnt); + ok(once == 1, "once = %x\n", once); +} + START_TEST(msvcp120) { if(!init()) return; test__Xtime_diff_to_millis2(); test_xtime_get(); test__Getcvt(); + test__Call_once(); FreeLibrary(msvcp); } diff --git a/dlls/msvcp120_app/msvcp120_app.spec b/dlls/msvcp120_app/msvcp120_app.spec index bd949be..bdfea8b 100644 --- a/dlls/msvcp120_app/msvcp120_app.spec +++ b/dlls/msvcp120_app/msvcp120_app.spec @@ -3668,8 +3668,8 @@ @ cdecl -ret64 -arch=arm ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MAA_JPB_W_J@Z(ptr wstr int64) msvcp120.?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MAA_JPB_W_J@Z @ thiscall -ret64 -arch=i386 ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MAE_JPB_W_J@Z(ptr wstr int64) msvcp120.?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MAE_JPB_W_J@Z @ cdecl -arch=win64 ?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MEAA_JPEB_W_J@Z(ptr ptr long) msvcp120.?xsputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@MEAA_JPEB_W_J@Z -@ stub _Call_once -@ stub _Call_onceEx +@ cdecl _Call_once(ptr ptr) msvcp120._Call_once +@ cdecl _Call_onceEx(ptr ptr ptr) msvcp120._Call_onceEx @ stub _Cnd_broadcast @ stub _Cnd_destroy @ stub _Cnd_do_broadcast_at_thread_exit diff --git a/dlls/msvcp90/misc.c b/dlls/msvcp90/misc.c index 51b2a67..22f90c8 100644 --- a/dlls/msvcp90/misc.c +++ b/dlls/msvcp90/misc.c @@ -630,6 +630,41 @@ void __asm_dummy_vtables(void) { #endif #endif +#if _MSVCP_VER >= 110 +static CRITICAL_SECTION call_once_cs; +static CRITICAL_SECTION_DEBUG call_once_cs_debug = +{ + 0, 0, &call_once_cs, + { &call_once_cs_debug.ProcessLocksList, &call_once_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": call_once_cs") } +}; +static CRITICAL_SECTION call_once_cs = { &call_once_cs_debug, -1, 0, 0, 0, 0 }; + +void __cdecl _Call_onceEx(int *once, void (__cdecl *func)(void*), void *argv) +{ + TRACE("%p %p %p\n", once, func, argv); + + EnterCriticalSection(&call_once_cs); + if(!*once) { + /* FIXME: handle exceptions */ + func(argv); + *once = 1; + } + LeaveCriticalSection(&call_once_cs); +} + +void __cdecl call_once_func_wrapper(void *func) +{ + ((void (__cdecl*)(void))func)(); +} + +void __cdecl _Call_once(int *once, void (__cdecl *func)(void)) +{ + TRACE("%p %p\n", once, func); + _Call_onceEx(once, call_once_func_wrapper, func); +} +#endif + void init_misc(void *base) { #ifdef __x86_64__