Based on !2524.
This adds the remaining stubs needed for Crazy Machines 3 to work and decode preview images correctly in online mode.
-- v5: 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. msvcr100: Add Context::Block() implementation. msvcr100: Add missing ExternalContextBase virtual functions stubs. msvcr110: Implement _Context::_IsSynchronouslyBlocked.
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 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index ede70116f4a..075ee2f0b16 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]; + BOOL blocked; } ExternalContextBase; extern const vtable_ptr ExternalContextBase_vtable; static void ExternalContextBase_ctor(ExternalContextBase*); @@ -927,7 +928,13 @@ bool __thiscall ExternalContextBase_IsSynchronouslyBlocked(const ExternalContext DEFINE_THISCALL_WRAPPER(ExternalContextBase_Block, 4) void __thiscall ExternalContextBase_Block(ExternalContextBase *this) { - FIXME("(%p)->() stub\n", this); + BOOL blocked = TRUE; + + TRACE("(%p)->()\n", this); + + this->blocked = TRUE; + while (this->blocked) + RtlWaitOnAddress(&this->blocked, &blocked, sizeof(BOOL), NULL); }
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 075ee2f0b16..3a551c7a233 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; }
DEFINE_THISCALL_WRAPPER(ExternalContextBase_Block, 4)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/concurrency.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index 3a551c7a233..e6cf3ddc161 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -915,7 +915,10 @@ 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); + + this->blocked = FALSE; + 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 e6cf3ddc161..67e8d36d5aa 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 @@ -3125,14 +3128,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; } @@ -3166,7 +3161,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);
@@ -3179,11 +3174,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(); @@ -3200,7 +3195,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);
@@ -3222,17 +3217,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); } }
@@ -3310,7 +3305,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); @@ -3318,7 +3313,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; }
I've pushed changed version of your patches: - removed _Cancellation_beacon patches - I think it needs more investigation, I'm not saying that I'm against such a stub but I think we should try harder to understand what it does, I didn't have time to do it now, please open new MR with _Cancellation_beacon changes - correct IsSynchronouslyBlocked virtual function offset - add missing ExternalContextBase virtual functions - use Context blocking functions in reader_writer_lock to show how it should be implemented to get IsSynchronouslyBlocked working
The IsSynchronouslyBlocked function will often return wrong values now. It would be nice to rewrite other functions to use Block()/Unblock(). In order to implement timed waits separate thread/threadpool will need to be used.
This merge request was approved by Piotr Caban.
On Fri Apr 14 16:32:58 2023 +0000, Piotr Caban wrote:
I've pushed changed version of your patches:
- removed _Cancellation_beacon patches - I think it needs more
investigation, I'm not saying that I'm against such a stub but I think we should try harder to understand what it does, I didn't have time to do it now, please open new MR with _Cancellation_beacon changes
- correct IsSynchronouslyBlocked virtual function offset
- add missing ExternalContextBase virtual functions
- use Context blocking functions in reader_writer_lock to show how it
should be implemented to get IsSynchronouslyBlocked working The IsSynchronouslyBlocked function will often return wrong values now. It would be nice to rewrite other functions to use Block()/Unblock(). In order to implement timed waits separate thread/threadpool will need to be used.
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.