- 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:
Robert Shearman 2005-02-08 13:42:15 +00:00 committed by Alexandre Julliard
parent 19e86c7de3
commit f8a2edb805
5 changed files with 95 additions and 68 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);