From ccda9bbba43f642f9f1cb631c18adfbc59019a18 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Thu, 17 Nov 2016 09:56:21 -0600 Subject: [PATCH] msvcr120: Add _Condition_variable tests. Signed-off-by: Piotr Caban Signed-off-by: Alexandre Julliard --- dlls/msvcr120/tests/msvcr120.c | 125 +++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index 4ecea51d7b5..e631738d0f9 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -46,6 +46,8 @@ struct thiscall_thunk static ULONG_PTR (WINAPI *call_thiscall_func1)( void *func, void *this ); static ULONG_PTR (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a ); +static ULONG_PTR (WINAPI *call_thiscall_func3)( void *func, + void *this, const void *a, const void *b ); static void init_thiscall_thunk(void) { @@ -58,16 +60,19 @@ static void init_thiscall_thunk(void) thunk->jmp_edx = 0xe2ff; /* jmp *%edx */ call_thiscall_func1 = (void *)thunk; call_thiscall_func2 = (void *)thunk; + call_thiscall_func3 = (void *)thunk; } #define call_func1(func,_this) call_thiscall_func1(func,_this) #define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)(a)) +#define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)(a),(const void*)(b)) #else #define init_thiscall_thunk() #define call_func1(func,_this) func(_this) #define call_func2(func,_this,a) func(_this,a) +#define call_func3(func,_this,a,b) func(_this,a,b) #endif /* __i386__ */ @@ -103,6 +108,11 @@ typedef struct int unknown2[2]; } critical_section_scoped_lock; +typedef struct { + void *chain; + critical_section lock; +} _Condition_variable; + static inline float __port_infinity(void) { static const unsigned __inf_bytes = 0x7f800000; @@ -188,6 +198,13 @@ static critical_section_scoped_lock* (__thiscall *p_critical_section_scoped_lock (critical_section_scoped_lock*, critical_section *); static void (__thiscall *p_critical_section_scoped_lock_dtor)(critical_section_scoped_lock*); +static _Condition_variable* (__thiscall *p__Condition_variable_ctor)(_Condition_variable*); +static void (__thiscall *p__Condition_variable_dtor)(_Condition_variable*); +static void (__thiscall *p__Condition_variable_wait)(_Condition_variable*, critical_section*); +static MSVCRT_bool (__thiscall *p__Condition_variable_wait_for)(_Condition_variable*, critical_section*, unsigned int); +static void (__thiscall *p__Condition_variable_notify_one)(_Condition_variable*); +static void (__thiscall *p__Condition_variable_notify_all)(_Condition_variable*); + #define SETNOFAIL(x,y) x = (void*)GetProcAddress(module,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) @@ -240,6 +257,18 @@ static BOOL init(void) "??0scoped_lock@critical_section@Concurrency@@QEAA@AEAV12@@Z"); SET(p_critical_section_scoped_lock_dtor, "??1scoped_lock@critical_section@Concurrency@@QEAA@XZ"); + SET(p__Condition_variable_ctor, + "??0_Condition_variable@details@Concurrency@@QEAA@XZ"); + SET(p__Condition_variable_dtor, + "??1_Condition_variable@details@Concurrency@@QEAA@XZ"); + SET(p__Condition_variable_wait, + "?wait@_Condition_variable@details@Concurrency@@QEAAXAEAVcritical_section@3@@Z"); + SET(p__Condition_variable_wait_for, + "?wait_for@_Condition_variable@details@Concurrency@@QEAA_NAEAVcritical_section@3@I@Z"); + SET(p__Condition_variable_notify_one, + "?notify_one@_Condition_variable@details@Concurrency@@QEAAXXZ"); + SET(p__Condition_variable_notify_all, + "?notify_all@_Condition_variable@details@Concurrency@@QEAAXXZ"); } else { #ifdef __arm__ SET(p_critical_section_ctor, @@ -260,6 +289,18 @@ static BOOL init(void) "??0scoped_lock@critical_section@Concurrency@@QAA@AAV12@@Z"); SET(p_critical_section_scoped_lock_dtor, "??1scoped_lock@critical_section@Concurrency@@QAA@XZ"); + SET(p__Condition_variable_ctor, + "??0_Condition_variable@details@Concurrency@@QAA@XZ"); + SET(p__Condition_variable_dtor, + "??1_Condition_variable@details@Concurrency@@QAA@XZ"); + SET(p__Condition_variable_wait, + "?wait@_Condition_variable@details@Concurrency@@QAAXAAVcritical_section@3@@Z"); + SET(p__Condition_variable_wait_for, + "?wait_for@_Condition_variable@details@Concurrency@@QAA_NAAVcritical_section@3@I@Z"); + SET(p__Condition_variable_notify_one, + "?notify_one@_Condition_variable@details@Concurrency@@QAAXXZ"); + SET(p__Condition_variable_notify_all, + "?notify_all@_Condition_variable@details@Concurrency@@QAAXXZ"); #else SET(p_critical_section_ctor, "??0critical_section@Concurrency@@QAE@XZ"); @@ -279,6 +320,18 @@ static BOOL init(void) "??0scoped_lock@critical_section@Concurrency@@QAE@AAV12@@Z"); SET(p_critical_section_scoped_lock_dtor, "??1scoped_lock@critical_section@Concurrency@@QAE@XZ"); + SET(p__Condition_variable_ctor, + "??0_Condition_variable@details@Concurrency@@QAE@XZ"); + SET(p__Condition_variable_dtor, + "??1_Condition_variable@details@Concurrency@@QAE@XZ"); + SET(p__Condition_variable_wait, + "?wait@_Condition_variable@details@Concurrency@@QAEXAAVcritical_section@3@@Z"); + SET(p__Condition_variable_wait_for, + "?wait_for@_Condition_variable@details@Concurrency@@QAE_NAAVcritical_section@3@I@Z"); + SET(p__Condition_variable_notify_one, + "?notify_one@_Condition_variable@details@Concurrency@@QAEXXZ"); + SET(p__Condition_variable_notify_all, + "?notify_all@_Condition_variable@details@Concurrency@@QAEXXZ"); #endif } @@ -758,6 +811,77 @@ static void test__wcreate_locale(void) ok(errno == -1, "expected errno -1, but got %i\n", e); } +struct wait_thread_arg +{ + critical_section *cs; + _Condition_variable *cv; + HANDLE thread_initialized; +}; + +static DWORD WINAPI condition_variable_wait_thread(void *varg) +{ + struct wait_thread_arg *arg = varg; + + call_func1(p_critical_section_lock, arg->cs); + SetEvent(arg->thread_initialized); + call_func2(p__Condition_variable_wait, arg->cv, arg->cs); + call_func1(p_critical_section_unlock, arg->cs); + return 0; +} + +static void test__Condition_variable(void) +{ + critical_section cs; + _Condition_variable cv; + HANDLE thread_initialized = CreateEventW(NULL, FALSE, FALSE, NULL); + struct wait_thread_arg wait_thread_arg = { &cs, &cv, thread_initialized }; + HANDLE threads[2]; + DWORD ret; + MSVCRT_bool b; + + ok(thread_initialized != NULL, "CreateEvent failed\n"); + + call_func1(p_critical_section_ctor, &cs); + call_func1(p__Condition_variable_ctor, &cv); + + call_func1(p__Condition_variable_notify_one, &cv); + call_func1(p__Condition_variable_notify_all, &cv); + + threads[0] = CreateThread(0, 0, condition_variable_wait_thread, + &wait_thread_arg, 0, 0); + ok(threads[0] != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread_initialized, INFINITE); + call_func1(p_critical_section_lock, &cs); + call_func1(p_critical_section_unlock, &cs); + + threads[1] = CreateThread(0, 0, condition_variable_wait_thread, + &wait_thread_arg, 0, 0); + ok(threads[1] != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread_initialized, INFINITE); + call_func1(p_critical_section_lock, &cs); + call_func1(p_critical_section_unlock, &cs); + + call_func1(p__Condition_variable_notify_one, &cv); + ret = WaitForSingleObject(threads[1], 500); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", ret); + call_func1(p__Condition_variable_notify_one, &cv); + ret = WaitForSingleObject(threads[0], 500); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", ret); + + CloseHandle(threads[0]); + CloseHandle(threads[1]); + + call_func1(p_critical_section_lock, &cs); + b = call_func3(p__Condition_variable_wait_for, &cv, &cs, 1); + ok(!b, "_Condition_variable_wait_for returned TRUE\n"); + call_func1(p_critical_section_unlock, &cs); + + call_func1(p_critical_section_dtor, &cs); + call_func1(p__Condition_variable_dtor, &cv); + + CloseHandle(thread_initialized); +} + START_TEST(msvcr120) { if (!init()) return; @@ -773,4 +897,5 @@ START_TEST(msvcr120) test_critical_section(); test_fegetenv(); test__wcreate_locale(); + test__Condition_variable(); }