[PATCH] msvcr120: Add tests for _StructuredTaskCollection.

Torge Matthies tmatthies at codeweavers.com
Thu May 19 13:44:04 CDT 2022


Signed-off-by: Torge Matthies <tmatthies at codeweavers.com>
---
 dlls/msvcr120/tests/msvcr120.c | 269 +++++++++++++++++++++++++++++++++
 1 file changed, 269 insertions(+)

diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c
index a3161266db41..26b363de6c59 100644
--- a/dlls/msvcr120/tests/msvcr120.c
+++ b/dlls/msvcr120/tests/msvcr120.c
@@ -162,6 +162,27 @@ typedef struct {
     Context *ctx;
 } _Context;
 
+typedef struct _StructuredTaskCollection
+{
+    void *unk1;
+    unsigned int unk2;
+    void *unk3;
+    Context *context;
+    volatile LONG count;
+    volatile LONG finished;
+    void *unk4;
+    void *event;
+} _StructuredTaskCollection;
+
+typedef struct _UnrealizedChore
+{
+    const vtable_ptr *vtable;
+    void (__cdecl *proc)(struct _UnrealizedChore*);
+    struct _StructuredTaskCollection *task_collection;
+    void (__cdecl *proc_wrapper)(struct _UnrealizedChore*);
+    void *unk[6];
+} _UnrealizedChore;
+
 static char* (CDECL *p_setlocale)(int category, const char* locale);
 static struct MSVCRT_lconv* (CDECL *p_localeconv)(void);
 static size_t (CDECL *p_wcstombs_s)(size_t *ret, char* dest, size_t sz, const wchar_t* src, size_t max);
@@ -225,6 +246,11 @@ static void (__thiscall *p__Condition_variable_notify_all)(_Condition_variable*)
 static Context* (__cdecl *p_Context_CurrentContext)(void);
 static _Context* (__cdecl *p__Context__CurrentContext)(_Context*);
 
+static _StructuredTaskCollection* (__thiscall *p__StructuredTaskCollection_ctor)(_StructuredTaskCollection*, void*);
+static void (__thiscall *p__StructuredTaskCollection_dtor)(_StructuredTaskCollection*);
+static void (__thiscall *p__StructuredTaskCollection__Schedule)(_StructuredTaskCollection*, _UnrealizedChore*);
+static int (__stdcall *p__StructuredTaskCollection__RunAndWait)(_StructuredTaskCollection*, _UnrealizedChore*);
+
 #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)
 
@@ -279,6 +305,14 @@ static BOOL init(void)
     SET(p_towctrans, "towctrans");
     SET(p__Context__CurrentContext, "?_CurrentContext at _Context@details at Concurrency@@SA?AV123 at XZ");
     if(sizeof(void*) == 8) { /* 64-bit initialization */
+        SET(p__StructuredTaskCollection_ctor,
+                "??0_StructuredTaskCollection at details@Concurrency@@QEAA at PEAV_CancellationTokenState@12@@Z");
+        SET(p__StructuredTaskCollection_dtor,
+                "??1_StructuredTaskCollection at details@Concurrency@@QEAA at XZ");
+        SET(p__StructuredTaskCollection__Schedule,
+                "?_Schedule at _StructuredTaskCollection@details at Concurrency@@QEAAXPEAV_UnrealizedChore at 23@@Z");
+        SET(p__StructuredTaskCollection__RunAndWait,
+                "?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z");
         SET(p_critical_section_ctor,
                 "??0critical_section at Concurrency@@QEAA at XZ");
         SET(p_critical_section_dtor,
@@ -313,6 +347,14 @@ static BOOL init(void)
                 "?CurrentContext at Context@Concurrency@@SAPEAV12 at XZ");
     } else {
 #ifdef __arm__
+        SET(p__StructuredTaskCollection_ctor,
+                "??0_StructuredTaskCollection at details@Concurrency@@QAA at PAV_CancellationTokenState@12@@Z");
+        SET(p__StructuredTaskCollection_dtor,
+                "??1_StructuredTaskCollection at details@Concurrency@@QAA at XZ");
+        SET(p__StructuredTaskCollection__Schedule,
+                "?_Schedule at _StructuredTaskCollection@details at Concurrency@@QAAXPAV_UnrealizedChore at 23@@Z");
+        SET(p__StructuredTaskCollection__RunAndWait,
+                "?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z");
         SET(p_critical_section_ctor,
                 "??0critical_section at Concurrency@@QAA at XZ");
         SET(p_critical_section_dtor,
@@ -344,6 +386,14 @@ static BOOL init(void)
         SET(p__Condition_variable_notify_all,
                 "?notify_all at _Condition_variable@details at Concurrency@@QAAXXZ");
 #else
+        SET(p__StructuredTaskCollection_ctor,
+                "??0_StructuredTaskCollection at details@Concurrency@@QAE at PAV_CancellationTokenState@12@@Z");
+        SET(p__StructuredTaskCollection_dtor,
+                "??1_StructuredTaskCollection at details@Concurrency@@QAE at XZ");
+        SET(p__StructuredTaskCollection__Schedule,
+                "?_Schedule at _StructuredTaskCollection@details at Concurrency@@QAEXPAV_UnrealizedChore at 23@@Z");
+        SET(p__StructuredTaskCollection__RunAndWait,
+                "?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z");
         SET(p_critical_section_ctor,
                 "??0critical_section at Concurrency@@QAE at XZ");
         SET(p_critical_section_dtor,
@@ -1270,6 +1320,224 @@ static void test_CurrentContext(void)
     ok(ret == &_ctx, "expected %p, got %p\n", &_ctx, ret);
 }
 
+static void _UnrealizedChore_ctor(_UnrealizedChore *chore, void (__cdecl *proc)(_UnrealizedChore*))
+{
+    memset(chore, 0, sizeof(*chore));
+    chore->proc = proc;
+}
+
+struct chore
+{
+    _UnrealizedChore chore;
+    BOOL executed;
+    HANDLE start_event;
+    HANDLE set_event;
+    HANDLE wait_event;
+    DWORD main_tid;
+};
+
+static void __cdecl chore_proc(_UnrealizedChore *_this)
+{
+    struct chore *chore = CONTAINING_RECORD(_this, struct chore, chore);
+
+    if (chore->start_event)
+    {
+        DWORD ret = WaitForSingleObject(chore->start_event, 5000);
+        ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", ret);
+    }
+
+    ok(!chore->executed, "Chore was already executed\n");
+
+    if (chore->main_tid)
+    {
+        ok(GetCurrentThreadId() == chore->main_tid,
+                "Main chore is not running on the main thread: 0x%lx != 0x%lx\n",
+                GetCurrentThreadId(), chore->main_tid);
+    }
+
+    if (!chore->wait_event)
+        chore->executed = TRUE;
+
+    if (chore->set_event)
+    {
+        BOOL b = SetEvent(chore->set_event);
+        ok(b, "SetEvent failed\n");
+    }
+
+    if (chore->wait_event)
+    {
+        DWORD ret = WaitForSingleObject(chore->wait_event, 5000);
+        ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", ret);
+        chore->executed = TRUE;
+    }
+}
+
+static void chore_ctor(struct chore *chore)
+{
+    memset(chore, 0, sizeof(*chore));
+    _UnrealizedChore_ctor(&chore->chore, chore_proc);
+}
+
+static void test_StructuredTaskCollection(void)
+{
+    HANDLE chore_start_evt, chore_evt1, chore_evt2;
+    _StructuredTaskCollection task_coll;
+    struct chore chore1, chore2;
+    DWORD main_thread_id;
+    Context *context;
+    int status;
+    DWORD ret;
+    BOOL b;
+
+    main_thread_id = GetCurrentThreadId();
+    context = p_Context_CurrentContext();
+
+    memset(&task_coll, 0x55, sizeof(task_coll));
+    if (!call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL))
+    {
+        skip("_StructuredTaskCollection constructor not implemented\n");
+        return;
+    }
+    ok(task_coll.unk2 == 0x1fffffff,
+            "_StructuredTaskCollection ctor set wrong unk2: 0x%x != 0x1fffffff\n", task_coll.unk2);
+    ok(task_coll.unk3 == NULL,
+            "_StructuredTaskCollection ctor set wrong unk3: %p != NULL\n", task_coll.unk3);
+    ok(task_coll.context == NULL,
+            "_StructuredTaskCollection ctor set wrong context: %p != NULL\n", task_coll.context);
+    ok(task_coll.count == 0,
+            "_StructuredTaskCollection ctor set wrong count: %ld != 0\n", task_coll.count);
+    ok(task_coll.finished == LONG_MIN,
+            "_StructuredTaskCollection ctor set wrong finished: %ld != %ld\n", task_coll.finished, LONG_MIN);
+    ok(task_coll.unk4 == NULL,
+            "_StructuredTaskCollection ctor set wrong unk4: %p != NULL\n", task_coll.unk4);
+
+    chore_start_evt = CreateEventW(NULL, TRUE, FALSE, NULL);
+    ok(chore_start_evt != NULL, "CreateEvent failed: 0x%lx\n", GetLastError());
+    chore_evt1 = CreateEventW(NULL, FALSE, FALSE, NULL);
+    ok(chore_evt1 != NULL, "CreateEvent failed: 0x%lx\n", GetLastError());
+    chore_evt2 = CreateEventW(NULL, FALSE, FALSE, NULL);
+    ok(chore_evt2 != NULL, "CreateEvent failed: 0x%lx\n", GetLastError());
+
+    /* test running chores (only main) */
+    chore_ctor(&chore1);
+    chore1.main_tid = main_thread_id;
+
+    status = p__StructuredTaskCollection__RunAndWait(&task_coll, &chore1.chore);
+    ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status);
+    ok(chore1.executed, "Scheduled chore was not executed\n");
+    call_func1(p__StructuredTaskCollection_dtor, &task_coll);
+
+    /* test running chores (main + scheduled) */
+    call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL);
+    ResetEvent(chore_start_evt);
+    chore_ctor(&chore1);
+    chore1.start_event = chore_start_evt;
+    chore_ctor(&chore2);
+    chore2.main_tid = main_thread_id;
+
+    call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore1.chore);
+    ok(chore1.chore.task_collection == &task_coll, "Wrong chore #1 task_collection: expected %p, actual %p\n",
+            &task_coll, chore1.chore.task_collection);
+    ok(chore1.chore.proc_wrapper != NULL, "Chore #1 proc_wrapper was not set\n");
+    ok(task_coll.count == 1, "Wrong chore count: %ld != 1\n", task_coll.count);
+    ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context);
+
+    b = SetEvent(chore_start_evt);
+    ok(b, "SetEvent failed\n");
+
+    status = p__StructuredTaskCollection__RunAndWait(&task_coll, &chore2.chore);
+    ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status);
+    ok(chore1.executed, "Scheduled chore was not executed\n");
+    ok(chore2.executed, "Main chore was not executed\n");
+    call_func1(p__StructuredTaskCollection_dtor, &task_coll);
+
+    /* test that scheduled chores may run in parallel */
+    call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL);
+    ResetEvent(chore_start_evt);
+    chore_ctor(&chore1);
+    chore1.start_event = chore_start_evt;
+    chore1.set_event = chore_evt2;
+    chore1.wait_event = chore_evt1;
+    chore_ctor(&chore2);
+    chore2.start_event = chore_start_evt;
+    chore2.set_event = chore_evt1;
+    chore2.wait_event = chore_evt2;
+
+    call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore1.chore);
+    ok(chore1.chore.task_collection == &task_coll, "Wrong chore #1 task_collection: expected %p, actual %p\n",
+            &task_coll, chore1.chore.task_collection);
+    ok(chore1.chore.proc_wrapper != NULL, "Chore #1 proc_wrapper was not set\n");
+    ok(task_coll.count == 1, "Wrong chore count: %ld != 1\n", task_coll.count);
+    ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context);
+
+    call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore2.chore);
+    ok(chore2.chore.task_collection == &task_coll, "Wrong chore #2 task_collection: expected %p, actual %p\n",
+            &task_coll, chore2.chore.task_collection);
+    ok(chore2.chore.proc_wrapper != NULL, "Chore #2 proc_wrapper was not set\n");
+    ok(task_coll.count == 2, "Wrong chore count: %ld != 2\n", task_coll.count);
+    ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context);
+
+    b = SetEvent(chore_start_evt);
+    ok(b, "SetEvent failed\n");
+
+    status = p__StructuredTaskCollection__RunAndWait(&task_coll, NULL);
+    ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status);
+    ok(chore1.executed, "Chore #1 was not executed\n");
+    ok(chore2.executed, "Chore #2 was not executed\n");
+    call_func1(p__StructuredTaskCollection_dtor, &task_coll);
+
+    /* test that scheduled chores are executed even if _RunAndWait is not called */
+    call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL);
+    ResetEvent(chore_start_evt);
+    chore_ctor(&chore1);
+    chore1.start_event = chore_start_evt;
+    chore1.set_event = chore_evt1;
+
+    call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore1.chore);
+    ok(chore1.chore.task_collection == &task_coll, "Wrong chore #1 task_collection: expected %p, actual %p\n",
+            &task_coll, chore1.chore.task_collection);
+    ok(chore1.chore.proc_wrapper != NULL, "Chore #1 proc_wrapper was not set\n");
+    ok(task_coll.count == 1, "Wrong chore count: %ld != 1\n", task_coll.count);
+    ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context);
+
+    b = SetEvent(chore_start_evt);
+    ok(b, "SetEvent failed\n");
+
+    ret = WaitForSingleObject(chore_evt1, 5000);
+    ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", ret);
+    ok(chore1.executed, "Chore was not executed\n");
+
+    status = p__StructuredTaskCollection__RunAndWait(&task_coll, NULL);
+    ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status);
+    ok(chore1.chore.task_collection == NULL, "Chore's task collection was not reset after execution\n");
+    call_func1(p__StructuredTaskCollection_dtor, &task_coll);
+
+    /* test that finished chores can be scheduled again */
+    call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL);
+    ResetEvent(chore_start_evt);
+    chore1.set_event = NULL;
+    chore1.executed = FALSE;
+
+    call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore1.chore);
+    ok(chore1.chore.task_collection == &task_coll, "Wrong chore #1 task_collection: expected %p, actual %p\n",
+            &task_coll, chore1.chore.task_collection);
+    ok(chore1.chore.proc_wrapper != NULL, "Chore #1 proc_wrapper was not set\n");
+    ok(task_coll.count == 1, "Wrong chore count: %ld != 1\n", task_coll.count);
+    ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context);
+
+    b = SetEvent(chore_start_evt);
+    ok(b, "SetEvent failed\n");
+
+    status = p__StructuredTaskCollection__RunAndWait(&task_coll, NULL);
+    ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status);
+    ok(chore1.executed, "Chore was not executed\n");
+    call_func1(p__StructuredTaskCollection_dtor, &task_coll);
+
+    CloseHandle(chore_start_evt);
+    CloseHandle(chore_evt1);
+    CloseHandle(chore_evt2);
+}
+
 START_TEST(msvcr120)
 {
     if (!init()) return;
@@ -1292,4 +1560,5 @@ START_TEST(msvcr120)
     test_nexttoward();
     test_towctrans();
     test_CurrentContext();
+    test_StructuredTaskCollection();
 }
-- 
2.36.1




More information about the wine-devel mailing list