- Based on !463 - _RunAndWait and exception handling implemented in later commits
@piotr
-- v6: msvcr100: Implement _StructuredTaskCollection::_Schedule and _Schedule_loc. msvcr100: Factor out the mapping of a context to a scheduler. msvcr100: Cache one Context instance. msvcr100: Factor out EXCEPTION_RECORD to exception_ptr conversion. msvcr100: Move exception_ptr functions to a separate file.
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/msvcr100/Makefile.in | 1 + dlls/msvcr110/Makefile.in | 1 + dlls/msvcr120/Makefile.in | 1 + dlls/msvcrt/cpp.c | 358 ++---------------------------------- dlls/msvcrt/cxx.h | 8 + dlls/msvcrt/exception_ptr.c | 329 +++++++++++++++++++++++++++++++++ dlls/ucrtbase/Makefile.in | 1 + 7 files changed, 358 insertions(+), 341 deletions(-) create mode 100644 dlls/msvcrt/exception_ptr.c
diff --git a/dlls/msvcr100/Makefile.in b/dlls/msvcr100/Makefile.in index a48ae314257..d17aa79b3d7 100644 --- a/dlls/msvcr100/Makefile.in +++ b/dlls/msvcr100/Makefile.in @@ -19,6 +19,7 @@ C_SRCS = \ except_arm64.c \ except_i386.c \ except_x86_64.c \ + exception_ptr.c \ exit.c \ file.c \ heap.c \ diff --git a/dlls/msvcr110/Makefile.in b/dlls/msvcr110/Makefile.in index 26db1d46f7a..0bc15e27d94 100644 --- a/dlls/msvcr110/Makefile.in +++ b/dlls/msvcr110/Makefile.in @@ -19,6 +19,7 @@ C_SRCS = \ except_arm64.c \ except_i386.c \ except_x86_64.c \ + exception_ptr.c \ exit.c \ file.c \ heap.c \ diff --git a/dlls/msvcr120/Makefile.in b/dlls/msvcr120/Makefile.in index d2957c2f1d3..cc3d5b2bdff 100644 --- a/dlls/msvcr120/Makefile.in +++ b/dlls/msvcr120/Makefile.in @@ -19,6 +19,7 @@ C_SRCS = \ except_arm64.c \ except_i386.c \ except_x86_64.c \ + exception_ptr.c \ exit.c \ file.c \ heap.c \ diff --git a/dlls/msvcrt/cpp.c b/dlls/msvcrt/cpp.c index f3200e046cb..27ae2bbd46d 100644 --- a/dlls/msvcrt/cpp.c +++ b/dlls/msvcrt/cpp.c @@ -583,7 +583,9 @@ DEFINE_RTTI_DATA1( bad_cast, 0, &exception_rtti_base_descriptor, ".?AVbad_cast@@ DEFINE_RTTI_DATA2( __non_rtti_object, 0, &bad_typeid_rtti_base_descriptor, &exception_rtti_base_descriptor, ".?AV__non_rtti_object@@" ) #endif
+#if _MSVCR_VER >= 100 DEFINE_CXX_EXCEPTION0( exception, exception_dtor ) +#endif DEFINE_CXX_DATA1( bad_typeid, &exception_cxx_type_info, bad_typeid_dtor ) DEFINE_CXX_DATA1( bad_cast, &exception_cxx_type_info, bad_cast_dtor ) DEFINE_CXX_DATA2( __non_rtti_object, &bad_typeid_cxx_type_info, @@ -605,7 +607,11 @@ void msvcrt_init_exception(void *base) init_bad_cast_rtti(base); init___non_rtti_object_rtti(base);
+#if _MSVCR_VER >= 100 init_exception_cxx(base); +#else + init_exception_cxx_type_info(base); +#endif init_bad_typeid_cxx(base); init_bad_cast_cxx(base); init___non_rtti_object_cxx(base); @@ -624,6 +630,16 @@ void throw_bad_alloc(void) } #endif
+#if _MSVCR_VER >= 100 +void throw_exception(const char* msg) +{ + exception e; + __exception_ctor(&e, msg, &exception_vtable); + _CxxThrowException(&e, &exception_exception_type); + +} +#endif + /****************************************************************** * ?set_terminate@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) * @@ -1128,351 +1144,11 @@ const char * __thiscall type_info_name_internal_method(type_info * _this, struct return type_info_name(_this); }
-#endif /* _MSVCR_VER >= 80 */ - -/* std::exception_ptr class helpers */ -typedef struct -{ - EXCEPTION_RECORD *rec; - LONG *ref; /* not binary compatible with native msvcr100 */ -} exception_ptr; - -#if _MSVCR_VER >= 100 - -/********************************************************************* - * ?__ExceptionPtrCreate@@YAXPAX@Z - * ?__ExceptionPtrCreate@@YAXPEAX@Z - */ -void __cdecl __ExceptionPtrCreate(exception_ptr *ep) -{ - TRACE("(%p)\n", ep); - - ep->rec = NULL; - ep->ref = NULL; -} - -#ifdef __ASM_USE_THISCALL_WRAPPER -extern void call_dtor(const cxx_exception_type *type, void *func, void *object); - -__ASM_GLOBAL_FUNC( call_dtor, - "movl 12(%esp),%ecx\n\t" - "call *8(%esp)\n\t" - "ret" ); -#elif __x86_64__ -static inline void call_dtor(const cxx_exception_type *type, unsigned int dtor, void *object) -{ - char *base = RtlPcToFileHeader((void*)type, (void**)&base); - void (__cdecl *func)(void*) = (void*)(base + dtor); - func(object); -} -#else -#define call_dtor(type, func, object) ((void (__thiscall*)(void*))(func))(object) -#endif - -/********************************************************************* - * ?__ExceptionPtrDestroy@@YAXPAX@Z - * ?__ExceptionPtrDestroy@@YAXPEAX@Z - */ -void __cdecl __ExceptionPtrDestroy(exception_ptr *ep) -{ - TRACE("(%p)\n", ep); - - if (!ep->rec) - return; - - if (!InterlockedDecrement(ep->ref)) - { - if (ep->rec->ExceptionCode == CXX_EXCEPTION) - { - const cxx_exception_type *type = (void*)ep->rec->ExceptionInformation[2]; - void *obj = (void*)ep->rec->ExceptionInformation[1]; - - if (type && type->destructor) call_dtor(type, type->destructor, obj); - HeapFree(GetProcessHeap(), 0, obj); - } - - HeapFree(GetProcessHeap(), 0, ep->rec); - HeapFree(GetProcessHeap(), 0, ep->ref); - } -} - -/********************************************************************* - * ?__ExceptionPtrCopy@@YAXPAXPBX@Z - * ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z - */ -void __cdecl __ExceptionPtrCopy(exception_ptr *ep, const exception_ptr *copy) -{ - TRACE("(%p %p)\n", ep, copy); - - /* don't destroy object stored in ep */ - *ep = *copy; - if (ep->ref) - InterlockedIncrement(copy->ref); -} - -/********************************************************************* - * ?__ExceptionPtrAssign@@YAXPAXPBX@Z - * ?__ExceptionPtrAssign@@YAXPEAXPEBX@Z - */ -void __cdecl __ExceptionPtrAssign(exception_ptr *ep, const exception_ptr *assign) -{ - TRACE("(%p %p)\n", ep, assign); - - /* don't destroy object stored in ep */ - if (ep->ref) - InterlockedDecrement(ep->ref); - - *ep = *assign; - if (ep->ref) - InterlockedIncrement(ep->ref); -} - -#endif /* _MSVCR_VER >= 100 */ - -/********************************************************************* - * ?__ExceptionPtrRethrow@@YAXPBX@Z - * ?__ExceptionPtrRethrow@@YAXPEBX@Z - */ -void __cdecl __ExceptionPtrRethrow(const exception_ptr *ep) -{ - TRACE("(%p)\n", ep); - - if (!ep->rec) - { - static const char *exception_msg = "bad exception"; - exception e; - - exception_ctor(&e, &exception_msg); - _CxxThrowException(&e, &exception_exception_type); - return; - } - - RaiseException(ep->rec->ExceptionCode, ep->rec->ExceptionFlags & (~EH_UNWINDING), - ep->rec->NumberParameters, ep->rec->ExceptionInformation); -} - -#if _MSVCR_VER >= 100 - -#ifdef __i386__ -extern void call_copy_ctor( void *func, void *this, void *src, int has_vbase ); -#else -static inline void call_copy_ctor( void *func, void *this, void *src, int has_vbase ) -{ - TRACE( "calling copy ctor %p object %p src %p\n", func, this, src ); - if (has_vbase) - ((void (__cdecl*)(void*, void*, BOOL))func)(this, src, 1); - else - ((void (__cdecl*)(void*, void*))func)(this, src); -} -#endif - -/********************************************************************* - * ?__ExceptionPtrCurrentException@@YAXPAX@Z - * ?__ExceptionPtrCurrentException@@YAXPEAX@Z - */ -#ifndef __x86_64__ -void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) -{ - EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record; - - TRACE("(%p)\n", ep); - - if (!rec) - { - ep->rec = NULL; - ep->ref = NULL; - return; - } - - ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); - ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); - - *ep->rec = *rec; - *ep->ref = 1; - - if (ep->rec->ExceptionCode == CXX_EXCEPTION) - { - const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2]; - const cxx_type_info *ti; - void **data, *obj; - - ti = et->type_info_table->info[0]; - data = HeapAlloc(GetProcessHeap(), 0, ti->size); - - obj = (void*)ep->rec->ExceptionInformation[1]; - if (ti->flags & CLASS_IS_SIMPLE_TYPE) - { - memcpy(data, obj, ti->size); - if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); - } - else if (ti->copy_ctor) - { - call_copy_ctor(ti->copy_ctor, data, get_this_pointer(&ti->offsets, obj), - ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); - } - else - memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size); - ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; - } - return; -} -#else -void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) -{ - EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record; - - TRACE("(%p)\n", ep); - - if (!rec) - { - ep->rec = NULL; - ep->ref = NULL; - return; - } - - ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); - ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); - - *ep->rec = *rec; - *ep->ref = 1; - - if (ep->rec->ExceptionCode == CXX_EXCEPTION) - { - const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2]; - const cxx_type_info *ti; - void **data, *obj; - char *base = RtlPcToFileHeader((void*)et, (void**)&base); - - ti = (const cxx_type_info*)(base + ((const cxx_type_info_table*)(base + et->type_info_table))->info[0]); - data = HeapAlloc(GetProcessHeap(), 0, ti->size); - - obj = (void*)ep->rec->ExceptionInformation[1]; - if (ti->flags & CLASS_IS_SIMPLE_TYPE) - { - memcpy(data, obj, ti->size); - if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); - } - else if (ti->copy_ctor) - { - call_copy_ctor(base + ti->copy_ctor, data, get_this_pointer(&ti->offsets, obj), - ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); - } - else - memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size); - ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; - } - return; -} -#endif - -#endif /* _MSVCR_VER >= 100 */ - -#if _MSVCR_VER >= 110 -/********************************************************************* - * ?__ExceptionPtrToBool@@YA_NPBX@Z - * ?__ExceptionPtrToBool@@YA_NPEBX@Z - */ -bool __cdecl __ExceptionPtrToBool(exception_ptr *ep) -{ - return !!ep->rec; -} -#endif - -#if _MSVCR_VER >= 100 - -/********************************************************************* - * ?__ExceptionPtrCopyException@@YAXPAXPBX1@Z - * ?__ExceptionPtrCopyException@@YAXPEAXPEBX1@Z - */ -#ifndef __x86_64__ -void __cdecl __ExceptionPtrCopyException(exception_ptr *ep, - exception *object, const cxx_exception_type *type) -{ - const cxx_type_info *ti; - void **data; - - __ExceptionPtrDestroy(ep); - - ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); - ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); - *ep->ref = 1; - - memset(ep->rec, 0, sizeof(EXCEPTION_RECORD)); - ep->rec->ExceptionCode = CXX_EXCEPTION; - ep->rec->ExceptionFlags = EH_NONCONTINUABLE; - ep->rec->NumberParameters = 3; - ep->rec->ExceptionInformation[0] = CXX_FRAME_MAGIC_VC6; - ep->rec->ExceptionInformation[2] = (ULONG_PTR)type; - - ti = type->type_info_table->info[0]; - data = HeapAlloc(GetProcessHeap(), 0, ti->size); - if (ti->flags & CLASS_IS_SIMPLE_TYPE) - { - memcpy(data, object, ti->size); - if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); - } - else if (ti->copy_ctor) - { - call_copy_ctor(ti->copy_ctor, data, get_this_pointer(&ti->offsets, object), - ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); - } - else - memcpy(data, get_this_pointer(&ti->offsets, object), ti->size); - ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; -} -#else -void __cdecl __ExceptionPtrCopyException(exception_ptr *ep, - exception *object, const cxx_exception_type *type) -{ - const cxx_type_info *ti; - void **data; - char *base; - - RtlPcToFileHeader((void*)type, (void**)&base); - __ExceptionPtrDestroy(ep); - - ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); - ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); - *ep->ref = 1; - - memset(ep->rec, 0, sizeof(EXCEPTION_RECORD)); - ep->rec->ExceptionCode = CXX_EXCEPTION; - ep->rec->ExceptionFlags = EH_NONCONTINUABLE; - ep->rec->NumberParameters = 4; - ep->rec->ExceptionInformation[0] = CXX_FRAME_MAGIC_VC6; - ep->rec->ExceptionInformation[2] = (ULONG_PTR)type; - ep->rec->ExceptionInformation[3] = (ULONG_PTR)base; - - ti = (const cxx_type_info*)(base + ((const cxx_type_info_table*)(base + type->type_info_table))->info[0]); - data = HeapAlloc(GetProcessHeap(), 0, ti->size); - if (ti->flags & CLASS_IS_SIMPLE_TYPE) - { - memcpy(data, object, ti->size); - if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); - } - else if (ti->copy_ctor) - { - call_copy_ctor(base + ti->copy_ctor, data, get_this_pointer(&ti->offsets, object), - ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); - } - else - memcpy(data, get_this_pointer(&ti->offsets, object), ti->size); - ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; -} -#endif - -bool __cdecl __ExceptionPtrCompare(const exception_ptr *ep1, const exception_ptr *ep2) -{ - return ep1->rec == ep2->rec; -} - -#endif /* _MSVCR_VER >= 100 */ - -#if _MSVCR_VER >= 80 void* __cdecl __AdjustPointer(void *obj, const this_ptr_offsets *off) { return get_this_pointer(off, obj); } + #endif
#if _MSVCR_VER >= 140 diff --git a/dlls/msvcrt/cxx.h b/dlls/msvcrt/cxx.h index cacbb1524b6..4051229c626 100644 --- a/dlls/msvcrt/cxx.h +++ b/dlls/msvcrt/cxx.h @@ -308,3 +308,11 @@ __ASM_BLOCK_BEGIN(type_info_vtables) \ __ASM_VTABLE(type_info, \ VTABLE_ADD_FUNC(type_info_vector_dtor)); \ __ASM_BLOCK_END + +typedef struct +{ + EXCEPTION_RECORD *rec; + LONG *ref; /* not binary compatible with native msvcr100 */ +} exception_ptr; + +void throw_exception(const char*) DECLSPEC_HIDDEN; diff --git a/dlls/msvcrt/exception_ptr.c b/dlls/msvcrt/exception_ptr.c new file mode 100644 index 00000000000..6f683039331 --- /dev/null +++ b/dlls/msvcrt/exception_ptr.c @@ -0,0 +1,329 @@ +#include <stdarg.h> +#include <stdbool.h> + +#include "windef.h" +#include "winternl.h" +#include "wine/exception.h" +#include "wine/debug.h" +#include "msvcrt.h" +#include "cxx.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* std::exception_ptr class helpers */ + + +/********************************************************************* + * ?__ExceptionPtrCreate@@YAXPAX@Z + * ?__ExceptionPtrCreate@@YAXPEAX@Z + */ +void __cdecl __ExceptionPtrCreate(exception_ptr *ep) +{ + TRACE("(%p)\n", ep); + + ep->rec = NULL; + ep->ref = NULL; +} + +#ifdef __ASM_USE_THISCALL_WRAPPER +extern void call_dtor(const cxx_exception_type *type, void *func, void *object); + +__ASM_GLOBAL_FUNC( call_dtor, + "movl 12(%esp),%ecx\n\t" + "call *8(%esp)\n\t" + "ret" ); +#elif __x86_64__ +static inline void call_dtor(const cxx_exception_type *type, unsigned int dtor, void *object) +{ + char *base = RtlPcToFileHeader((void*)type, (void**)&base); + void (__cdecl *func)(void*) = (void*)(base + dtor); + func(object); +} +#else +#define call_dtor(type, func, object) ((void (__thiscall*)(void*))(func))(object) +#endif + +/********************************************************************* + * ?__ExceptionPtrDestroy@@YAXPAX@Z + * ?__ExceptionPtrDestroy@@YAXPEAX@Z + */ +void __cdecl __ExceptionPtrDestroy(exception_ptr *ep) +{ + TRACE("(%p)\n", ep); + + if (!ep->rec) + return; + + if (!InterlockedDecrement(ep->ref)) + { + if (ep->rec->ExceptionCode == CXX_EXCEPTION) + { + const cxx_exception_type *type = (void*)ep->rec->ExceptionInformation[2]; + void *obj = (void*)ep->rec->ExceptionInformation[1]; + + if (type && type->destructor) call_dtor(type, type->destructor, obj); + HeapFree(GetProcessHeap(), 0, obj); + } + + HeapFree(GetProcessHeap(), 0, ep->rec); + HeapFree(GetProcessHeap(), 0, ep->ref); + } +} + +/********************************************************************* + * ?__ExceptionPtrCopy@@YAXPAXPBX@Z + * ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z + */ +void __cdecl __ExceptionPtrCopy(exception_ptr *ep, const exception_ptr *copy) +{ + TRACE("(%p %p)\n", ep, copy); + + /* don't destroy object stored in ep */ + *ep = *copy; + if (ep->ref) + InterlockedIncrement(copy->ref); +} + +/********************************************************************* + * ?__ExceptionPtrAssign@@YAXPAXPBX@Z + * ?__ExceptionPtrAssign@@YAXPEAXPEBX@Z + */ +void __cdecl __ExceptionPtrAssign(exception_ptr *ep, const exception_ptr *assign) +{ + TRACE("(%p %p)\n", ep, assign); + + /* don't destroy object stored in ep */ + if (ep->ref) + InterlockedDecrement(ep->ref); + + *ep = *assign; + if (ep->ref) + InterlockedIncrement(ep->ref); +} + +/********************************************************************* + * ?__ExceptionPtrRethrow@@YAXPBX@Z + * ?__ExceptionPtrRethrow@@YAXPEBX@Z + */ +void __cdecl __ExceptionPtrRethrow(const exception_ptr *ep) +{ + TRACE("(%p)\n", ep); + + if (!ep->rec) + { + throw_exception("bad exception"); + return; + } + + RaiseException(ep->rec->ExceptionCode, ep->rec->ExceptionFlags & (~EH_UNWINDING), + ep->rec->NumberParameters, ep->rec->ExceptionInformation); +} + +#ifdef __i386__ +extern void call_copy_ctor( void *func, void *this, void *src, int has_vbase ); +#else +static inline void call_copy_ctor( void *func, void *this, void *src, int has_vbase ) +{ + TRACE( "calling copy ctor %p object %p src %p\n", func, this, src ); + if (has_vbase) + ((void (__cdecl*)(void*, void*, BOOL))func)(this, src, 1); + else + ((void (__cdecl*)(void*, void*))func)(this, src); +} +#endif + +/********************************************************************* + * ?__ExceptionPtrCurrentException@@YAXPAX@Z + * ?__ExceptionPtrCurrentException@@YAXPEAX@Z + */ +#ifndef __x86_64__ +void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) +{ + EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record; + + TRACE("(%p)\n", ep); + + if (!rec) + { + ep->rec = NULL; + ep->ref = NULL; + return; + } + + ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); + ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); + + *ep->rec = *rec; + *ep->ref = 1; + + if (ep->rec->ExceptionCode == CXX_EXCEPTION) + { + const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2]; + const cxx_type_info *ti; + void **data, *obj; + + ti = et->type_info_table->info[0]; + data = HeapAlloc(GetProcessHeap(), 0, ti->size); + + obj = (void*)ep->rec->ExceptionInformation[1]; + if (ti->flags & CLASS_IS_SIMPLE_TYPE) + { + memcpy(data, obj, ti->size); + if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); + } + else if (ti->copy_ctor) + { + call_copy_ctor(ti->copy_ctor, data, get_this_pointer(&ti->offsets, obj), + ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); + } + else + memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size); + ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; + } + return; +} +#else +void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) +{ + EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record; + + TRACE("(%p)\n", ep); + + if (!rec) + { + ep->rec = NULL; + ep->ref = NULL; + return; + } + + ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); + ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); + + *ep->rec = *rec; + *ep->ref = 1; + + if (ep->rec->ExceptionCode == CXX_EXCEPTION) + { + const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2]; + const cxx_type_info *ti; + void **data, *obj; + char *base = RtlPcToFileHeader((void*)et, (void**)&base); + + ti = (const cxx_type_info*)(base + ((const cxx_type_info_table*)(base + et->type_info_table))->info[0]); + data = HeapAlloc(GetProcessHeap(), 0, ti->size); + + obj = (void*)ep->rec->ExceptionInformation[1]; + if (ti->flags & CLASS_IS_SIMPLE_TYPE) + { + memcpy(data, obj, ti->size); + if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); + } + else if (ti->copy_ctor) + { + call_copy_ctor(base + ti->copy_ctor, data, get_this_pointer(&ti->offsets, obj), + ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); + } + else + memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size); + ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; + } + return; +} +#endif + +#if _MSVCR_VER >= 110 +/********************************************************************* + * ?__ExceptionPtrToBool@@YA_NPBX@Z + * ?__ExceptionPtrToBool@@YA_NPEBX@Z + */ +bool __cdecl __ExceptionPtrToBool(exception_ptr *ep) +{ + return !!ep->rec; +} +#endif + +/********************************************************************* + * ?__ExceptionPtrCopyException@@YAXPAXPBX1@Z + * ?__ExceptionPtrCopyException@@YAXPEAXPEBX1@Z + */ +#ifndef __x86_64__ +void __cdecl __ExceptionPtrCopyException(exception_ptr *ep, + exception *object, const cxx_exception_type *type) +{ + const cxx_type_info *ti; + void **data; + + __ExceptionPtrDestroy(ep); + + ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); + ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); + *ep->ref = 1; + + memset(ep->rec, 0, sizeof(EXCEPTION_RECORD)); + ep->rec->ExceptionCode = CXX_EXCEPTION; + ep->rec->ExceptionFlags = EH_NONCONTINUABLE; + ep->rec->NumberParameters = 3; + ep->rec->ExceptionInformation[0] = CXX_FRAME_MAGIC_VC6; + ep->rec->ExceptionInformation[2] = (ULONG_PTR)type; + + ti = type->type_info_table->info[0]; + data = HeapAlloc(GetProcessHeap(), 0, ti->size); + if (ti->flags & CLASS_IS_SIMPLE_TYPE) + { + memcpy(data, object, ti->size); + if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); + } + else if (ti->copy_ctor) + { + call_copy_ctor(ti->copy_ctor, data, get_this_pointer(&ti->offsets, object), + ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); + } + else + memcpy(data, get_this_pointer(&ti->offsets, object), ti->size); + ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; +} +#else +void __cdecl __ExceptionPtrCopyException(exception_ptr *ep, + exception *object, const cxx_exception_type *type) +{ + const cxx_type_info *ti; + void **data; + char *base; + + RtlPcToFileHeader((void*)type, (void**)&base); + __ExceptionPtrDestroy(ep); + + ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); + ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); + *ep->ref = 1; + + memset(ep->rec, 0, sizeof(EXCEPTION_RECORD)); + ep->rec->ExceptionCode = CXX_EXCEPTION; + ep->rec->ExceptionFlags = EH_NONCONTINUABLE; + ep->rec->NumberParameters = 4; + ep->rec->ExceptionInformation[0] = CXX_FRAME_MAGIC_VC6; + ep->rec->ExceptionInformation[2] = (ULONG_PTR)type; + ep->rec->ExceptionInformation[3] = (ULONG_PTR)base; + + ti = (const cxx_type_info*)(base + ((const cxx_type_info_table*)(base + type->type_info_table))->info[0]); + data = HeapAlloc(GetProcessHeap(), 0, ti->size); + if (ti->flags & CLASS_IS_SIMPLE_TYPE) + { + memcpy(data, object, ti->size); + if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); + } + else if (ti->copy_ctor) + { + call_copy_ctor(base + ti->copy_ctor, data, get_this_pointer(&ti->offsets, object), + ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); + } + else + memcpy(data, get_this_pointer(&ti->offsets, object), ti->size); + ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; +} +#endif + +bool __cdecl __ExceptionPtrCompare(const exception_ptr *ep1, const exception_ptr *ep2) +{ + return ep1->rec == ep2->rec; +} diff --git a/dlls/ucrtbase/Makefile.in b/dlls/ucrtbase/Makefile.in index bf7f62ada8a..4e7cfc03b5c 100644 --- a/dlls/ucrtbase/Makefile.in +++ b/dlls/ucrtbase/Makefile.in @@ -23,6 +23,7 @@ C_SRCS = \ except_arm64.c \ except_i386.c \ except_x86_64.c \ + exception_ptr.c \ exit.c \ file.c \ heap.c \
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/msvcrt/exception_ptr.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/dlls/msvcrt/exception_ptr.c b/dlls/msvcrt/exception_ptr.c index 6f683039331..9b83c600a2b 100644 --- a/dlls/msvcrt/exception_ptr.c +++ b/dlls/msvcrt/exception_ptr.c @@ -132,15 +132,9 @@ static inline void call_copy_ctor( void *func, void *this, void *src, int has_vb } #endif
-/********************************************************************* - * ?__ExceptionPtrCurrentException@@YAXPAX@Z - * ?__ExceptionPtrCurrentException@@YAXPEAX@Z - */ #ifndef __x86_64__ -void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) +static void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) { - EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record; - TRACE("(%p)\n", ep);
if (!rec) @@ -183,10 +177,8 @@ void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) return; } #else -void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) +static void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) { - EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record; - TRACE("(%p)\n", ep);
if (!rec) @@ -231,6 +223,16 @@ void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) } #endif
+/********************************************************************* + * ?__ExceptionPtrCurrentException@@YAXPAX@Z + * ?__ExceptionPtrCurrentException@@YAXPEAX@Z + */ +void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) +{ + TRACE("(%p)\n", ep); + exception_ptr_from_record(ep, msvcrt_get_thread_data()->exc_record); +} + #if _MSVCR_VER >= 110 /********************************************************************* * ?__ExceptionPtrToBool@@YA_NPBX@Z
From: Torge Matthies tmatthies@codeweavers.com
Keep the one with the lowest id, which seems to be the behavior on native.
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/msvcrt/concurrency.c | 68 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 5 deletions(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index d0c9924c631..3ca8d748cad 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -97,6 +97,7 @@ typedef struct { } ExternalContextBase; extern const vtable_ptr ExternalContextBase_vtable; static void ExternalContextBase_ctor(ExternalContextBase*); +static void ExternalContextBase_dtor(ExternalContextBase*);
typedef struct Scheduler { const vtable_ptr *vtable; @@ -359,6 +360,16 @@ enum ConcRT_EventType CONCRT_EVENT_DETACH };
+static CRITICAL_SECTION cached_context_cs; +static CRITICAL_SECTION_DEBUG cached_context_cs_debug = +{ + 0, 0, &cached_context_cs, + { &cached_context_cs_debug.ProcessLocksList, &cached_context_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": cached_context_cs") } +}; +static CRITICAL_SECTION cached_context_cs = { &cached_context_cs_debug, -1, 0, 0, 0, 0 }; +static ExternalContextBase* cached_context; + static DWORD context_tls_index = TLS_OUT_OF_INDEXES;
static CRITICAL_SECTION default_scheduler_cs; @@ -674,6 +685,55 @@ static BOOL WINAPI init_context_tls_index(INIT_ONCE *once, void *param, void **c return context_tls_index != TLS_OUT_OF_INDEXES; }
+static Context* allocate_context(void) +{ + ExternalContextBase *context = NULL; + + EnterCriticalSection(&cached_context_cs); + if (cached_context) + { + context = cached_context; + cached_context = NULL; + } + LeaveCriticalSection(&cached_context_cs); + if (!context) + { + context = operator_new(sizeof(ExternalContextBase)); + ExternalContextBase_ctor(context); + } + return &context->context; +} + +static void free_context(Context* ctx) +{ + ExternalContextBase *context = (ExternalContextBase*)ctx; + + if (context->context.vtable != &ExternalContextBase_vtable) + { + call_Context_dtor(ctx, 1); + return; + } + + EnterCriticalSection(&cached_context_cs); + if (cached_context && context->id < cached_context->id) + { + ExternalContextBase_dtor(cached_context); + operator_delete(cached_context); + cached_context = NULL; + } + if (!cached_context) + { + cached_context = context; + context = NULL; + } + LeaveCriticalSection(&cached_context_cs); + if (context) + { + ExternalContextBase_dtor(context); + operator_delete(context); + } +} + static Context* get_current_context(void) { static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; @@ -689,10 +749,8 @@ static Context* get_current_context(void)
ret = TlsGetValue(context_tls_index); if (!ret) { - ExternalContextBase *context = operator_new(sizeof(ExternalContextBase)); - ExternalContextBase_ctor(context); - TlsSetValue(context_tls_index, context); - ret = &context->context; + ret = allocate_context(); + TlsSetValue(context_tls_index, ret); } return ret; } @@ -3122,7 +3180,7 @@ void msvcrt_free_scheduler_thread(void) { Context *context = try_get_current_context(); if (!context) return; - call_Context_dtor(context, 1); + free_context(context); }
#endif /* _MSVCR_VER >= 100 */
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/msvcrt/concurrency.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index 3ca8d748cad..5422c0c776e 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -755,29 +755,38 @@ static Context* get_current_context(void) return ret; }
+static Scheduler* get_scheduler_from_context(Context *ctx) +{ + ExternalContextBase *context = (ExternalContextBase*)ctx; + + if (context->context.vtable != &ExternalContextBase_vtable) + return NULL; + return context->scheduler.scheduler; +} + static Scheduler* try_get_current_scheduler(void) { - ExternalContextBase *context = (ExternalContextBase*)try_get_current_context(); + Context *context = try_get_current_context(); + Scheduler *ret;
if (!context) return NULL;
- if (context->context.vtable != &ExternalContextBase_vtable) { + ret = get_scheduler_from_context(context); + if (!ret) ERR("unknown context set\n"); - return NULL; - } - return context->scheduler.scheduler; + return ret; }
static Scheduler* get_current_scheduler(void) { - ExternalContextBase *context = (ExternalContextBase*)get_current_context(); + Context *context = get_current_context(); + Scheduler *ret;
- if (context->context.vtable != &ExternalContextBase_vtable) { + ret = get_scheduler_from_context(context); + if (!ret) ERR("unknown context set\n"); - return NULL; - } - return context->scheduler.scheduler; + return ret; }
/* ?CurrentContext@Context@Concurrency@@SAPAV12@XZ */
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/concrt140/Makefile.in | 4 +- dlls/concrt140/concrt140.c | 17 ++++ dlls/msvcr120/tests/msvcr120.c | 6 +- dlls/msvcrt/concurrency.c | 157 +++++++++++++++++++++++++++++++-- dlls/msvcrt/cxx.h | 4 + dlls/msvcrt/exception_ptr.c | 13 ++- 6 files changed, 188 insertions(+), 13 deletions(-)
diff --git a/dlls/concrt140/Makefile.in b/dlls/concrt140/Makefile.in index aac1ed7b34a..05258adf7ee 100644 --- a/dlls/concrt140/Makefile.in +++ b/dlls/concrt140/Makefile.in @@ -1,7 +1,9 @@ +EXTRADEFS = -D_CONCRT= MODULE = concrt140.dll PARENTSRC = ../msvcrt
C_SRCS = \ concrt140.c \ concurrency.c \ - details.c + details.c \ + exception_ptr.c diff --git a/dlls/concrt140/concrt140.c b/dlls/concrt140/concrt140.c index 0a770c9dae6..aa2fdd7c981 100644 --- a/dlls/concrt140/concrt140.c +++ b/dlls/concrt140/concrt140.c @@ -105,6 +105,23 @@ void DECLSPEC_NORETURN throw_range_error(const char *str) _CxxThrowException(&e, &range_error_exception_type); }
+#ifdef __i386__ +__ASM_GLOBAL_FUNC( call_copy_ctor, + "pushl %ebp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") + __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") + "movl %esp, %ebp\n\t" + __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") + "pushl $1\n\t" + "movl 12(%ebp), %ecx\n\t" + "pushl 16(%ebp)\n\t" + "call *8(%ebp)\n\t" + "leave\n" + __ASM_CFI(".cfi_def_cfa %esp,4\n\t") + __ASM_CFI(".cfi_same_value %ebp\n\t") + "ret" ); +#endif + static BOOL init_cxx_funcs(void) { msvcp140 = LoadLibraryA("msvcp140.dll"); diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index ac35076af03..24e4914d98a 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -170,7 +170,7 @@ typedef struct _StructuredTaskCollection Context *context; volatile LONG count; volatile LONG finished; - void *unk4; + void *exception; void *event; } _StructuredTaskCollection;
@@ -1439,8 +1439,8 @@ static void test_StructuredTaskCollection(void) "_StructuredTaskCollection ctor set wrong count: %ld != 0\n", task_coll.count); ok(task_coll.finished == LONG_MIN, "_StructuredTaskCollection ctor set wrong finished: %ld != %ld\n", task_coll.finished, LONG_MIN); - ok(task_coll.unk4 == NULL, - "_StructuredTaskCollection ctor set wrong unk4: %p != NULL\n", task_coll.unk4); + ok(task_coll.exception == NULL, + "_StructuredTaskCollection ctor set wrong exception: %p != NULL\n", task_coll.exception);
chore_start_evt = CreateEventW(NULL, TRUE, FALSE, NULL); ok(chore_start_evt != NULL, "CreateEvent failed: 0x%lx\n", GetLastError()); diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index 5422c0c776e..d71c8fc7a0e 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -20,10 +20,14 @@
#include <stdarg.h> #include <stdbool.h> +#include <malloc.h>
#include "windef.h" +#include "winbase.h" #include "winternl.h" #include "wine/debug.h" +#include "wine/exception.h" +#include "wine/list.h" #include "msvcrt.h" #include "cxx.h"
@@ -89,11 +93,20 @@ struct scheduler_list { struct scheduler_list *next; };
+struct _UnrealizedChore; + +struct scheduled_chore { + struct list entry; + struct _UnrealizedChore *chore; +}; + typedef struct { Context context; struct scheduler_list scheduler; unsigned int id; union allocator_cache_entry *allocator_cache[8]; + struct list scheduled_chores; + CRITICAL_SECTION scheduled_chores_cs; } ExternalContextBase; extern const vtable_ptr ExternalContextBase_vtable; static void ExternalContextBase_ctor(ExternalContextBase*); @@ -165,14 +178,28 @@ typedef struct yield_func yield_func; } SpinWait;
-typedef struct +struct _StructuredTaskCollection; + +typedef struct _UnrealizedChore { - char dummy; + const vtable_ptr *vtable; + void (__cdecl *chore_proc)(struct _UnrealizedChore*); + struct _StructuredTaskCollection *task_collection; + void (__cdecl *chore_wrapper)(struct _UnrealizedChore*); + void *unk[6]; } _UnrealizedChore;
-typedef struct +#define FINISHED_INITIAL 0x80000000 +typedef struct _StructuredTaskCollection { - char dummy; + void *unk1; + unsigned int unk2; + void *unk3; + Context *context; + volatile LONG count; + volatile LONG finished; + void *exception; + void *event; } _StructuredTaskCollection;
/* keep in sync with msvcp90/msvcp90.h */ @@ -640,6 +667,7 @@ DEFINE_RTTI_DATA1(scheduler_resource_allocation_error, 0, &cexception_rtti_base_ DEFINE_CXX_DATA1(improper_lock, &cexception_cxx_type_info, cexception_dtor) DEFINE_CXX_DATA1(improper_scheduler_attach, &cexception_cxx_type_info, cexception_dtor) DEFINE_CXX_DATA1(improper_scheduler_detach, &cexception_cxx_type_info, cexception_dtor) +DEFINE_CXX_DATA1(invalid_multiple_scheduling, &cexception_cxx_type_info, cexception_dtor) DEFINE_CXX_DATA1(invalid_scheduler_policy_key, &cexception_cxx_type_info, cexception_dtor) DEFINE_CXX_DATA1(invalid_scheduler_policy_thread_specification, &cexception_cxx_type_info, cexception_dtor) DEFINE_CXX_DATA1(invalid_scheduler_policy_value, &cexception_cxx_type_info, cexception_dtor) @@ -920,6 +948,12 @@ static void ExternalContextBase_dtor(ExternalContextBase *this) operator_delete(scheduler_cur); } } + + EnterCriticalSection(&this->scheduled_chores_cs); + if (!list_empty(&this->scheduled_chores)) + ERR("scheduled chore list is not empty\n"); + LeaveCriticalSection(&this->scheduled_chores_cs); + DeleteCriticalSection(&this->scheduled_chores_cs); }
DEFINE_THISCALL_WRAPPER(ExternalContextBase_vector_dtor, 8) @@ -949,6 +983,8 @@ static void ExternalContextBase_ctor(ExternalContextBase *this) memset(this, 0, sizeof(*this)); this->context.vtable = &ExternalContextBase_vtable; this->id = InterlockedIncrement(&context_id); + list_init(&this->scheduled_chores); + InitializeCriticalSection(&this->scheduled_chores_cs);
create_default_scheduler(); this->scheduler.scheduler = &default_scheduler->scheduler; @@ -1882,6 +1918,100 @@ void __thiscall _StructuredTaskCollection_dtor(_StructuredTaskCollection *this)
#endif /* _MSVCR_VER >= 120 */
+static void CALLBACK chore_wrapper_finally(BOOL normal, void *data) +{ + _UnrealizedChore *chore = data; + LONG prev_finished, new_finished; + volatile LONG *ptr; + + TRACE("(%u %p)\n", normal, data); + + if (!chore->task_collection) + return; + ptr = &chore->task_collection->finished; + chore->task_collection = NULL; + + do { + prev_finished = *ptr; + if (prev_finished == FINISHED_INITIAL) + new_finished = 1; + else + new_finished = prev_finished + 1; + } while (InterlockedCompareExchange(ptr, new_finished, prev_finished) + != prev_finished); +} + +static void __cdecl chore_wrapper(_UnrealizedChore *chore) +{ + TRACE("(%p)\n", chore); + + __TRY + { + if (chore->chore_proc) + chore->chore_proc(chore); + } + __FINALLY_CTX(chore_wrapper_finally, chore) +} + +static void __cdecl _StructuredTaskCollection_scheduler_cb(void *data) +{ + ExternalContextBase *context = data; + struct list *entry; + struct scheduled_chore *sc; + _UnrealizedChore *chore; + + TRACE("(%p)\n", context); + + EnterCriticalSection(&context->scheduled_chores_cs); + entry = list_head(&context->scheduled_chores); + if (entry) + list_remove(entry); + LeaveCriticalSection(&context->scheduled_chores_cs); + if (!entry) + return; + + sc = LIST_ENTRY(entry, struct scheduled_chore, entry); + chore = sc->chore; + operator_delete(sc); + + chore->chore_wrapper(chore); +} + +static bool schedule_chore(_StructuredTaskCollection *this, + _UnrealizedChore *chore, ExternalContextBase **context) +{ + struct scheduled_chore *sc; + + if (chore->task_collection) { + invalid_multiple_scheduling e; + invalid_multiple_scheduling_ctor_str(&e, "Chore scheduled multiple times"); + _CxxThrowException(&e, &invalid_multiple_scheduling_exception_type); + return FALSE; + } + + *context = (ExternalContextBase*)this->context; + if (!*context) { + *context = (ExternalContextBase*)get_current_context(); + if ((*context)->context.vtable != &ExternalContextBase_vtable) { + ERR("unknown context set\n"); + return FALSE; + } + this->context = (Context*)*context; + } + + sc = operator_new(sizeof(*sc)); + sc->chore = chore; + + chore->task_collection = this; + chore->chore_wrapper = chore_wrapper; + InterlockedIncrement(&this->count); + + EnterCriticalSection(&(*context)->scheduled_chores_cs); + list_add_head(&(*context)->scheduled_chores, &sc->entry); + LeaveCriticalSection(&(*context)->scheduled_chores_cs); + return TRUE; +} + #if _MSVCR_VER >= 110
/* ?_Schedule@_StructuredTaskCollection@details@Concurrency@@QAAXPAV_UnrealizedChore@23@PAVlocation@3@@Z */ @@ -1892,7 +2022,14 @@ void __thiscall _StructuredTaskCollection__Schedule_loc( _StructuredTaskCollection *this, _UnrealizedChore *chore, /*location*/void *placement) { - FIXME("(%p %p %p): stub!\n", this, chore, placement); + ExternalContextBase *context; + + FIXME("(%p %p %p): semi-stub\n", this, chore, placement); + + if (schedule_chore(this, chore, &context)) + call_Scheduler_ScheduleTask_loc( + get_scheduler_from_context((Context*)context), + _StructuredTaskCollection_scheduler_cb, context, placement); }
#endif /* _MSVCR_VER >= 110 */ @@ -1904,7 +2041,14 @@ DEFINE_THISCALL_WRAPPER(_StructuredTaskCollection__Schedule, 8) void __thiscall _StructuredTaskCollection__Schedule( _StructuredTaskCollection *this, _UnrealizedChore *chore) { - FIXME("(%p %p): stub!\n", this, chore); + ExternalContextBase *context; + + TRACE("(%p %p)\n", this, chore); + + if (schedule_chore(this, chore, &context)) + call_Scheduler_ScheduleTask( + get_scheduler_from_context((Context*)context), + _StructuredTaskCollection_scheduler_cb, context); }
/* ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z */ @@ -3163,6 +3307,7 @@ void msvcrt_init_concurrency(void *base) init_improper_lock_cxx(base); init_improper_scheduler_attach_cxx(base); init_improper_scheduler_detach_cxx(base); + init_invalid_multiple_scheduling_cxx(base); init_invalid_scheduler_policy_key_cxx(base); init_invalid_scheduler_policy_thread_specification_cxx(base); init_invalid_scheduler_policy_value_cxx(base); diff --git a/dlls/msvcrt/cxx.h b/dlls/msvcrt/cxx.h index 4051229c626..b8fa2c2efda 100644 --- a/dlls/msvcrt/cxx.h +++ b/dlls/msvcrt/cxx.h @@ -316,3 +316,7 @@ typedef struct } exception_ptr;
void throw_exception(const char*) DECLSPEC_HIDDEN; +void exception_ptr_from_record(exception_ptr*,EXCEPTION_RECORD*) DECLSPEC_HIDDEN; + +void __cdecl __ExceptionPtrCreate(exception_ptr*); +void __cdecl __ExceptionPtrDestroy(exception_ptr*); diff --git a/dlls/msvcrt/exception_ptr.c b/dlls/msvcrt/exception_ptr.c index 9b83c600a2b..cd697d2b1ac 100644 --- a/dlls/msvcrt/exception_ptr.c +++ b/dlls/msvcrt/exception_ptr.c @@ -12,7 +12,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
/* std::exception_ptr class helpers */
- /********************************************************************* * ?__ExceptionPtrCreate@@YAXPAX@Z * ?__ExceptionPtrCreate@@YAXPEAX@Z @@ -70,6 +69,8 @@ void __cdecl __ExceptionPtrDestroy(exception_ptr *ep) } }
+#ifndef _CONCRT + /********************************************************************* * ?__ExceptionPtrCopy@@YAXPAXPBX@Z * ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z @@ -119,6 +120,8 @@ void __cdecl __ExceptionPtrRethrow(const exception_ptr *ep) ep->rec->NumberParameters, ep->rec->ExceptionInformation); }
+#endif + #ifdef __i386__ extern void call_copy_ctor( void *func, void *this, void *src, int has_vbase ); #else @@ -133,7 +136,7 @@ static inline void call_copy_ctor( void *func, void *this, void *src, int has_vb #endif
#ifndef __x86_64__ -static void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) +void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) { TRACE("(%p)\n", ep);
@@ -177,7 +180,7 @@ static void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) return; } #else -static void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) +void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) { TRACE("(%p)\n", ep);
@@ -223,6 +226,8 @@ static void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) } #endif
+#ifndef _CONCRT + /********************************************************************* * ?__ExceptionPtrCurrentException@@YAXPAX@Z * ?__ExceptionPtrCurrentException@@YAXPEAX@Z @@ -329,3 +334,5 @@ bool __cdecl __ExceptionPtrCompare(const exception_ptr *ep1, const exception_ptr { return ep1->rec == ep2->rec; } + +#endif
On Sat Jul 16 12:02:03 2022 +0000, Piotr Caban wrote:
The implementation can be probably moved from except_i386.c file to avoid code duplication.
I moved this duplicate code from here to dlls/concrt140/concrt140.c. Do you want me to make a new file for just this function, or is this ok?
On Fri Jul 22 15:39:58 2022 +0000, Torge Matthies wrote:
changed this line in [version 6 of the diff](/wine/wine/-/merge_requests/464/diffs?diff_id=5730&start_sha=0fe99bac47a25ab9db20922c4853f8e9ecb294ba#24c8e99f61c1fc2b69d361492bf667ba408b92b5_1937_1936)
We have to work together with the native code that is compiled into the programs, so I'd say this cas loop probably has to stay.
On Fri Jul 22 12:56:00 2022 +0000, Torge Matthies wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/464/diffs?diff_id=5721&start_sha=49477d87f721d30a198e1a3a42adba532bf0ba23#2428e4327615ada552138d2b949f2e60983c8193_20_15)
Done, I added the `throw_exception` helper function to throw/raise a base exception with a message.
On Sat Jul 16 11:39:32 2022 +0000, Piotr Caban wrote:
This is looking wrong, probably the line needs to be removed instead.
obsolete - this line is now required on `_MSVCR_VER >= 100` for the `throw_exception` helper
On Fri Jul 22 12:55:57 2022 +0000, Torge Matthies wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/464/diffs?diff_id=5721&start_sha=49477d87f721d30a198e1a3a42adba532bf0ba23#24c8e99f61c1fc2b69d361492bf667ba408b92b5_885_933)
It looks like native always caches one Context instance and reuses it for another thread. I'll also have to look more into why it doesn't just crash and burn if the initiating thread dies before the chore is done.
Piotr Caban (@piotr) commented about dlls/msvcrt/concurrency.c:
operator_delete(cached_context);
cached_context = NULL;
- }
- if (!cached_context)
- {
cached_context = context;
context = NULL;
- }
- LeaveCriticalSection(&cached_context_cs);
- if (context)
- {
ExternalContextBase_dtor(context);
operator_delete(context);
- }
+}
This needs some tests (maybe ThreadScheduler is doing the caching). I would suggest focusing on it later, when other _StructuredTaskCollection patches are in.
Piotr Caban (@piotr) commented about dlls/msvcrt/concurrency.c:
operator_delete(scheduler_cur); } }
- EnterCriticalSection(&this->scheduled_chores_cs);
- if (!list_empty(&this->scheduled_chores))
ERR("scheduled chore list is not empty\n");
This will crash if chore is executed after context is destroyed. I don't know how it's supposed to work but if it doesn't crash with native, I will prefer something along these lines (not tested): ```c if (!list_empty(&this->scheduled_chores)) FIXME("scheduled chores list is not empty\n"); while (!list_empty(&this->scheduled_chores)) { entry = list_head(&this->scheduled_chores); list_remove(entry); LeaveCriticalSection(&this->scheduled_chores_cs);
sc = LIST_ENTRY(entry, struct scheduled_chore, entry); chore = sc->chore; operator_delete(sc);
_StructuredTaskCollection_RunAndWait(chore->task_collection, chore); EnterCriticalSection(&this->scheduled_chores_cs); } ```
Unfortunately it may be tricky to test depending how context caching works (another option is to cancel the task collections). FWIW I think that incorrect solution is better than a crash.
On Fri Jul 22 15:42:53 2022 +0000, Torge Matthies wrote:
I moved this duplicate code from here to dlls/concrt140/concrt140.c. Do you want me to make a new file for just this function, or is this ok?
There's no need to create new file.
Piotr Caban (@piotr) commented about dlls/msvcrt/exception_ptr.c:
+#include <stdarg.h> +#include <stdbool.h>
+#include "windef.h"
The license file header is missing.