Based on !2524.
This adds the remaining stubs needed for Crazy Machines 3 to work and decode preview images correctly in online mode.
-- v6: msvcr100: Use Context blocking functions in reader_writer_lock class. msvcr100: Add ExternalContextBase::Unblock implementation. msvcr100: Add ExternalContextBase::IsSynchronouslyBlocked() implementation. msvcr100: Add ExternalContextBase::Block() implementation.
From: Torge Matthies tmatthies@codeweavers.com
--- dlls/msvcr110/msvcr110.spec | 6 +++--- dlls/msvcr120/msvcr120.spec | 6 +++--- dlls/msvcr120_app/msvcr120_app.spec | 6 +++--- dlls/msvcrt/concurrency.c | 9 +++++++++ 4 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/dlls/msvcr110/msvcr110.spec b/dlls/msvcr110/msvcr110.spec index 1032c9e4c7a..da4e22960b9 100644 --- a/dlls/msvcr110/msvcr110.spec +++ b/dlls/msvcr110/msvcr110.spec @@ -550,9 +550,9 @@ @ stub -arch=arm ?_IsCanceling@_TaskCollection@details@Concurrency@@QAA_NXZ @ stub -arch=i386 ?_IsCanceling@_TaskCollection@details@Concurrency@@QAE_NXZ @ stub -arch=win64 ?_IsCanceling@_TaskCollection@details@Concurrency@@QEAA_NXZ -@ stub -arch=arm ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBA_NXZ -@ stub -arch=i386 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBE_NXZ -@ stub -arch=win64 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QEBA_NXZ +@ cdecl -arch=arm ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBA_NXZ(ptr) _Context_IsSynchronouslyBlocked +@ thiscall -arch=i386 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBE_NXZ(ptr) _Context_IsSynchronouslyBlocked +@ cdecl -arch=win64 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QEBA_NXZ(ptr) _Context_IsSynchronouslyBlocked @ stub -arch=win32 ?_Name_base@type_info@@CAPBDPBV1@PAU__type_info_node@@@Z @ stub -arch=win64 ?_Name_base@type_info@@CAPEBDPEBV1@PEAU__type_info_node@@@Z @ stub -arch=win32 ?_Name_base_internal@type_info@@CAPBDPBV1@PAU__type_info_node@@@Z diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec index ca11ea4b49d..1eff4e82f61 100644 --- a/dlls/msvcr120/msvcr120.spec +++ b/dlls/msvcr120/msvcr120.spec @@ -541,9 +541,9 @@ @ stub -arch=arm ?_IsCanceling@_TaskCollection@details@Concurrency@@QAA_NXZ @ stub -arch=i386 ?_IsCanceling@_TaskCollection@details@Concurrency@@QAE_NXZ @ stub -arch=win64 ?_IsCanceling@_TaskCollection@details@Concurrency@@QEAA_NXZ -@ stub -arch=arm ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBA_NXZ -@ stub -arch=i386 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBE_NXZ -@ stub -arch=win64 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QEBA_NXZ +@ cdecl -arch=arm ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBA_NXZ(ptr) _Context_IsSynchronouslyBlocked +@ thiscall -arch=i386 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBE_NXZ(ptr) _Context_IsSynchronouslyBlocked +@ cdecl -arch=win64 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QEBA_NXZ(ptr) _Context_IsSynchronouslyBlocked @ stub -arch=win32 ?_Name_base@type_info@@CAPBDPBV1@PAU__type_info_node@@@Z @ stub -arch=win64 ?_Name_base@type_info@@CAPEBDPEBV1@PEAU__type_info_node@@@Z @ stub -arch=win32 ?_Name_base_internal@type_info@@CAPBDPBV1@PAU__type_info_node@@@Z diff --git a/dlls/msvcr120_app/msvcr120_app.spec b/dlls/msvcr120_app/msvcr120_app.spec index aad6ece8acc..bb1d6914c40 100644 --- a/dlls/msvcr120_app/msvcr120_app.spec +++ b/dlls/msvcr120_app/msvcr120_app.spec @@ -538,9 +538,9 @@ @ stub -arch=arm ?_IsCanceling@_TaskCollection@details@Concurrency@@QAA_NXZ @ stub -arch=i386 ?_IsCanceling@_TaskCollection@details@Concurrency@@QAE_NXZ @ stub -arch=win64 ?_IsCanceling@_TaskCollection@details@Concurrency@@QEAA_NXZ -@ stub -arch=arm ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBA_NXZ -@ stub -arch=i386 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBE_NXZ -@ stub -arch=win64 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QEBA_NXZ +@ cdecl -arch=arm ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBA_NXZ(ptr) msvcr120.?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBA_NXZ +@ thiscall -arch=i386 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBE_NXZ(ptr) msvcr120.?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QBE_NXZ +@ cdecl -arch=win64 ?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QEBA_NXZ(ptr) msvcr120.?_IsSynchronouslyBlocked@_Context@details@Concurrency@@QEBA_NXZ @ stub -arch=win32 ?_Name_base@type_info@@CAPBDPBV1@PAU__type_info_node@@@Z @ stub -arch=win64 ?_Name_base@type_info@@CAPEBDPEBV1@PEAU__type_info_node@@@Z @ stub -arch=win32 ?_Name_base_internal@type_info@@CAPBDPBV1@PAU__type_info_node@@@Z diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index d148aadd13a..f81cd9571a3 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -68,6 +68,8 @@ typedef struct { unsigned int, (const Context*), (this)) #define call_Context_GetScheduleGroupId(this) CALL_VTBL_FUNC(this, 8, \ unsigned int, (const Context*), (this)) +#define call_Context_IsSynchronouslyBlocked(this) CALL_VTBL_FUNC(this, 16, \ + bool, (const Context*), (this)) #define call_Context_dtor(this, flags) CALL_VTBL_FUNC(this, 20, \ Context*, (Context*, unsigned int), (this, flags))
@@ -875,6 +877,13 @@ _Context *__cdecl _Context__CurrentContext(_Context *ret) ret->context = Context_CurrentContext(); return ret; } + +DEFINE_THISCALL_WRAPPER(_Context_IsSynchronouslyBlocked, 4) +BOOL __thiscall _Context_IsSynchronouslyBlocked(const _Context *this) +{ + TRACE("(%p)\n", this); + return call_Context_IsSynchronouslyBlocked(this->context); +} #endif
DEFINE_THISCALL_WRAPPER(ExternalContextBase_GetId, 4)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/concurrency.c | 94 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index f81cd9571a3..42ca4ed7d19 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -920,6 +920,86 @@ bool __thiscall ExternalContextBase_IsSynchronouslyBlocked(const ExternalContext return FALSE; }
+DEFINE_THISCALL_WRAPPER(ExternalContextBase_Block, 4) +void __thiscall ExternalContextBase_Block(ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_Yield, 4) +void __thiscall ExternalContextBase_Yield(ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_SpinYield, 4) +void __thiscall ExternalContextBase_SpinYield(ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_Oversubscribe, 8) +void __thiscall ExternalContextBase_Oversubscribe( + ExternalContextBase *this, bool oversubscribe) +{ + FIXME("(%p)->(%x) stub\n", this, oversubscribe); +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_Alloc, 8) +void* __thiscall ExternalContextBase_Alloc(ExternalContextBase *this, size_t size) +{ + FIXME("(%p)->(%Iu) stub\n", this, size); + return NULL; +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_Free, 8) +void __thiscall ExternalContextBase_Free(ExternalContextBase *this, void *addr) +{ + FIXME("(%p)->(%p) stub\n", this, addr); +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_EnterCriticalRegionHelper, 4) +int __thiscall ExternalContextBase_EnterCriticalRegionHelper(ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); + return 0; +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_EnterHyperCriticalRegionHelper, 4) +int __thiscall ExternalContextBase_EnterHyperCriticalRegionHelper(ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); + return 0; +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_ExitCriticalRegionHelper, 4) +int __thiscall ExternalContextBase_ExitCriticalRegionHelper(ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); + return 0; +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_ExitHyperCriticalRegionHelper, 4) +int __thiscall ExternalContextBase_ExitHyperCriticalRegionHelper(ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); + return 0; +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_GetCriticalRegionType, 4) +int __thiscall ExternalContextBase_GetCriticalRegionType(const ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); + return 0; +} + +DEFINE_THISCALL_WRAPPER(ExternalContextBase_GetContextKind, 4) +int __thiscall ExternalContextBase_GetContextKind(const ExternalContextBase *this) +{ + FIXME("(%p)->() stub\n", this); + return 0; +} + static void remove_scheduled_chores(Scheduler *scheduler, const ExternalContextBase *context) { ThreadScheduler *tscheduler = (ThreadScheduler*)scheduler; @@ -3483,7 +3563,19 @@ __ASM_BLOCK_BEGIN(concurrency_vtables) VTABLE_ADD_FUNC(ExternalContextBase_GetScheduleGroupId) VTABLE_ADD_FUNC(ExternalContextBase_Unblock) VTABLE_ADD_FUNC(ExternalContextBase_IsSynchronouslyBlocked) - VTABLE_ADD_FUNC(ExternalContextBase_vector_dtor)); + VTABLE_ADD_FUNC(ExternalContextBase_vector_dtor) + VTABLE_ADD_FUNC(ExternalContextBase_Block) + VTABLE_ADD_FUNC(ExternalContextBase_Yield) + VTABLE_ADD_FUNC(ExternalContextBase_SpinYield) + VTABLE_ADD_FUNC(ExternalContextBase_Oversubscribe) + VTABLE_ADD_FUNC(ExternalContextBase_Alloc) + VTABLE_ADD_FUNC(ExternalContextBase_Free) + VTABLE_ADD_FUNC(ExternalContextBase_EnterCriticalRegionHelper) + VTABLE_ADD_FUNC(ExternalContextBase_EnterHyperCriticalRegionHelper) + VTABLE_ADD_FUNC(ExternalContextBase_ExitCriticalRegionHelper) + VTABLE_ADD_FUNC(ExternalContextBase_ExitHyperCriticalRegionHelper) + VTABLE_ADD_FUNC(ExternalContextBase_GetCriticalRegionType) + VTABLE_ADD_FUNC(ExternalContextBase_GetContextKind)); __ASM_VTABLE(ThreadScheduler, VTABLE_ADD_FUNC(ThreadScheduler_vector_dtor) VTABLE_ADD_FUNC(ThreadScheduler_Id)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/concurrency.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index 42ca4ed7d19..ede70116f4a 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -72,6 +72,8 @@ typedef struct { bool, (const Context*), (this)) #define call_Context_dtor(this, flags) CALL_VTBL_FUNC(this, 20, \ Context*, (Context*, unsigned int), (this, flags)) +#define call_Context_Block(this) CALL_VTBL_FUNC(this, 24, \ + void, (Context*), (this))
typedef struct { Context *context; @@ -824,7 +826,9 @@ unsigned int __cdecl Context_Id(void) /* ?Block@Context@Concurrency@@SAXXZ */ void __cdecl Context_Block(void) { - FIXME("()\n"); + Context *ctx = get_current_context(); + TRACE("()\n"); + call_Context_Block(ctx); }
/* ?Yield@Context@Concurrency@@SAXXZ */
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/concurrency.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index ede70116f4a..565b911425e 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -100,6 +100,7 @@ typedef struct { struct scheduler_list scheduler; unsigned int id; union allocator_cache_entry *allocator_cache[8]; + LONG blocked; } ExternalContextBase; extern const vtable_ptr ExternalContextBase_vtable; static void ExternalContextBase_ctor(ExternalContextBase*); @@ -927,7 +928,16 @@ bool __thiscall ExternalContextBase_IsSynchronouslyBlocked(const ExternalContext DEFINE_THISCALL_WRAPPER(ExternalContextBase_Block, 4) void __thiscall ExternalContextBase_Block(ExternalContextBase *this) { - FIXME("(%p)->() stub\n", this); + LONG blocked; + + TRACE("(%p)->()\n", this); + + blocked = InterlockedIncrement(&this->blocked); + while (blocked >= 1) + { + RtlWaitOnAddress(&this->blocked, &blocked, sizeof(LONG), NULL); + blocked = this->blocked; + } }
DEFINE_THISCALL_WRAPPER(ExternalContextBase_Yield, 4)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/concurrency.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index 565b911425e..d7520ac308c 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -921,8 +921,8 @@ void __thiscall ExternalContextBase_Unblock(ExternalContextBase *this) DEFINE_THISCALL_WRAPPER(ExternalContextBase_IsSynchronouslyBlocked, 4) bool __thiscall ExternalContextBase_IsSynchronouslyBlocked(const ExternalContextBase *this) { - FIXME("(%p)->() stub\n", this); - return FALSE; + TRACE("(%p)->()\n", this); + return this->blocked >= 1; }
DEFINE_THISCALL_WRAPPER(ExternalContextBase_Block, 4)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/concurrency.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index d7520ac308c..d524deb9e2c 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -915,7 +915,11 @@ unsigned int __thiscall ExternalContextBase_GetScheduleGroupId(const ExternalCon DEFINE_THISCALL_WRAPPER(ExternalContextBase_Unblock, 4) void __thiscall ExternalContextBase_Unblock(ExternalContextBase *this) { - FIXME("(%p)->() stub\n", this); + TRACE("(%p)->()\n", this); + + /* TODO: throw context_unblock_unbalanced if this->blocked goes below -1 */ + if (InterlockedDecrement(&this->blocked) < 1) + RtlWakeAddressSingle(&this->blocked); }
DEFINE_THISCALL_WRAPPER(ExternalContextBase_IsSynchronouslyBlocked, 4)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/concurrency.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index d524deb9e2c..aede8069be7 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -68,6 +68,8 @@ typedef struct { unsigned int, (const Context*), (this)) #define call_Context_GetScheduleGroupId(this) CALL_VTBL_FUNC(this, 8, \ unsigned int, (const Context*), (this)) +#define call_Context_Unblock(this) CALL_VTBL_FUNC(this, 12, \ + void, (Context*), (this)) #define call_Context_IsSynchronouslyBlocked(this) CALL_VTBL_FUNC(this, 16, \ bool, (const Context*), (this)) #define call_Context_dtor(this, flags) CALL_VTBL_FUNC(this, 20, \ @@ -324,6 +326,7 @@ typedef struct { typedef struct rwl_queue { struct rwl_queue *next; + Context *ctx; } rwl_queue;
#define WRITER_WAITING 0x80000000 @@ -3129,14 +3132,6 @@ reader_writer_lock* __thiscall reader_writer_lock_ctor(reader_writer_lock *this) { TRACE("(%p)\n", this);
- if (!keyed_event) { - HANDLE event; - - NtCreateKeyedEvent(&event, GENERIC_READ|GENERIC_WRITE, NULL, 0); - if (InterlockedCompareExchangePointer(&keyed_event, event, NULL) != NULL) - NtClose(event); - } - memset(this, 0, sizeof(*this)); return this; } @@ -3170,7 +3165,7 @@ static inline void spin_wait_for_next_rwl(rwl_queue *q) DEFINE_THISCALL_WRAPPER(reader_writer_lock_lock, 4) void __thiscall reader_writer_lock_lock(reader_writer_lock *this) { - rwl_queue q = { NULL }, *last; + rwl_queue q = { NULL, get_current_context() }, *last;
TRACE("(%p)\n", this);
@@ -3183,11 +3178,11 @@ void __thiscall reader_writer_lock_lock(reader_writer_lock *this) last = InterlockedExchangePointer((void**)&this->writer_tail, &q); if (last) { last->next = &q; - NtWaitForKeyedEvent(keyed_event, &q, 0, NULL); + call_Context_Block(q.ctx); } else { this->writer_head = &q; if (InterlockedOr(&this->count, WRITER_WAITING)) - NtWaitForKeyedEvent(keyed_event, &q, 0, NULL); + call_Context_Block(q.ctx); }
this->thread_id = GetCurrentThreadId(); @@ -3204,7 +3199,7 @@ void __thiscall reader_writer_lock_lock(reader_writer_lock *this) DEFINE_THISCALL_WRAPPER(reader_writer_lock_lock_read, 4) void __thiscall reader_writer_lock_lock_read(reader_writer_lock *this) { - rwl_queue q; + rwl_queue q = { NULL, get_current_context() };
TRACE("(%p)\n", this);
@@ -3226,17 +3221,17 @@ void __thiscall reader_writer_lock_lock_read(reader_writer_lock *this) if (InterlockedCompareExchange(&this->count, count+1, count) == count) break;
if (count & WRITER_WAITING) - NtWaitForKeyedEvent(keyed_event, &q, 0, NULL); + call_Context_Block(q.ctx);
head = InterlockedExchangePointer((void**)&this->reader_head, NULL); while(head && head != &q) { rwl_queue *next = head->next; InterlockedIncrement(&this->count); - NtReleaseKeyedEvent(keyed_event, head, 0, NULL); + call_Context_Unblock(head->ctx); head = next; } } else { - NtWaitForKeyedEvent(keyed_event, &q, 0, NULL); + call_Context_Block(q.ctx); } }
@@ -3314,7 +3309,7 @@ void __thiscall reader_writer_lock_unlock(reader_writer_lock *this) this->thread_id = 0; next = this->writer_head->next; if (next) { - NtReleaseKeyedEvent(keyed_event, next, 0, NULL); + call_Context_Unblock(next->ctx); return; } InterlockedAnd(&this->count, ~WRITER_WAITING); @@ -3322,7 +3317,7 @@ void __thiscall reader_writer_lock_unlock(reader_writer_lock *this) while (head) { next = head->next; InterlockedIncrement(&this->count); - NtReleaseKeyedEvent(keyed_event, head, 0, NULL); + call_Context_Unblock(head->ctx); head = next; }
On Fri Apr 14 16:33:16 2023 +0000, Torge Matthies wrote:
I didn't think that this is how `IsSynchronouslyBlocked` was implemented, I thought it was unrelated to `Block`, but this makes sense. This implementation of `Block`/`Unblock` is racy though, an earlier call to `Unblock` doesn't unblock a later call to `Block`, while the documentation explicitly states that it should. But that's an easy fix, I'll just make `blocked` a LONG.
Thanks for spotting it.
Piotr Caban (@piotr) commented about dlls/msvcrt/concurrency.c:
DEFINE_THISCALL_WRAPPER(ExternalContextBase_Unblock, 4) void __thiscall ExternalContextBase_Unblock(ExternalContextBase *this) {
- FIXME("(%p)->() stub\n", this);
- TRACE("(%p)->()\n", this);
- /* TODO: throw context_unblock_unbalanced if this->blocked goes below -1 */
- if (InterlockedDecrement(&this->blocked) < 1)
RtlWakeAddressSingle(&this->blocked);
Is the if condition correct? It looks like it should be following: ```suggestion:-1+0 if (!InterlockedDecrement(&this->blocked)) RtlWakeAddressSingle(&this->blocked); ```
On Fri Apr 14 17:26:51 2023 +0000, Piotr Caban wrote:
Is the if condition correct? It looks like it should be following:
if (!InterlockedDecrement(&this->blocked)) RtlWakeAddressSingle(&this->blocked);
True, that would work better