- 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
* 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.
*
*/
@ -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)

View File

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

View File

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

View File

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

View File

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