Signed-off-by: Torge Matthies tmatthies@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@Concurrency@@IEAAXXZ(ptr) SpinWait__Reset @ stub -arch=arm ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=i386 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z -@ stub -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z +@ thiscall -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z(ptr ptr) StructuredTaskCollection__RunAndWait @ stub -arch=arm ?_RunAndWait@_TaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=i386 ?_RunAndWait@_TaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=win64 ?_RunAndWait@_TaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@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@Concurrency@@IAEXXZ(ptr) SpinWait__Reset @ cdecl -arch=win64 ?_Reset@?$_SpinWait@$0A@@details@Concurrency@@IEAAXXZ(ptr) SpinWait__Reset @ stub -arch=win32 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z -@ stub -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z +@ thiscall -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z(ptr ptr) StructuredTaskCollection__RunAndWait @ stub -arch=win32 ?_RunAndWait@_TaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=win64 ?_RunAndWait@_TaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z @ stub -arch=win32 ?_Schedule@_StructuredTaskCollection@details@Concurrency@@QAEXPAV_UnrealizedChore@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@Concurrency@@IEAAXXZ(ptr) SpinWait__Reset @ stub -arch=arm ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=i386 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z -@ stub -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z +@ thiscall -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z(ptr ptr) StructuredTaskCollection__RunAndWait @ stub -arch=arm ?_RunAndWait@_TaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=i386 ?_RunAndWait@_TaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=win64 ?_RunAndWait@_TaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@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@Concurrency@@IEAAXXZ(ptr) SpinWait__Reset @ stub -arch=arm ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=i386 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z -@ stub -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z +@ thiscall -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z(ptr ptr) StructuredTaskCollection__RunAndWait @ stub -arch=arm ?_RunAndWait@_TaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=i386 ?_RunAndWait@_TaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=win64 ?_RunAndWait@_TaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@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@Concurrency@@IEAAXXZ(ptr) msvcr120.?_Reset@?$_SpinWait@$0A@@details@Concurrency@@IEAAXXZ @ stub -arch=arm ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=i386 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z -@ stub -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z +@ thiscall -arch=win64 ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z(ptr ptr) msvcr120.?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z @ stub -arch=arm ?_RunAndWait@_TaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=i386 ?_RunAndWait@_TaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z @ stub -arch=win64 ?_RunAndWait@_TaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@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@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@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@_StructuredTaskCollection@details@Concurrency@@QEAAXPEAV_UnrealizedChore@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 */