Commit a6a416cb authored by Mike Hearn's avatar Mike Hearn Committed by Alexandre Julliard

- Make apartment access thread-safe by introducing refcounting and

wider usage of the apartment lock. - Rework OLE TLS management to eliminate uninitialised apartments and parent chaining.
parent a790b2d1
......@@ -38,12 +38,8 @@
#include "winreg.h"
#include "winternl.h"
/* Windows maps COINIT values to 0x80 for apartment threaded, 0x140
* for free threaded, and 0 for uninitialized apartments. There is
* no real advantage in us doing this and certainly no release version
* of an app should be poking around with these flags. So we need a
* special value for uninitialized */
#define COINIT_UNINITIALIZED 0x100
struct apartment;
/* exported interface */
typedef struct tagXIF {
......@@ -59,7 +55,7 @@ typedef struct tagXIF {
/* exported object */
typedef struct tagXOBJECT {
IRpcStubBufferVtbl *lpVtbl;
struct tagAPARTMENT *parent;
struct apartment *parent;
struct tagXOBJECT *next;
LPUNKNOWN obj; /* object identity (IUnknown) */
OID oid; /* object ID */
......@@ -83,7 +79,7 @@ struct ifproxy
struct proxy_manager
{
const IInternalUnknownVtbl *lpVtbl;
struct tagAPARTMENT *parent;
struct apartment *parent;
struct list entry;
LPRPCCHANNELBUFFER chan; /* channel to object */
OXID oxid; /* object exported ID */
......@@ -93,11 +89,13 @@ struct proxy_manager
CRITICAL_SECTION cs; /* thread safety for this object and children */
};
/* apartment */
typedef struct tagAPARTMENT {
struct tagAPARTMENT *next, *prev, *parent;
/* this needs to become a COM object that implements IRemUnknown */
struct apartment
{
struct list entry;
DWORD refs; /* refcount of the apartment */
DWORD model; /* threading model */
DWORD inits; /* CoInitialize count */
DWORD tid; /* thread id */
HANDLE thread; /* thread handle */
OXID oxid; /* object exporter ID */
......@@ -107,13 +105,11 @@ typedef struct tagAPARTMENT {
LPMESSAGEFILTER filter; /* message filter */
XOBJECT *objs; /* exported objects */
struct list proxies; /* imported objects */
LPUNKNOWN state; /* state object (see Co[Get,Set]State) */
LPVOID ErrorInfo; /* thread error info */
DWORD listenertid; /* id of apartment_listener_thread */
struct list stubmgrs; /* stub managers for exported objects */
} APARTMENT;
};
extern APARTMENT MTA, *apts;
typedef struct apartment APARTMENT;
extern void* StdGlobalInterfaceTable_Construct(void);
extern void StdGlobalInterfaceTable_Destroy(void* self);
......@@ -196,27 +192,41 @@ int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id);
/* compobj.c */
APARTMENT *COM_CreateApartment(DWORD model);
APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref);
DWORD COM_ApartmentAddRef(struct apartment *apt);
DWORD COM_ApartmentRelease(struct apartment *apt);
extern CRITICAL_SECTION csApartment;
/* this is what is stored in TEB->ReservedForOle */
struct oletls
{
struct apartment *apt;
IErrorInfo *errorinfo; /* see errorinfo.c */
IUnknown *state; /* see CoSetState */
};
/*
* Per-thread values are stored in the TEB on offset 0xF80,
* see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm
*/
static inline APARTMENT* COM_CurrentInfo(void)
/* will create if necessary */
static inline struct oletls *COM_CurrentInfo(void)
{
APARTMENT* apt = NtCurrentTeb()->ReservedForOle;
return apt;
if (!NtCurrentTeb()->ReservedForOle)
NtCurrentTeb()->ReservedForOle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct oletls));
return NtCurrentTeb()->ReservedForOle;
}
static inline APARTMENT* COM_CurrentApt(void)
{
APARTMENT* apt = COM_CurrentInfo();
if (apt && apt->parent) apt = apt->parent;
return apt;
{
return COM_CurrentInfo()->apt;
}
/* compobj.c */
APARTMENT *COM_CreateApartment(DWORD model);
HWND COM_GetApartmentWin(OXID oxid);
APARTMENT *COM_ApartmentFromOXID(OXID oxid);
#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
#endif /* __WINE_OLE_COMPOBJ_H */
......@@ -20,7 +20,7 @@
* NOTES:
*
* The errorinfo is a per-thread object. The reference is stored in the
* TEB at offset 0xf80
* TEB at offset 0xf80.
*/
#include <stdarg.h>
......@@ -483,20 +483,20 @@ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo)
*/
HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
{
APARTMENT * apt = COM_CurrentInfo();
TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->ErrorInfo);
TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo);
if(!pperrinfo) return E_INVALIDARG;
if (!apt || !apt->ErrorInfo)
if (!COM_CurrentInfo()->errorinfo)
{
*pperrinfo = NULL;
return S_FALSE;
}
*pperrinfo = (IErrorInfo*)(apt->ErrorInfo);
*pperrinfo = COM_CurrentInfo()->errorinfo;
/* clear thread error state */
apt->ErrorInfo = NULL;
COM_CurrentInfo()->errorinfo = NULL;
return S_OK;
}
......@@ -506,18 +506,16 @@ HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo)
{
IErrorInfo * pei;
APARTMENT * apt = COM_CurrentInfo();
TRACE("(%ld, %p)\n", dwReserved, perrinfo);
if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
/* release old errorinfo */
pei = (IErrorInfo*)apt->ErrorInfo;
if(pei) IErrorInfo_Release(pei);
pei = COM_CurrentInfo()->errorinfo;
if (pei) IErrorInfo_Release(pei);
/* set to new value */
apt->ErrorInfo = perrinfo;
if(perrinfo) IErrorInfo_AddRef(perrinfo);
COM_CurrentInfo()->errorinfo = perrinfo;
if (perrinfo) IErrorInfo_AddRef(perrinfo);
return S_OK;
}
......@@ -109,9 +109,13 @@ static HRESULT register_ifstub(wine_marshal_id *mid, IUnknown *obj, IRpcStubBuff
}
else
{
TRACE("constructing new stub manager\n");
struct apartment *apt;
manager = new_stub_manager(COM_ApartmentFromOXID(mid->oxid), obj);
TRACE("constructing new stub manager\n");
apt = COM_ApartmentFromOXID(mid->oxid, TRUE);
manager = new_stub_manager(apt, obj);
COM_ApartmentRelease(apt);
if (!manager) return E_OUTOFMEMORY;
if (!tablemarshal) stub_manager_ref(manager, 1);
......
......@@ -308,8 +308,6 @@ PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
if (ref)
return ref;
FIXME("Free all stuff\n");
memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id));
pipe = PIPE_FindByMID(&This->mid);
......@@ -892,7 +890,7 @@ static DWORD WINAPI apartment_listener_thread(LPVOID param)
HANDLE listenPipe;
APARTMENT *apt = (APARTMENT *) param;
/* we must join the marshalling threads apartment */
/* we must join the marshalling threads apartment. we already have a ref here */
NtCurrentTeb()->ReservedForOle = apt;
sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid));
......@@ -926,7 +924,7 @@ static DWORD WINAPI apartment_listener_thread(LPVOID param)
void start_apartment_listener_thread()
{
APARTMENT *apt = COM_CurrentApt();
assert( apt );
TRACE("apt->listenertid=%ld\n", apt->listenertid);
......
......@@ -41,6 +41,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(ole);
/* this refs the apartment on success, otherwise there is no ref */
struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
{
struct stub_manager *sm;
......@@ -71,6 +72,7 @@ struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
list_add_head(&apt->stubmgrs, &sm->entry);
LeaveCriticalSection(&apt->cs);
COM_ApartmentAddRef(apt);
TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object);
return sm;
......@@ -82,7 +84,7 @@ struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object)
struct list *cursor;
APARTMENT *apt;
if (!(apt = COM_ApartmentFromOXID(oxid)))
if (!(apt = COM_ApartmentFromOXID(oxid, TRUE)))
{
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
return NULL;
......@@ -101,6 +103,8 @@ struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object)
}
LeaveCriticalSection(&apt->cs);
COM_ApartmentRelease(apt);
TRACE("found %p from object %p\n", result, object);
return result;
......@@ -112,14 +116,13 @@ struct stub_manager *get_stub_manager(OXID oxid, OID oid)
struct list *cursor;
APARTMENT *apt;
if (!(apt = COM_ApartmentFromOXID(oxid)))
if (!(apt = COM_ApartmentFromOXID(oxid, TRUE)))
{
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
return NULL;
}
EnterCriticalSection(&apt->cs);
LIST_FOR_EACH( cursor, &apt->stubmgrs )
{
struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
......@@ -130,9 +133,10 @@ struct stub_manager *get_stub_manager(OXID oxid, OID oid)
break;
}
}
LeaveCriticalSection(&apt->cs);
COM_ApartmentRelease(apt);
TRACE("found %p from oid %s\n", result, wine_dbgstr_longlong(oid));
return result;
......
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