[PATCH v4 2/3] msvcr100: Implement _StructuredTaskCollection::_RunAndWait and _Schedule.

Torge Matthies tmatthies at codeweavers.com
Mon Apr 11 09:30:07 CDT 2022


Signed-off-by: Torge Matthies <tmatthies at codeweavers.com>
---
v3 -> v4:
  Implemented execution of the chores in a thread pool.

 dlls/concrt140/concrt140.spec       |   2 +-
 dlls/msvcr100/msvcr100.spec         |   2 +-
 dlls/msvcr110/msvcr110.spec         |   2 +-
 dlls/msvcr120/msvcr120.spec         |   2 +-
 dlls/msvcr120_app/msvcr120_app.spec |   2 +-
 dlls/msvcrt/concurrency.c           | 151 +++++++++++++++++++++++++++-
 6 files changed, 151 insertions(+), 10 deletions(-)

diff --git a/dlls/concrt140/concrt140.spec b/dlls/concrt140/concrt140.spec
index ab57c736672..6b5ab7a5511 100644
--- a/dlls/concrt140/concrt140.spec
+++ b/dlls/concrt140/concrt140.spec
@@ -590,7 +590,7 @@
 @ cdecl -arch=win64 ?_Reset@?$_SpinWait@$0A@@details at Concurrency@@IEAAXXZ(ptr) SpinWait__Reset
 @ stub -arch=arm ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=i386 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
-@ stub -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
+@ thiscall -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z(ptr ptr) StructuredTaskCollection__RunAndWait
 @ stub -arch=arm ?_RunAndWait at _TaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=i386 ?_RunAndWait at _TaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=win64 ?_RunAndWait at _TaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec
index 68a78a6aa16..4b6308193a5 100644
--- a/dlls/msvcr100/msvcr100.spec
+++ b/dlls/msvcr100/msvcr100.spec
@@ -360,7 +360,7 @@
 @ thiscall -arch=win32 ?_Reset@?$_SpinWait@$0A@@details at Concurrency@@IAEXXZ(ptr) SpinWait__Reset
 @ cdecl -arch=win64 ?_Reset@?$_SpinWait@$0A@@details at Concurrency@@IEAAXXZ(ptr) SpinWait__Reset
 @ stub -arch=win32 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
-@ stub -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
+@ thiscall -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z(ptr ptr) StructuredTaskCollection__RunAndWait
 @ stub -arch=win32 ?_RunAndWait at _TaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=win64 ?_RunAndWait at _TaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
 @ stub -arch=win32 ?_Schedule at _StructuredTaskCollection@details at Concurrency@@QAEXPAV_UnrealizedChore at 23@@Z
diff --git a/dlls/msvcr110/msvcr110.spec b/dlls/msvcr110/msvcr110.spec
index 0f5eaf9ac51..64c015b8ab6 100644
--- a/dlls/msvcr110/msvcr110.spec
+++ b/dlls/msvcr110/msvcr110.spec
@@ -610,7 +610,7 @@
 @ cdecl -arch=win64 ?_Reset@?$_SpinWait@$0A@@details at Concurrency@@IEAAXXZ(ptr) SpinWait__Reset
 @ stub -arch=arm ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=i386 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
-@ stub -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
+@ thiscall -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z(ptr ptr) StructuredTaskCollection__RunAndWait
 @ stub -arch=arm ?_RunAndWait at _TaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=i386 ?_RunAndWait at _TaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=win64 ?_RunAndWait at _TaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec
index 332a617932e..46e16257b5d 100644
--- a/dlls/msvcr120/msvcr120.spec
+++ b/dlls/msvcr120/msvcr120.spec
@@ -592,7 +592,7 @@
 @ cdecl -arch=win64 ?_Reset@?$_SpinWait@$0A@@details at Concurrency@@IEAAXXZ(ptr) SpinWait__Reset
 @ stub -arch=arm ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=i386 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
-@ stub -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
+@ thiscall -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z(ptr ptr) StructuredTaskCollection__RunAndWait
 @ stub -arch=arm ?_RunAndWait at _TaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=i386 ?_RunAndWait at _TaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=win64 ?_RunAndWait at _TaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
diff --git a/dlls/msvcr120_app/msvcr120_app.spec b/dlls/msvcr120_app/msvcr120_app.spec
index ee2ee2c42a1..2bf4a5010f8 100644
--- a/dlls/msvcr120_app/msvcr120_app.spec
+++ b/dlls/msvcr120_app/msvcr120_app.spec
@@ -588,7 +588,7 @@
 @ cdecl -arch=win64 ?_Reset@?$_SpinWait@$0A@@details at Concurrency@@IEAAXXZ(ptr) msvcr120.?_Reset@?$_SpinWait@$0A@@details at Concurrency@@IEAAXXZ
 @ stub -arch=arm ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=i386 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
-@ stub -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
+@ thiscall -arch=win64 ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z(ptr ptr) msvcr120.?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
 @ stub -arch=arm ?_RunAndWait at _TaskCollection@details at Concurrency@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=i386 ?_RunAndWait at _TaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z
 @ stub -arch=win64 ?_RunAndWait at _TaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c
index b884952b314..2da39745f93 100644
--- a/dlls/msvcrt/concurrency.c
+++ b/dlls/msvcrt/concurrency.c
@@ -22,8 +22,10 @@
 #include <stdbool.h>
 
 #include "windef.h"
+#include "winbase.h"
 #include "winternl.h"
 #include "wine/debug.h"
+#include "wine/exception.h"
 #include "msvcrt.h"
 #include "cxx.h"
 
@@ -176,14 +178,39 @@ typedef struct cs_queue
 
 #if _MSVCR_VER >= 100
 
-typedef struct
-{
-    char dummy;
+/* This class seems to be 80 bytes big on x86-64, judging by the addresses passed in to
+   StructuredTaskCollection__RunAndWait */
+typedef struct UnrealizedChore
+{
+    void *unk1;
+    void (__cdecl *callback)(struct UnrealizedChore *this, void *unk);
+    void *unk2;
+    void *unk3;
+    void *unk4;
+    void *unk5;
+    void *unk6;
+    void *unk7;
+    void *unk8;
+    void *unk9;
 } UnrealizedChore;
 
+typedef struct StructuredTaskCollectionChoresEntry
+{
+    struct StructuredTaskCollectionChoresEntry *next;
+    UnrealizedChore *chore;
+    TP_WORK *work;
+    volatile LONG *waiting_on_ptr;
+} StructuredTaskCollectionChoresEntry;
+
 typedef struct
 {
-    char dummy;
+    void *unk1;
+    unsigned int unk2;
+    void *unk3;
+    StructuredTaskCollectionChoresEntry *volatile unk_chores;
+    unsigned int count;
+    unsigned int unk5;
+    void *unk6;
 } StructuredTaskCollection;
 
 #endif /* _MSVCR_VER >= 100 */
@@ -1757,11 +1784,125 @@ bool __thiscall SpinWait__SpinOnce(SpinWait *this)
 
 #if _MSVCR_VER >= 100
 
+static void CALLBACK StructuredTaskCollection_threadpool_cb_finally(BOOL normal, void *data)
+{
+    StructuredTaskCollectionChoresEntry *entry = data;
+
+    TRACE("(%u %p)\n", normal, data);
+
+    if (entry->waiting_on_ptr && InterlockedDecrement(entry->waiting_on_ptr) == 0)
+        RtlWakeAddressSingle((void*)entry->waiting_on_ptr);
+}
+
+static inline void StructuredTaskCollection_run_chore(UnrealizedChore *chore, void* unk)
+{
+    if (chore->callback)
+        chore->callback(chore, unk);
+}
+
+static void WINAPI StructuredTaskCollection_threadpool_cb(TP_CALLBACK_INSTANCE *inst, void *data, TP_WORK *work)
+{
+    StructuredTaskCollectionChoresEntry *entry = data;
+
+    TRACE("(%p %p)\n", inst, data);
+
+    __TRY
+    {
+        StructuredTaskCollection_run_chore(entry->chore, NULL);
+    }
+    __FINALLY_CTX(StructuredTaskCollection_threadpool_cb_finally, data)
+}
+
+/* ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z */
+DEFINE_THISCALL_WRAPPER(StructuredTaskCollection__RunAndWait, 8)
+/*enum Concurrency::details::_TaskCollectionStatus*/int __thiscall StructuredTaskCollection__RunAndWait(StructuredTaskCollection *this, UnrealizedChore *chore)
+{
+    StructuredTaskCollectionChoresEntry *chores, *entry, *next;
+    LONG total_count = 0, created_count = 0;
+    TP_POOL *tpool = NULL;
+    TP_CALLBACK_ENVIRON cbenv;
+    volatile LONG waiting_on = 0;
+    int ret = 1;
+    LONG val;
+
+    TRACE("(%p %p)\n", this, chore);
+
+    chores = InterlockedExchangePointer((void *volatile *)&this->unk_chores, NULL);
+    this->count = 0;
+
+    if (!chores)
+        return ret;
+
+    for (entry = chores; entry; entry = entry->next)
+        total_count++;
+
+    tpool = CreateThreadpool(NULL);
+    if (!tpool || !SetThreadpoolThreadMinimum(tpool, total_count))
+        goto done;
+    SetThreadpoolThreadMaximum(tpool, total_count);
+
+    memset(&cbenv, 0, sizeof(cbenv));
+    cbenv.Version = 1;
+    cbenv.Pool = tpool;
+
+    for (entry = chores; entry; entry = entry->next)
+    {
+        entry->waiting_on_ptr = &waiting_on;
+        entry->work = CreateThreadpoolWork(StructuredTaskCollection_threadpool_cb, entry, &cbenv);
+        if (!entry->work)
+        {
+            ret = 0;
+            goto done;
+        }
+        created_count++;
+    }
+
+    InterlockedExchange(&waiting_on, created_count);
+    for (entry = chores; entry; entry = entry->next)
+        SubmitThreadpoolWork(entry->work);
+
+    if (chore)
+        StructuredTaskCollection_run_chore(chore, NULL);
+
+    TRACE("waiting on %u workers\n", created_count);
+
+    while ((val = InterlockedCompareExchange(&waiting_on, 0, 0)))
+        RtlWaitOnAddress((void*)&waiting_on, (void*)&val, sizeof(waiting_on), NULL);
+
+done:
+    for (entry = chores; entry; entry = next)
+    {
+        if (created_count > 0)
+        {
+            CloseThreadpoolWork(entry->work);
+            created_count--;
+        }
+        next = entry->next;
+        operator_delete(entry);
+    }
+
+    if (tpool) CloseThreadpool(tpool);
+
+    return ret;
+}
+
 /* ?_Schedule at _StructuredTaskCollection@details at Concurrency@@QEAAXPEAV_UnrealizedChore at 23@@Z */
 DEFINE_THISCALL_WRAPPER(StructuredTaskCollection__Schedule, 8)
 void __thiscall StructuredTaskCollection__Schedule(StructuredTaskCollection *this, UnrealizedChore *chore)
 {
-    FIXME("(%p %p): stub!\n", this, chore);
+    StructuredTaskCollectionChoresEntry *entry, *next;
+
+    TRACE("(%p %p)\n", this, chore);
+
+    entry = operator_new(sizeof(StructuredTaskCollectionChoresEntry));
+    entry->chore = chore;
+    do
+    {
+        next = this->unk_chores;
+        entry->next = next;
+    }
+    while (InterlockedCompareExchangePointer((void *volatile *)&this->unk_chores, entry, next) != next);
+    this->count++;
 }
 
 #endif /* _MSVCR_VER >= 100 */
-- 
2.35.1




More information about the wine-devel mailing list