Piotr Caban : msvcp140: Add condition variable tests.
Alexandre Julliard
julliard at winehq.org
Tue Mar 15 17:57:50 CDT 2022
Module: wine
Branch: master
Commit: e3d02807fc7be6351fc80aa814d21b86e4e0236d
URL: https://source.winehq.org/git/wine.git/?a=commit;h=e3d02807fc7be6351fc80aa814d21b86e4e0236d
Author: Piotr Caban <piotr at codeweavers.com>
Date: Tue Mar 15 14:37:14 2022 +0100
msvcp140: Add condition variable tests.
Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/msvcp140/tests/msvcp140.c | 191 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 191 insertions(+)
diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c
index b24c5e0f53d..14ba4a767d0 100644
--- a/dlls/msvcp140/tests/msvcp140.c
+++ b/dlls/msvcp140/tests/msvcp140.c
@@ -142,6 +142,45 @@ typedef struct {
void *arg;
} _Threadpool_chore;
+typedef struct
+{
+ HANDLE hnd;
+ DWORD id;
+} _Thrd_t;
+
+typedef struct cs_queue
+{
+ struct cs_queue *next;
+ BOOL free;
+ int unknown;
+} cs_queue;
+
+typedef struct
+{
+ ULONG_PTR unk_thread_id;
+ cs_queue unk_active;
+ void *unknown[2];
+ cs_queue *head;
+ void *tail;
+} critical_section;
+
+typedef struct
+{
+ DWORD flags;
+ critical_section cs;
+ DWORD thread_id;
+ DWORD count;
+} *_Mtx_t;
+
+typedef void *_Cnd_t;
+
+typedef struct {
+ __time64_t sec;
+ int nsec;
+} xtime;
+
+typedef int (__cdecl *_Thrd_start_t)(void*);
+
enum file_type {
file_not_found = -1,
none_file,
@@ -172,6 +211,20 @@ static void (__thiscall *p__TaskEventLogger__LogWorkItemStarted)(_TaskEventLogge
static int (__cdecl *p__Schedule_chore)(_Threadpool_chore*);
static int (__cdecl *p__Reschedule_chore)(const _Threadpool_chore*);
static void (__cdecl *p__Release_chore)(_Threadpool_chore*);
+static int (__cdecl *p__Mtx_init)(_Mtx_t*, int);
+static void (__cdecl *p__Mtx_destroy)(_Mtx_t);
+static int (__cdecl *p__Mtx_lock)(_Mtx_t);
+static int (__cdecl *p__Mtx_unlock)(_Mtx_t);
+static int (__cdecl *p__Cnd_init)(_Cnd_t*);
+static void (__cdecl *p__Cnd_destroy)(_Cnd_t);
+static int (__cdecl *p__Cnd_wait)(_Cnd_t, _Mtx_t);
+static int (__cdecl *p__Cnd_timedwait)(_Cnd_t, _Mtx_t, const xtime*);
+static int (__cdecl *p__Cnd_broadcast)(_Cnd_t);
+static int (__cdecl *p__Cnd_signal)(_Cnd_t);
+static int (__cdecl *p__Thrd_create)(_Thrd_t*, _Thrd_start_t, void*);
+static int (__cdecl *p__Thrd_join)(_Thrd_t, int*);
+static int (__cdecl *p__Xtime_diff_to_millis2)(const xtime*, const xtime*);
+static int (__cdecl *p_xtime_get)(xtime*, int);
static void (__cdecl *p_Close_dir)(void*);
static MSVCP_bool (__cdecl *p_Current_get)(WCHAR *);
@@ -269,6 +322,21 @@ static BOOL init(void)
SET(p__Syserror_map, "?_Syserror_map at std@@YAPBDH at Z");
}
+ SET(p__Mtx_init, "_Mtx_init");
+ SET(p__Mtx_destroy, "_Mtx_destroy");
+ SET(p__Mtx_lock, "_Mtx_lock");
+ SET(p__Mtx_unlock, "_Mtx_unlock");
+ SET(p__Cnd_init, "_Cnd_init");
+ SET(p__Cnd_destroy, "_Cnd_destroy");
+ SET(p__Cnd_wait, "_Cnd_wait");
+ SET(p__Cnd_timedwait, "_Cnd_timedwait");
+ SET(p__Cnd_broadcast, "_Cnd_broadcast");
+ SET(p__Cnd_signal, "_Cnd_signal");
+ SET(p__Thrd_create, "_Thrd_create");
+ SET(p__Thrd_join, "_Thrd_join");
+ SET(p__Xtime_diff_to_millis2, "_Xtime_diff_to_millis2");
+ SET(p_xtime_get, "xtime_get");
+
SET(p_Close_dir, "_Close_dir");
SET(p_Current_get, "_Current_get");
SET(p_Current_set, "_Current_set");
@@ -1385,6 +1453,128 @@ static void test_Equivalent(void)
ok(SetCurrentDirectoryW(current_path), "SetCurrentDirectoryW failed\n");
}
+#define NUM_THREADS 10
+#define TIMEDELTA 250 /* 250 ms uncertainty allowed */
+struct cndmtx
+{
+ HANDLE initialized;
+ LONG started;
+ int thread_no;
+
+ _Cnd_t cnd;
+ _Mtx_t mtx;
+ BOOL timed_wait;
+};
+
+static int __cdecl cnd_wait_thread(void *arg)
+{
+ struct cndmtx *cm = arg;
+ int r;
+
+ p__Mtx_lock(cm->mtx);
+
+ if(InterlockedIncrement(&cm->started) == cm->thread_no)
+ SetEvent(cm->initialized);
+
+ if(cm->timed_wait) {
+ xtime xt;
+
+ p_xtime_get(&xt, 1);
+ xt.sec += 2;
+ r = p__Cnd_timedwait(cm->cnd, cm->mtx, &xt);
+ ok(!r, "timed wait failed\n");
+ } else {
+ r = p__Cnd_wait(cm->cnd, cm->mtx);
+ ok(!r, "wait failed\n");
+ }
+
+ p__Mtx_unlock(cm->mtx);
+ return 0;
+}
+
+static void test_cnd(void)
+{
+ _Thrd_t threads[NUM_THREADS];
+ xtime xt, before, after;
+ struct cndmtx cm;
+ int r, i, diff;
+ _Cnd_t cnd;
+ _Mtx_t mtx;
+
+ r = p__Cnd_init(&cnd);
+ ok(!r, "failed to init cnd\n");
+
+ r = p__Mtx_init(&mtx, 0);
+ ok(!r, "failed to init mtx\n");
+
+ p__Cnd_destroy(NULL);
+
+ /* test _Cnd_signal/_Cnd_wait */
+ cm.initialized = CreateEventW(NULL, FALSE, FALSE, NULL);
+ cm.started = 0;
+ cm.thread_no = 1;
+ cm.cnd = cnd;
+ cm.mtx = mtx;
+ cm.timed_wait = FALSE;
+ p__Thrd_create(&threads[0], cnd_wait_thread, (void*)&cm);
+
+ WaitForSingleObject(cm.initialized, INFINITE);
+ p__Mtx_lock(mtx);
+ p__Mtx_unlock(mtx);
+
+ r = p__Cnd_signal(cm.cnd);
+ ok(!r, "failed to signal\n");
+ p__Thrd_join(threads[0], NULL);
+
+ /* test _Cnd_timedwait time out */
+ p__Mtx_lock(mtx);
+ p_xtime_get(&before, 1);
+ xt = before;
+ xt.sec += 1;
+ /* try to avoid failures on spurious wakeup */
+ p__Cnd_timedwait(cnd, mtx, &xt);
+ r = p__Cnd_timedwait(cnd, mtx, &xt);
+ p_xtime_get(&after, 1);
+ p__Mtx_unlock(mtx);
+
+ diff = p__Xtime_diff_to_millis2(&after, &before);
+ ok(r == 2, "should have timed out\n");
+ ok(diff > 1000 - TIMEDELTA, "got %d\n", diff);
+
+ /* test _Cnd_timedwait */
+ cm.started = 0;
+ cm.timed_wait = TRUE;
+ p__Thrd_create(&threads[0], cnd_wait_thread, (void*)&cm);
+
+ WaitForSingleObject(cm.initialized, INFINITE);
+ p__Mtx_lock(mtx);
+ p__Mtx_unlock(mtx);
+
+ r = p__Cnd_signal(cm.cnd);
+ ok(!r, "failed to signal\n");
+ p__Thrd_join(threads[0], NULL);
+
+ /* test _Cnd_broadcast */
+ cm.started = 0;
+ cm.thread_no = NUM_THREADS;
+
+ for(i = 0; i < cm.thread_no; i++)
+ p__Thrd_create(&threads[i], cnd_wait_thread, (void*)&cm);
+
+ WaitForSingleObject(cm.initialized, INFINITE);
+ p__Mtx_lock(mtx);
+ p__Mtx_unlock(mtx);
+
+ r = p__Cnd_broadcast(cnd);
+ ok(!r, "failed to broadcast\n");
+ for(i = 0; i < cm.thread_no; i++)
+ p__Thrd_join(threads[i], NULL);
+
+ p__Cnd_destroy(cnd);
+ p__Mtx_destroy(mtx);
+ CloseHandle(cm.initialized);
+}
+
START_TEST(msvcp140)
{
if(!init()) return;
@@ -1410,5 +1600,6 @@ START_TEST(msvcp140)
test__Winerror_map();
test__Syserror_map();
test_Equivalent();
+ test_cnd();
FreeLibrary(msvcp);
}
More information about the wine-cvs
mailing list