[PATCH 0/4] MR10982: combase: Share context token between MTA threads.
These changes will be needed by IContextCallback::ContextCallback function. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10982
From: Piotr Caban <piotr@codeweavers.com> --- include/comsvcs.idl | 2 ++ libs/uuid/uuid.c | 1 + 2 files changed, 3 insertions(+) diff --git a/include/comsvcs.idl b/include/comsvcs.idl index 902c78b05c8..614b9ee43f3 100644 --- a/include/comsvcs.idl +++ b/include/comsvcs.idl @@ -23,6 +23,8 @@ import "oaidl.idl"; #define threading(model) #endif +cpp_quote("EXTERN_C const GUID IID_IEnterActivityWithNoLock;") + typedef DWORD_PTR INSTID; typedef DWORD_PTR RESID; typedef DWORD RESOURCERATING; diff --git a/libs/uuid/uuid.c b/libs/uuid/uuid.c index dd12c769922..13c036776f8 100644 --- a/libs/uuid/uuid.c +++ b/libs/uuid/uuid.c @@ -111,6 +111,7 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); DEFINE_GUID(IID_ISFHelper, 0x1fe68efb,0x1874,0x9812,0x56,0xdc,0x00,0x00,0x00,0x00,0x00,0x00); DEFINE_GUID(IID_IProxyManager, 0x00000008,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); DEFINE_GUID(IID_IBindStatusCallbackHolder,0x79eac9cc,0xbaf9,0x11ce,0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b); +DEFINE_GUID(IID_IEnterActivityWithNoLock, 0xd7174f82,0x36b8,0x4aa8,0x80,0x0a,0xe9,0x63,0xab,0x2d,0xfa,0xb9); DEFINE_GUID(FMTID_SummaryInformation,0xF29F85E0,0x4FF9,0x1068,0xAB,0x91,0x08,0x00,0x2B,0x27,0xB3,0xD9); DEFINE_GUID(FMTID_DocSummaryInformation,0xD5CDD502,0x2E9C,0x101B,0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10982
From: Piotr Caban <piotr@codeweavers.com> --- include/objidlbase.idl | 2 ++ libs/uuid/uuid.c | 1 + 2 files changed, 3 insertions(+) diff --git a/include/objidlbase.idl b/include/objidlbase.idl index ec27c6da0b0..f5fe3c23bee 100644 --- a/include/objidlbase.idl +++ b/include/objidlbase.idl @@ -23,6 +23,8 @@ import "unknwn.idl"; cpp_quote("#ifndef _OBJIDLBASE_") cpp_quote("#define _OBJIDLBASE_") +cpp_quote ("EXTERN_C const GUID IID_ICallbackWithNoReentrancyToApplicationSTA;") + interface IStream; interface IEnumString; diff --git a/libs/uuid/uuid.c b/libs/uuid/uuid.c index 13c036776f8..03d7286dfa2 100644 --- a/libs/uuid/uuid.c +++ b/libs/uuid/uuid.c @@ -112,6 +112,7 @@ DEFINE_GUID(IID_ISFHelper, 0x1fe68efb,0x1874,0x9812,0x56,0xdc,0x0 DEFINE_GUID(IID_IProxyManager, 0x00000008,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); DEFINE_GUID(IID_IBindStatusCallbackHolder,0x79eac9cc,0xbaf9,0x11ce,0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b); DEFINE_GUID(IID_IEnterActivityWithNoLock, 0xd7174f82,0x36b8,0x4aa8,0x80,0x0a,0xe9,0x63,0xab,0x2d,0xfa,0xb9); +DEFINE_GUID(IID_ICallbackWithNoReentrancyToApplicationSTA, 0x0a299774,0x3e4e,0xfc42,0x1d,0x9d,0x72,0xce,0xe1,0x05,0xca,0x57); DEFINE_GUID(FMTID_SummaryInformation,0xF29F85E0,0x4FF9,0x1068,0xAB,0x91,0x08,0x00,0x2B,0x27,0xB3,0xD9); DEFINE_GUID(FMTID_DocSummaryInformation,0xD5CDD502,0x2E9C,0x101B,0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10982
From: Piotr Caban <piotr@codeweavers.com> --- dlls/combase/combase.c | 169 +++++++++++++++++++++++++------------ dlls/ole32/tests/compobj.c | 46 ++++++++++ 2 files changed, 163 insertions(+), 52 deletions(-) diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index a627d4779ec..8b42615fc0e 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -395,39 +395,6 @@ HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data) return S_OK; } -static void com_cleanup_tlsdata(void) -{ - struct tlsdata *tlsdata = NtCurrentTeb()->ReservedForOle; - struct init_spy *cursor, *cursor2; - - if (!tlsdata) - return; - - if (tlsdata->apt) - apartment_release(tlsdata->apt); - if (tlsdata->implicit_mta_cookie) - apartment_decrement_mta_usage(tlsdata->implicit_mta_cookie); - - if (tlsdata->errorinfo) - IErrorInfo_Release(tlsdata->errorinfo); - if (tlsdata->state) - IUnknown_Release(tlsdata->state); - - LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, entry) - { - list_remove(&cursor->entry); - if (cursor->spy) - IInitializeSpy_Release(cursor->spy); - free(cursor); - } - - if (tlsdata->context_token) - IObjContext_Release(tlsdata->context_token); - - free(tlsdata); - NtCurrentTeb()->ReservedForOle = NULL; -} - struct global_options { IGlobalOptions IGlobalOptions_iface; @@ -2436,13 +2403,24 @@ HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) return S_OK; } -struct thread_context +static CRITICAL_SECTION context_cs; +static CRITICAL_SECTION_DEBUG context_cs_debug = +{ + 0, 0, &context_cs, + { &context_cs_debug.ProcessLocksList, &context_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": context_cs") } +}; +static CRITICAL_SECTION context_cs = { &context_cs_debug, -1, 0, 0, 0, 0 }; + + +static struct thread_context { IComThreadingInfo IComThreadingInfo_iface; IContextCallback IContextCallback_iface; IObjContext IObjContext_iface; - LONG refcount; -}; + LONG ref; + LONG reported_ref; +} *mta_context; static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface) { @@ -2492,22 +2470,36 @@ static HRESULT WINAPI thread_context_info_QueryInterface(IComThreadingInfo *ifac static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface) { struct thread_context *context = impl_from_IComThreadingInfo(iface); - return InterlockedIncrement(&context->refcount); + InterlockedIncrement(&context->ref); + return InterlockedIncrement(&context->reported_ref); } -static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface) +static void context_token_release(IObjContext *iface) { - struct thread_context *context = impl_from_IComThreadingInfo(iface); + struct thread_context *context = impl_from_IObjContext(iface); - /* Context instance is initially created with CoGetContextToken() with refcount set to 0, - releasing context while refcount is at 0 destroys it. */ - if (!context->refcount) + if (!InterlockedDecrement(&context->ref)) { + EnterCriticalSection(&context_cs); + if (context->ref) + { + LeaveCriticalSection(&context_cs); + return; + } + if (context == mta_context) mta_context = NULL; + LeaveCriticalSection(&context_cs); + free(context); - return 0; } +} - return InterlockedDecrement(&context->refcount); +static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface) +{ + struct thread_context *context = impl_from_IComThreadingInfo(iface); + ULONG ret = InterlockedDecrement(&context->reported_ref); + + context_token_release(&context->IObjContext_iface); + return ret; } static HRESULT WINAPI thread_context_info_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype) @@ -2708,21 +2700,44 @@ static const IObjContextVtbl thread_object_context_vtbl = HRESULT WINAPI CoGetContextToken(ULONG_PTR *token) { struct tlsdata *tlsdata; + struct apartment *apt; HRESULT hr; TRACE("%p\n", token); - if (!InternalIsProcessInitialized()) + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; + + if (!token) + return E_POINTER; + + if (!(apt = apartment_get_current_or_mta())) { ERR("apartment not initialised\n"); return CO_E_NOTINITIALIZED; } - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (tlsdata->context_token) + { + struct thread_context *context = impl_from_IObjContext(tlsdata->context_token); + if ((apt->multi_threaded && context != mta_context) || + (!apt->multi_threaded && context == mta_context)) + { + context_token_release(tlsdata->context_token); + tlsdata->context_token = NULL; + } + } - if (!token) - return E_POINTER; + if (!tlsdata->context_token && apt->multi_threaded && mta_context) + { + EnterCriticalSection(&context_cs); + if (mta_context) + { + tlsdata->context_token = &mta_context->IObjContext_iface; + InterlockedIncrement(&mta_context->ref); + } + LeaveCriticalSection(&context_cs); + } if (!tlsdata->context_token) { @@ -2730,14 +2745,30 @@ HRESULT WINAPI CoGetContextToken(ULONG_PTR *token) context = calloc(1, sizeof(*context)); if (!context) + { + apartment_release(apt); return E_OUTOFMEMORY; + } context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl; context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl; context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl; - /* Context token does not take a reference, it's always zero until the - interface is explicitly requested with CoGetObjectContext(). */ - context->refcount = 0; + context->ref = 1; + context->reported_ref = 0; + + if (apt->multi_threaded) + { + EnterCriticalSection(&context_cs); + if (!mta_context) + mta_context = context; + else + { + context_token_release(&context->IObjContext_iface); + context = mta_context; + InterlockedIncrement(&context->ref); + } + LeaveCriticalSection(&context_cs); + } tlsdata->context_token = &context->IObjContext_iface; } @@ -2745,6 +2776,7 @@ HRESULT WINAPI CoGetContextToken(ULONG_PTR *token) *token = (ULONG_PTR)tlsdata->context_token; TRACE("context_token %p\n", tlsdata->context_token); + apartment_release(apt); return S_OK; } @@ -3435,6 +3467,39 @@ HRESULT WINAPI CoRegisterActivationFilter(IActivationFilter *filter) return E_NOTIMPL; } +static void com_cleanup_tlsdata(void) +{ + struct tlsdata *tlsdata = NtCurrentTeb()->ReservedForOle; + struct init_spy *cursor, *cursor2; + + if (!tlsdata) + return; + + if (tlsdata->apt) + apartment_release(tlsdata->apt); + if (tlsdata->implicit_mta_cookie) + apartment_decrement_mta_usage(tlsdata->implicit_mta_cookie); + + if (tlsdata->errorinfo) + IErrorInfo_Release(tlsdata->errorinfo); + if (tlsdata->state) + IUnknown_Release(tlsdata->state); + + LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, entry) + { + list_remove(&cursor->entry); + if (cursor->spy) + IInitializeSpy_Release(cursor->spy); + free(cursor); + } + + if (tlsdata->context_token) + context_token_release(tlsdata->context_token); + + free(tlsdata); + NtCurrentTeb()->ReservedForOle = NULL; +} + /*********************************************************************** * DllMain (combase.@) */ diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 2c4cc566f3a..1f6e2326129 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -2201,12 +2201,42 @@ static void test_CoGetCallContext(void) CoUninitialize(); } +static DWORD WINAPI get_context_token_thread(void *arg) +{ + ULONG_PTR mta_token = (ULONG_PTR)arg, token; + HRESULT hr; + ULONG refs; + + test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA); + hr = pCoGetContextToken(&token); + ok(hr == S_OK, "Expected S_OK, got 0x%08lx\n", hr); + ok(token, "Expected token != 0\n"); + ok(token == mta_token, "token != mta_token\n"); + + refs = IUnknown_AddRef((IUnknown *)token); + ok(refs == 1, "Expected 1, got %lu\n", refs); + IUnknown_Release((IUnknown *)token); + + hr = CoInitialize(NULL); + ok(hr == S_OK, "CoInitialize() failed with error 0x%08lx\n", hr); + test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE); + + hr = pCoGetContextToken(&token); + ok(hr == S_OK, "Expected S_OK, got 0x%08lx\n", hr); + ok(token, "Expected token != 0\n"); + ok(token != mta_token, "token == mta_token\n"); + + CoUninitialize(); + return 0; +} + static void test_CoGetContextToken(void) { HRESULT hr; ULONG refs; ULONG_PTR token, token2; IObjContext *ctx; + HANDLE thread; if (!pCoGetContextToken) { @@ -2267,6 +2297,22 @@ static void test_CoGetContextToken(void) refs = IObjContext_Release(ctx); ok(refs == 1, "Expected 0, got %lu\n", refs); + CoUninitialize(); + + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + ok(hr == S_OK, "Expected S_OK, got 0x%08lx\n", hr); + + token = 0; + hr = pCoGetContextToken(&token); + ok(hr == S_OK, "Expected S_OK, got 0x%08lx\n", hr); + ok(token, "Expected token != 0\n"); + ok(token != token2, "token did not change\n"); + + thread = CreateThread(NULL, 0, get_context_token_thread, (void*)token, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + refs = IObjContext_Release(ctx); ok(refs == 0, "Expected 0, got %lu\n", refs); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10982
From: Piotr Caban <piotr@codeweavers.com> --- dlls/combase/combase.c | 14 +++++++++++--- dlls/ole32/tests/compobj.c | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 8b42615fc0e..ad4d0bfce68 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -2545,9 +2545,17 @@ static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId(IComThreadin static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id) { - FIXME("%s stub\n", debugstr_guid(logical_thread_id)); + struct tlsdata *tlsdata; + HRESULT hr; - return E_NOTIMPL; + TRACE("%s\n", debugstr_guid(logical_thread_id)); + + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; + + tlsdata->causality_id = *logical_thread_id; + tlsdata->flags |= OLETLS_UUIDINITIALIZED; + return S_OK; } static const IComThreadingInfoVtbl thread_context_info_vtbl = @@ -2794,7 +2802,7 @@ HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id) if (FAILED(hr = com_get_tlsdata(&tlsdata))) return hr; - if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL)) + if (!(tlsdata->flags & OLETLS_UUIDINITIALIZED)) { CoCreateGuid(&tlsdata->causality_id); tlsdata->flags |= OLETLS_UUIDINITIALIZED; diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 1f6e2326129..5ec5febb1a9 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -2044,6 +2044,21 @@ static void test_CoGetObjectContext(void) hr = CoGetCurrentLogicalThreadId(&id2); ok(IsEqualGUID(&id, &id2), "got %s, expected %s\n", wine_dbgstr_guid(&id), wine_dbgstr_guid(&id2)); + id = GUID_NULL; + hr = IComThreadingInfo_SetCurrentLogicalThreadId(pComThreadingInfo, &id); + ok(hr == S_OK, "got 0x%08lx\n", hr); + + hr = IComThreadingInfo_GetCurrentLogicalThreadId(pComThreadingInfo, &id); + ok(hr == S_OK, "got 0x%08lx\n", hr); + ok(IsEqualGUID(&id, &GUID_NULL), "id = %s\n", wine_dbgstr_guid(&id)); + + hr = CoGetCurrentLogicalThreadId(&id); + ok(hr == S_OK, "got 0x%08lx\n", hr); + ok(IsEqualGUID(&id, &GUID_NULL), "id = %s\n", wine_dbgstr_guid(&id)); + + hr = IComThreadingInfo_SetCurrentLogicalThreadId(pComThreadingInfo, &id2); + ok(hr == S_OK, "got 0x%08lx\n", hr); + hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype); ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType"); ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10982
This merge request was approved by Huw Davies. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10982
participants (3)
-
Huw Davies (@huw) -
Piotr Caban -
Piotr Caban (@piotr)