- Split up apartment creation so that the long code paths that don't
need locking no longer have locking. - Add special cases for the threads that join apartments but can't increase the refcount of the apartment. - Free TLS storage on thread destruction (including releasing the apartment the thread is in, if any, and so making another test pass).
This commit is contained in:
parent
19e86c7de3
commit
f8a2edb805
|
@ -31,23 +31,19 @@
|
|||
* - Rewrite the CoLockObjectExternal code, it does totally the wrong
|
||||
* thing currently (should be controlling the stub manager)
|
||||
*
|
||||
* - Free the ReservedForOle data in DllMain(THREAD_DETACH)
|
||||
*
|
||||
* - Implement the service control manager (in rpcss) to keep track
|
||||
* of registered class objects: ISCM::ServerRegisterClsid et al
|
||||
* - Implement the OXID resolver so we don't need magic pipe names for
|
||||
* clients and servers to meet up
|
||||
* - Flip our marshalling on top of the RPC runtime transport API,
|
||||
* so we no longer use named pipes to communicate
|
||||
* - Rework threading so re-entrant calls don't need to be sent on
|
||||
* the incoming pipe
|
||||
* - Implement RPC thread affinity (should fix InstallShield painting
|
||||
* problems)
|
||||
*
|
||||
* - Make our custom marshalling use NDR to be wire compatible with
|
||||
* - Make all ole interface marshaling use NDR to be wire compatible with
|
||||
* native DCOM
|
||||
*
|
||||
*
|
||||
* - Use & interpret ORPCTHIS & ORPCTHAT.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
@ -219,72 +215,91 @@ void COM_TlsDestroy()
|
|||
* Manage apartments.
|
||||
*/
|
||||
|
||||
/* creates an apartment structure which stores OLE apartment-local
|
||||
* information */
|
||||
APARTMENT* COM_CreateApartment(DWORD model)
|
||||
/* allocates memory and fills in the necessary fields for a new apartment
|
||||
* object */
|
||||
static APARTMENT *apartment_construct(DWORD model)
|
||||
{
|
||||
APARTMENT *apt;
|
||||
|
||||
TRACE("creating new apartment, model=%ld\n", model);
|
||||
|
||||
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
|
||||
apt->tid = GetCurrentThreadId();
|
||||
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
||||
GetCurrentProcess(), &apt->thread,
|
||||
THREAD_ALL_ACCESS, FALSE, 0);
|
||||
|
||||
list_init(&apt->proxies);
|
||||
list_init(&apt->stubmgrs);
|
||||
apt->ipidc = 0;
|
||||
apt->refs = 1;
|
||||
apt->remunk_exported = FALSE;
|
||||
apt->oidc = 1;
|
||||
InitializeCriticalSection(&apt->cs);
|
||||
|
||||
apt->model = model;
|
||||
|
||||
if (model & COINIT_APARTMENTTHREADED)
|
||||
{
|
||||
/* FIXME: should be randomly generated by in an RPC call to rpcss */
|
||||
apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
|
||||
apt->win = CreateWindowA(aptWinClass, NULL, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, OLE32_hInstance, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: should be randomly generated by in an RPC call to rpcss */
|
||||
apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
|
||||
}
|
||||
|
||||
apt->shutdown_event = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
|
||||
|
||||
/* the locking here is not currently needed for the MTA case, but it
|
||||
* doesn't hurt and makes the code simpler */
|
||||
EnterCriticalSection(&csApartment);
|
||||
list_add_head(&apts, &apt->entry);
|
||||
LeaveCriticalSection(&csApartment);
|
||||
|
||||
return apt;
|
||||
}
|
||||
|
||||
/* gets and existing apartment if one exists or otherwise creates an apartment
|
||||
* structure which stores OLE apartment-local information and stores a pointer
|
||||
* to it in the thread-local storage */
|
||||
static APARTMENT *get_or_create_apartment(DWORD model)
|
||||
{
|
||||
APARTMENT *apt = COM_CurrentApt();
|
||||
|
||||
if (!apt)
|
||||
{
|
||||
/* The multi-threaded apartment (MTA) contains zero or more threads interacting
|
||||
* with free threaded (ie thread safe) COM objects. There is only ever one MTA
|
||||
* in a process
|
||||
*/
|
||||
EnterCriticalSection(&csApartment);
|
||||
if (!(model & COINIT_APARTMENTTHREADED) && MTA) /* See note 1 above */
|
||||
{
|
||||
TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
|
||||
apt = MTA;
|
||||
COM_ApartmentAddRef(apt);
|
||||
|
||||
LeaveCriticalSection(&csApartment);
|
||||
|
||||
COM_CurrentInfo()->apt = apt;
|
||||
return apt;
|
||||
}
|
||||
|
||||
TRACE("creating new apartment, model=%ld\n", model);
|
||||
|
||||
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
|
||||
apt->tid = GetCurrentThreadId();
|
||||
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
||||
GetCurrentProcess(), &apt->thread,
|
||||
THREAD_ALL_ACCESS, FALSE, 0);
|
||||
|
||||
list_init(&apt->proxies);
|
||||
list_init(&apt->stubmgrs);
|
||||
apt->ipidc = 0;
|
||||
apt->refs = 1;
|
||||
apt->remunk_exported = FALSE;
|
||||
apt->oidc = 1;
|
||||
InitializeCriticalSection(&apt->cs);
|
||||
|
||||
apt->model = model;
|
||||
|
||||
if (model & COINIT_APARTMENTTHREADED)
|
||||
{
|
||||
/* FIXME: should be randomly generated by in an RPC call to rpcss */
|
||||
apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
|
||||
apt->win = CreateWindowA(aptWinClass, NULL, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, OLE32_hInstance, NULL);
|
||||
apt = apartment_construct(model);
|
||||
COM_CurrentInfo()->apt = apt;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: should be randomly generated by in an RPC call to rpcss */
|
||||
apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
|
||||
MTA = apt;
|
||||
EnterCriticalSection(&csApartment);
|
||||
|
||||
/* The multi-threaded apartment (MTA) contains zero or more threads interacting
|
||||
* with free threaded (ie thread safe) COM objects. There is only ever one MTA
|
||||
* in a process */
|
||||
if (MTA)
|
||||
{
|
||||
TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
|
||||
COM_ApartmentAddRef(MTA);
|
||||
}
|
||||
else
|
||||
MTA = apartment_construct(model);
|
||||
|
||||
apt = MTA;
|
||||
COM_CurrentInfo()->apt = apt;
|
||||
|
||||
LeaveCriticalSection(&csApartment);
|
||||
}
|
||||
|
||||
apt->shutdown_event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
|
||||
|
||||
list_add_head(&apts, &apt->entry);
|
||||
LeaveCriticalSection(&csApartment);
|
||||
|
||||
COM_CurrentInfo()->apt = apt;
|
||||
}
|
||||
|
||||
return apt;
|
||||
|
@ -292,7 +307,9 @@ APARTMENT* COM_CreateApartment(DWORD model)
|
|||
|
||||
DWORD COM_ApartmentAddRef(struct apartment *apt)
|
||||
{
|
||||
return InterlockedIncrement(&apt->refs);
|
||||
DWORD refs = InterlockedIncrement(&apt->refs);
|
||||
TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
|
||||
return refs;
|
||||
}
|
||||
|
||||
DWORD COM_ApartmentRelease(struct apartment *apt)
|
||||
|
@ -302,6 +319,7 @@ DWORD COM_ApartmentRelease(struct apartment *apt)
|
|||
EnterCriticalSection(&csApartment);
|
||||
|
||||
ret = InterlockedDecrement(&apt->refs);
|
||||
TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
|
||||
/* destruction stuff that needs to happen under csApartment CS */
|
||||
if (ret == 0)
|
||||
{
|
||||
|
@ -594,7 +612,7 @@ HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
|
|||
|
||||
if (!(apt = COM_CurrentInfo()->apt))
|
||||
{
|
||||
apt = COM_CreateApartment(dwCoInit);
|
||||
apt = get_or_create_apartment(dwCoInit);
|
||||
if (!apt) return E_OUTOFMEMORY;
|
||||
}
|
||||
else if (dwCoInit != apt->model)
|
||||
|
|
|
@ -209,7 +209,6 @@ HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void);
|
|||
int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
|
||||
|
||||
/* compobj.c */
|
||||
APARTMENT *COM_CreateApartment(DWORD model);
|
||||
APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref);
|
||||
APARTMENT *COM_ApartmentFromTID(DWORD tid);
|
||||
DWORD COM_ApartmentAddRef(struct apartment *apt);
|
||||
|
|
|
@ -121,7 +121,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
|
|||
|
||||
switch(fdwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
OLE32_hInstance = hinstDLL;
|
||||
COMPOBJ_InitProcess();
|
||||
if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
|
||||
|
@ -132,6 +131,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
|
|||
COMPOBJ_UninitProcess();
|
||||
OLE32_hInstance = 0;
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
COM_TlsDestroy();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -790,7 +790,7 @@ static DWORD WINAPI client_dispatch_thread(LPVOID param)
|
|||
|
||||
/* join marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */
|
||||
COM_CurrentInfo()->apt = apt;
|
||||
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
int i;
|
||||
|
@ -825,6 +825,10 @@ static DWORD WINAPI client_dispatch_thread(LPVOID param)
|
|||
}
|
||||
|
||||
TRACE("exiting with hres %lx\n",hres);
|
||||
|
||||
/* leave marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */
|
||||
COM_CurrentInfo()->apt = NULL;
|
||||
|
||||
DisconnectNamedPipe(pipe);
|
||||
CloseHandle(pipe);
|
||||
return 0;
|
||||
|
@ -934,6 +938,9 @@ static DWORD WINAPI apartment_listener_thread(LPVOID p)
|
|||
|
||||
TRACE("shutting down: %s\n", wine_dbgstr_longlong(this_oxid));
|
||||
|
||||
/* we must leave the marshalling threads apartment. we don't have a ref here */
|
||||
COM_CurrentInfo()->apt = NULL;
|
||||
|
||||
DisconnectNamedPipe(listenPipe);
|
||||
CloseHandle(listenPipe);
|
||||
CloseHandle(overlapped.hEvent);
|
||||
|
|
|
@ -588,7 +588,7 @@ static void test_no_couninitialize()
|
|||
SetEvent(ncu_params.unmarshal_event);
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
|
||||
todo_wine { ok_no_locks(); }
|
||||
ok_no_locks();
|
||||
|
||||
CloseHandle(thread);
|
||||
CloseHandle(ncu_params.marshal_event);
|
||||
|
|
Loading…
Reference in New Issue