[PATCH v6 6/8] msvcr100: Implement _StructuredTaskCollection::_RunAndWait and _Schedule.
Torge Matthies
tmatthies at codeweavers.com
Mon Apr 25 08:56:30 CDT 2022
Signed-off-by: Torge Matthies <tmatthies at codeweavers.com>
---
dlls/msvcr120/tests/msvcr120.c | 6 +-
dlls/msvcrt/concurrency.c | 161 +++++++++++++++++++++++++++++++--
2 files changed, 155 insertions(+), 12 deletions(-)
diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c
index 1fde3afed4a8..a5e78fceb527 100644
--- a/dlls/msvcr120/tests/msvcr120.c
+++ b/dlls/msvcr120/tests/msvcr120.c
@@ -858,9 +858,9 @@ static void test_StructuredTaskCollection(void)
call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore2);
status = p__StructuredTaskCollection__RunAndWait(&task_coll, &main_chore);
ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status);
- todo_wine ok(chore1_executed, "_StructuredTaskCollection::_RunAndWait did not execute chore1\n");
- todo_wine ok(chore2_executed, "_StructuredTaskCollection::_RunAndWait did not execute chore2\n");
- todo_wine ok(main_chore_executed, "_StructuredTaskCollection::_RunAndWait did not execute the main chore\n");
+ ok(chore1_executed, "_StructuredTaskCollection::_RunAndWait did not execute chore1\n");
+ ok(chore2_executed, "_StructuredTaskCollection::_RunAndWait did not execute chore2\n");
+ ok(main_chore_executed, "_StructuredTaskCollection::_RunAndWait did not execute the main chore\n");
call_func1(p__StructuredTaskCollection_dtor, &task_coll);
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c
index 4153661091e5..eefc2b4274b6 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 */
@@ -1763,7 +1790,9 @@ bool __thiscall SpinWait__SpinOnce(SpinWait *this)
DEFINE_THISCALL_WRAPPER(StructuredTaskCollection_ctor, 8)
void __thiscall StructuredTaskCollection_ctor(StructuredTaskCollection *this, void *unk)
{
- FIXME("(%p): stub!\n", this);
+ FIXME("(%p): semi-stub!\n", this);
+
+ memset(this, 0, sizeof(*this));
}
#endif /* _MSVCR_VER >= 100 */
@@ -1776,20 +1805,122 @@ void __thiscall StructuredTaskCollection_ctor(StructuredTaskCollection *this, vo
DEFINE_THISCALL_WRAPPER(StructuredTaskCollection_dtor, 4)
void __thiscall StructuredTaskCollection_dtor(StructuredTaskCollection *this)
{
- FIXME("(%p): stub!\n", this);
+ StructuredTaskCollectionChoresEntry *entry, *next;
+
+ TRACE("(%p)\n", this);
+
+ for (entry = this->unk_chores; entry; entry = next)
+ {
+ next = entry->next;
+ operator_delete(entry);
+ }
}
#endif /* _MSVCR_VER >= 120 */
#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@@QAA?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z */
/* ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QAG?AW4_TaskCollectionStatus at 23@PAV_UnrealizedChore at 23@@Z */
/* ?_RunAndWait at _StructuredTaskCollection@details at Concurrency@@QEAA?AW4_TaskCollectionStatus at 23@PEAV_UnrealizedChore at 23@@Z */
/*enum Concurrency::details::_TaskCollectionStatus*/int __stdcall StructuredTaskCollection__RunAndWait(StructuredTaskCollection *this, UnrealizedChore *chore)
{
- FIXME("(%p %p): stub!\n", this, chore);
- return 1;
+ 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 %lu 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@@QAAXPAV_UnrealizedChore at 23@@Z */
@@ -1798,7 +1929,19 @@ void __thiscall StructuredTaskCollection_dtor(StructuredTaskCollection *this)
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.36.0
More information about the wine-devel
mailing list