Commit f8a2edb8 authored by Robert Shearman's avatar Robert Shearman Committed by Alexandre Julliard

- 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).
parent 19e86c7d
...@@ -31,23 +31,19 @@ ...@@ -31,23 +31,19 @@
* - 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.
* *
*/ */
#include "config.h" #include "config.h"
...@@ -219,72 +215,91 @@ void COM_TlsDestroy() ...@@ -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 = COM_CurrentApt(); APARTMENT *apt;
if (!apt) TRACE("creating new apartment, model=%ld\n", model);
{
/* 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); apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
apt->tid = GetCurrentThreadId();
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &apt->thread,
THREAD_ALL_ACCESS, FALSE, 0);
COM_CurrentInfo()->apt = apt; list_init(&apt->proxies);
return apt; 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;
}
TRACE("creating new apartment, model=%ld\n", model); apt->shutdown_event = CreateEventW(NULL, TRUE, FALSE, NULL);
TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT)); /* the locking here is not currently needed for the MTA case, but it
apt->tid = GetCurrentThreadId(); * doesn't hurt and makes the code simpler */
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), EnterCriticalSection(&csApartment);
GetCurrentProcess(), &apt->thread, list_add_head(&apts, &apt->entry);
THREAD_ALL_ACCESS, FALSE, 0); LeaveCriticalSection(&csApartment);
list_init(&apt->proxies); return apt;
list_init(&apt->stubmgrs); }
apt->ipidc = 0;
apt->refs = 1;
apt->remunk_exported = FALSE;
apt->oidc = 1;
InitializeCriticalSection(&apt->cs);
apt->model = model; /* 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)
{
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 */
apt->shutdown_event = CreateEventA(NULL, TRUE, FALSE, NULL); if (MTA)
{
TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
COM_ApartmentAddRef(MTA);
}
else
MTA = apartment_construct(model);
list_add_head(&apts, &apt->entry); apt = MTA;
LeaveCriticalSection(&csApartment); COM_CurrentInfo()->apt = apt;
COM_CurrentInfo()->apt = apt; LeaveCriticalSection(&csApartment);
}
} }
return apt; return apt;
...@@ -292,7 +307,9 @@ APARTMENT* COM_CreateApartment(DWORD model) ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
...@@ -790,7 +790,7 @@ static DWORD WINAPI client_dispatch_thread(LPVOID param) ...@@ -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 */ /* join marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */
COM_CurrentInfo()->apt = apt; COM_CurrentInfo()->apt = apt;
while (TRUE) while (TRUE)
{ {
int i; int i;
...@@ -825,6 +825,10 @@ static DWORD WINAPI client_dispatch_thread(LPVOID param) ...@@ -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) ...@@ -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() ...@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment