- 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,22 +31,18 @@
|
||||||
* - Rewrite the CoLockObjectExternal code, it does totally the wrong
|
* - Rewrite the CoLockObjectExternal code, it does totally the wrong
|
||||||
* thing currently (should be controlling the stub manager)
|
* 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
|
* - Implement the service control manager (in rpcss) to keep track
|
||||||
* of registered class objects: ISCM::ServerRegisterClsid et al
|
* of registered class objects: ISCM::ServerRegisterClsid et al
|
||||||
* - Implement the OXID resolver so we don't need magic pipe names for
|
* - Implement the OXID resolver so we don't need magic pipe names for
|
||||||
* clients and servers to meet up
|
* clients and servers to meet up
|
||||||
* - Flip our marshalling on top of the RPC runtime transport API,
|
* - Flip our marshalling on top of the RPC runtime transport API,
|
||||||
* so we no longer use named pipes to communicate
|
* 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
|
* - Implement RPC thread affinity (should fix InstallShield painting
|
||||||
* problems)
|
* 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
|
* native DCOM
|
||||||
*
|
* - Use & interpret ORPCTHIS & ORPCTHAT.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -219,72 +215,91 @@ void COM_TlsDestroy()
|
||||||
* Manage apartments.
|
* Manage apartments.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* creates an apartment structure which stores OLE apartment-local
|
/* allocates memory and fills in the necessary fields for a new apartment
|
||||||
* information */
|
* object */
|
||||||
APARTMENT* COM_CreateApartment(DWORD model)
|
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();
|
APARTMENT *apt = COM_CurrentApt();
|
||||||
|
|
||||||
if (!apt)
|
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)
|
if (model & COINIT_APARTMENTTHREADED)
|
||||||
{
|
{
|
||||||
/* FIXME: should be randomly generated by in an RPC call to rpcss */
|
apt = apartment_construct(model);
|
||||||
apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
|
COM_CurrentInfo()->apt = apt;
|
||||||
apt->win = CreateWindowA(aptWinClass, NULL, 0,
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 0, OLE32_hInstance, NULL);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* FIXME: should be randomly generated by in an RPC call to rpcss */
|
EnterCriticalSection(&csApartment);
|
||||||
apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
|
|
||||||
MTA = 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 */
|
||||||
|
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;
|
return apt;
|
||||||
|
@ -292,7 +307,9 @@ APARTMENT* COM_CreateApartment(DWORD model)
|
||||||
|
|
||||||
DWORD COM_ApartmentAddRef(struct apartment *apt)
|
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)
|
DWORD COM_ApartmentRelease(struct apartment *apt)
|
||||||
|
@ -302,6 +319,7 @@ DWORD COM_ApartmentRelease(struct apartment *apt)
|
||||||
EnterCriticalSection(&csApartment);
|
EnterCriticalSection(&csApartment);
|
||||||
|
|
||||||
ret = InterlockedDecrement(&apt->refs);
|
ret = InterlockedDecrement(&apt->refs);
|
||||||
|
TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
|
||||||
/* destruction stuff that needs to happen under csApartment CS */
|
/* destruction stuff that needs to happen under csApartment CS */
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
|
@ -594,7 +612,7 @@ HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
|
||||||
|
|
||||||
if (!(apt = COM_CurrentInfo()->apt))
|
if (!(apt = COM_CurrentInfo()->apt))
|
||||||
{
|
{
|
||||||
apt = COM_CreateApartment(dwCoInit);
|
apt = get_or_create_apartment(dwCoInit);
|
||||||
if (!apt) return E_OUTOFMEMORY;
|
if (!apt) return E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
else if (dwCoInit != apt->model)
|
else if (dwCoInit != apt->model)
|
||||||
|
|
|
@ -209,7 +209,6 @@ HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void);
|
||||||
int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
|
int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
|
||||||
|
|
||||||
/* compobj.c */
|
/* compobj.c */
|
||||||
APARTMENT *COM_CreateApartment(DWORD model);
|
|
||||||
APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref);
|
APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref);
|
||||||
APARTMENT *COM_ApartmentFromTID(DWORD tid);
|
APARTMENT *COM_ApartmentFromTID(DWORD tid);
|
||||||
DWORD COM_ApartmentAddRef(struct apartment *apt);
|
DWORD COM_ApartmentAddRef(struct apartment *apt);
|
||||||
|
|
|
@ -121,7 +121,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
|
||||||
|
|
||||||
switch(fdwReason) {
|
switch(fdwReason) {
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
DisableThreadLibraryCalls(hinstDLL);
|
|
||||||
OLE32_hInstance = hinstDLL;
|
OLE32_hInstance = hinstDLL;
|
||||||
COMPOBJ_InitProcess();
|
COMPOBJ_InitProcess();
|
||||||
if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
|
if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
|
||||||
|
@ -132,6 +131,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
|
||||||
COMPOBJ_UninitProcess();
|
COMPOBJ_UninitProcess();
|
||||||
OLE32_hInstance = 0;
|
OLE32_hInstance = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
COM_TlsDestroy();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -825,6 +825,10 @@ static DWORD WINAPI client_dispatch_thread(LPVOID param)
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("exiting with hres %lx\n",hres);
|
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);
|
DisconnectNamedPipe(pipe);
|
||||||
CloseHandle(pipe);
|
CloseHandle(pipe);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -934,6 +938,9 @@ static DWORD WINAPI apartment_listener_thread(LPVOID p)
|
||||||
|
|
||||||
TRACE("shutting down: %s\n", wine_dbgstr_longlong(this_oxid));
|
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);
|
DisconnectNamedPipe(listenPipe);
|
||||||
CloseHandle(listenPipe);
|
CloseHandle(listenPipe);
|
||||||
CloseHandle(overlapped.hEvent);
|
CloseHandle(overlapped.hEvent);
|
||||||
|
|
|
@ -588,7 +588,7 @@ static void test_no_couninitialize()
|
||||||
SetEvent(ncu_params.unmarshal_event);
|
SetEvent(ncu_params.unmarshal_event);
|
||||||
WaitForSingleObject(thread, INFINITE);
|
WaitForSingleObject(thread, INFINITE);
|
||||||
|
|
||||||
todo_wine { ok_no_locks(); }
|
ok_no_locks();
|
||||||
|
|
||||||
CloseHandle(thread);
|
CloseHandle(thread);
|
||||||
CloseHandle(ncu_params.marshal_event);
|
CloseHandle(ncu_params.marshal_event);
|
||||||
|
|
Loading…
Reference in New Issue