[PATCH v5 6/8] msvcr100: Implement _StructuredTaskCollection::_RunAndWait and _Schedule.
Torge Matthies
tmatthies at codeweavers.com
Wed Apr 20 09:33:21 CDT 2022
Signed-off-by: Torge Matthies <tmatthies at codeweavers.com>
---
v4 -> v5:
Merged in the implementation of StructuredTaskCollection_ctor and
StructuredTaskCollection_dtor.
Added the removal of test todos.
dlls/msvcr120/tests/msvcr120.c | 4 +-
dlls/msvcrt/concurrency.c | 161 +++++++++++++++++++++++++++++++--
2 files changed, 154 insertions(+), 11 deletions(-)
diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c
index d1367e274f3..7ea87b0123f 100644
--- a/dlls/msvcr120/tests/msvcr120.c
+++ b/dlls/msvcr120/tests/msvcr120.c
@@ -851,8 +851,8 @@ static void test_StructuredTaskCollection(void)
call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore2);
status = call_func2(p__StructuredTaskCollection__RunAndWait, &task_coll, NULL);
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");
+ ok(chore1_executed, "_StructuredTaskCollection::_RunAndWait did not execute chore1\n");
+ ok(chore2_executed, "_StructuredTaskCollection::_RunAndWait did not execute chore2\n");
call_func1(p__StructuredTaskCollection_dtor, &task_coll);
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c
index 7712b93f1a3..7ede7d8b6a7 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,21 +1805,123 @@ 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 */
DEFINE_THISCALL_WRAPPER(StructuredTaskCollection__RunAndWait, 8)
/*enum Concurrency::details::_TaskCollectionStatus*/int __thiscall 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 */
@@ -1799,7 +1930,19 @@ DEFINE_THISCALL_WRAPPER(StructuredTaskCollection__RunAndWait, 8)
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