* Changes to observers and service manager APIs.

* Use nsIComponentManagerObsolete.
* Fix weak reference leaks
* Cache interface infos better for significant perf increase.
* Better tests for leaks

Not part of the build.


git-svn-id: svn://10.0.0.236/trunk@111534 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
markh%activestate.com
2002-01-08 01:58:58 +00:00
parent 12ab2a809c
commit 2e157b2b2a
14 changed files with 217 additions and 77 deletions

View File

@@ -71,7 +71,7 @@ void PyXPCOM_LogError(const char *fmt, ...)
else {
streamout << "Traceback (most recent call last):\n";
streamout << szTraceback;
PyMem_Free((ANY *)szTraceback);
PyMem_Free((void *)szTraceback);
}
}
PyObject *temp = PyObject_Str(exc_typ);

View File

@@ -44,7 +44,7 @@ extern PyG_Base *MakePyG_nsIComponentLoader(PyObject *instance);
extern PyG_Base *MakePyG_nsIInputStream(PyObject *instance);
static char *PyXPCOM_szDefaultGatewayAttributeName = "_com_instance_default_gateway_";
nsresult GetDefaultGateway(PyObject *instance, REFNSIID iid, void **ret);
PyG_Base *GetDefaultGateway(PyObject *instance);
void AddDefaultGateway(PyObject *instance, nsISupports *gateway);
PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway);
@@ -78,11 +78,33 @@ PyG_Base::PyG_Base(PyObject *instance, const nsIID &iid)
// Note that "instance" is the _policy_ instance!!
NS_INIT_REFCNT();
PR_AtomicIncrement(&cGateways);
m_pBaseObject = NULL;
m_pBaseObject = GetDefaultGateway(instance);
// m_pWeakRef is an nsCOMPtr and needs no init.
NS_ABORT_IF_FALSE(!(iid.Equals(NS_GET_IID(nsISupportsWeakReference)) || iid.Equals(NS_GET_IID(nsIWeakReference))),"Should not be creating gateways with weak-ref interfaces");
m_iid = iid;
m_pPyObject = instance;
NS_PRECONDITION(instance, "NULL PyObject for PyXPCOM_XPTStub!");
#ifdef NS_BUILD_REFCNT_LOGGING
// If XPCOM reference count logging is enabled, then allow us to give the Python class.
PyObject *realInstance = PyObject_GetAttrString(instance, "_obj_");
PyObject *r = PyObject_Repr(realInstance);
const char *szRepr = PyString_AsString(r);
if (szRepr==NULL) szRepr = "";
int reprOffset = *szRepr=='<' ? 1 : 0;
static const char *reprPrefix = "component:";
if (strncmp(reprPrefix, szRepr+reprOffset, strlen(reprPrefix)) == 0)
reprOffset += strlen(reprPrefix);
strncpy(refcntLogRepr, szRepr + reprOffset, sizeof(refcntLogRepr)-1);
refcntLogRepr[sizeof(refcntLogRepr)-1] = '\0';
// See if we should get rid of the " at 0x12345" portion.
char *lastPos = strstr(refcntLogRepr, " at ");
if (lastPos) *lastPos = '\0';
Py_XDECREF(realInstance);
Py_XDECREF(r);
#endif // NS_BUILD_REFCNT_LOGGING
#ifdef DEBUG_LIFETIMES
{
char *iid_repr;
@@ -293,8 +315,8 @@ PyG_Base::QueryInterface(REFNSIID iid, void** ppv)
}
// If we have a "base object", then we need to delegate _every_ remaining
// QI to it.
if (m_pBaseObject != NULL && (m_pBaseObject->QueryInterface(iid, ppv)==NS_OK))
return NS_OK;
if (m_pBaseObject != NULL)
return m_pBaseObject->QueryInterface(iid, ppv);
// Call the Python policy to see if it (says it) supports the interface
PRBool supports = PR_FALSE;
@@ -341,28 +363,6 @@ PyG_Base::QueryInterface(REFNSIID iid, void** ppv)
} // end of temp scope for Python lock - lock released here!
if ( !supports )
return NS_ERROR_NO_INTERFACE;
// Now setup the base object pointer back to me.
// We do a QI on our internal one to ensure we can safely cast
// the result to a PyG_Base (both from the POV that is may not
// be a Python object, and that the vtables offsets may screw
// us even if it is!)
nsISupports *pLook = (nsISupports *)(*ppv);
nsIInternalPython *pTemp;
if (pLook->QueryInterface(NS_GET_IID(nsIInternalPython), (void **)&pTemp)==NS_OK) {
// One of our objects, so set the base object if it doesnt already have one
PyG_Base *pG = (PyG_Base *)pTemp;
// Eeek - just these few next lines need to be thread-safe :-(
CEnterLeaveXPCOMFramework _celf;
if (pG->m_pBaseObject==NULL && pG != (PyG_Base *)this) {
pG->m_pBaseObject = this;
pG->m_pBaseObject->AddRef();
#ifdef DEBUG_LIFETIMES
PYXPCOM_LOG_DEBUG("PyG_Base setting BaseObject of %p to %p\n", pG, this);
#endif
}
pTemp->Release();
}
return NS_OK;
}
@@ -370,7 +370,11 @@ nsrefcnt
PyG_Base::AddRef(void)
{
nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt);
NS_LOG_ADDREF(this, cnt, "PyG_Base", sizeof(*this));
#ifdef NS_BUILD_REFCNT_LOGGING
// If we have no pBaseObject, then we need to ignore them
if (m_pBaseObject == NULL)
NS_LOG_ADDREF(this, cnt, refcntLogRepr, sizeof(*this));
#endif
return cnt;
}
@@ -378,7 +382,10 @@ nsrefcnt
PyG_Base::Release(void)
{
nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt);
NS_LOG_RELEASE(this, cnt, "PyG_Base");
#ifdef NS_BUILD_REFCNT_LOGGING
if (m_pBaseObject == NULL)
NS_LOG_RELEASE(this, cnt, refcntLogRepr);
#endif
if ( cnt == 0 )
delete this;
return cnt;
@@ -701,10 +708,14 @@ PyObject *PyG_Base::UnwrapPythonObject(void)
*********************************************************************/
nsresult GetDefaultGateway(PyObject *instance, REFNSIID iid, void **ret)
PyG_Base *GetDefaultGateway(PyObject *policy)
{
// NOTE: Instance is the real instance, _not_ the policy.
// NOTE: Instance is the policy, not the real instance
PyObject *instance = PyObject_GetAttrString(policy, "_obj_");
if (instance == nsnull)
return nsnull;
PyObject *ob_existing_weak = PyObject_GetAttrString(instance, PyXPCOM_szDefaultGatewayAttributeName);
Py_DECREF(instance);
if (ob_existing_weak != NULL) {
PRBool ok = PR_TRUE;
nsCOMPtr<nsIWeakReference> pWeakRef;
@@ -713,11 +724,16 @@ nsresult GetDefaultGateway(PyObject *instance, REFNSIID iid, void **ret)
getter_AddRefs(pWeakRef),
PR_FALSE));
Py_DECREF(ob_existing_weak);
if (ok)
return pWeakRef->QueryReferent( iid, ret);
nsISupports *pip;
if (ok) {
nsresult nr = pWeakRef->QueryReferent( NS_GET_IID(nsIInternalPython), (void **)&pip);
if (NS_FAILED(nr))
return nsnull;
return (PyG_Base *)(nsIInternalPython *)pip;
}
} else
PyErr_Clear();
return NS_ERROR_FAILURE;
return nsnull;
}
PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway)

View File

@@ -34,6 +34,14 @@ PyXPCOM_GatewayWeakReference::PyXPCOM_GatewayWeakReference( PyG_Base *base )
{
m_pBase = base;
NS_INIT_REFCNT();
#ifdef NS_BUILD_REFCNT_LOGGING
// bloat view uses 40 chars - stick "(WR)" at the end of this position.
strncpy(refcntLogRepr, m_pBase->refcntLogRepr, sizeof(refcntLogRepr));
refcntLogRepr[sizeof(refcntLogRepr)-1] = '\0';
char *dest = refcntLogRepr + ((strlen(refcntLogRepr) > 36) ? 36 : strlen(refcntLogRepr));
strcpy(dest, "(WR)");
#endif // NS_BUILD_REFCNT_LOGGING
}
PyXPCOM_GatewayWeakReference::~PyXPCOM_GatewayWeakReference()
@@ -45,7 +53,29 @@ PyXPCOM_GatewayWeakReference::~PyXPCOM_GatewayWeakReference()
m_pBase = NULL;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(PyXPCOM_GatewayWeakReference, nsIWeakReference)
nsrefcnt
PyXPCOM_GatewayWeakReference::AddRef(void)
{
nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt);
#ifdef NS_BUILD_REFCNT_LOGGING
NS_LOG_ADDREF(this, cnt, refcntLogRepr, sizeof(*this));
#endif
return cnt;
}
nsrefcnt
PyXPCOM_GatewayWeakReference::Release(void)
{
nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt);
#ifdef NS_BUILD_REFCNT_LOGGING
NS_LOG_RELEASE(this, cnt, refcntLogRepr);
#endif
if ( cnt == 0 )
delete this;
return cnt;
}
NS_IMPL_THREADSAFE_QUERY_INTERFACE1(PyXPCOM_GatewayWeakReference, nsIWeakReference);
NS_IMETHODIMP
PyXPCOM_GatewayWeakReference::QueryReferent(REFNSIID iid, void * *ret)

View File

@@ -28,16 +28,16 @@
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIComponentManager.h>
#include <nsIComponentManagerObsolete.h>
static nsIComponentManager *GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsIComponentManager);
static nsIComponentManagerObsolete *GetI(PyObject *self) {
static const nsIID iid = NS_GET_IID(nsIComponentManagerObsolete);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsIComponentManager *)Py_nsISupports::GetI(self);
return (nsIComponentManagerObsolete *)Py_nsISupports::GetI(self);
}
static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args)
@@ -50,7 +50,7 @@ static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args)
PyErr_SetString(PyExc_ValueError, "2nd arg must be none");
return NULL;
}
nsIComponentManager *pI = GetI(self);
nsIComponentManagerObsolete *pI = GetI(self);
if (pI==NULL)
return NULL;
@@ -78,7 +78,7 @@ static PyObject *PyContractIDToClassID(PyObject *self, PyObject *args)
char *pid;
if (!PyArg_ParseTuple(args, "s", &pid))
return NULL;
nsIComponentManager *pI = GetI(self);
nsIComponentManagerObsolete *pI = GetI(self);
if (pI==NULL)
return NULL;
@@ -104,7 +104,7 @@ static PyObject *PyCLSIDToContractID(PyObject *self, PyObject *args)
return NULL;
char *ret_pid = nsnull;
char *ret_class = nsnull;
nsIComponentManager *pI = GetI(self);
nsIComponentManagerObsolete *pI = GetI(self);
if (pI==NULL)
return NULL;
@@ -130,7 +130,7 @@ static PyObject *PyEnumerateCLSIDs(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIComponentManager *pI = GetI(self);
nsIComponentManagerObsolete *pI = GetI(self);
if (pI==NULL)
return NULL;
@@ -150,7 +150,7 @@ static PyObject *PyEnumerateContractIDs(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIComponentManager *pI = GetI(self);
nsIComponentManagerObsolete *pI = GetI(self);
if (pI==NULL)
return NULL;

View File

@@ -361,6 +361,9 @@ public:
// This means that once we have created it (and while we
// are alive) it will never die.
nsCOMPtr<nsIWeakReference> m_pWeakRef;
#ifdef NS_BUILD_REFCNT_LOGGING
char refcntLogRepr[64]; // sigh - I wish I knew how to use the Moz string classes :( OK for debug only tho.
#endif
protected:
PyG_Base(PyObject *instance, const nsIID &iid);
virtual ~PyG_Base();
@@ -430,6 +433,9 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEAKREFERENCE;
PyG_Base *m_pBase; // NO REF COUNT!!!
#ifdef NS_BUILD_REFCNT_LOGGING
char refcntLogRepr[41];
#endif
};
@@ -655,7 +661,7 @@ PyXPCOM_TypeObject *ClassName::type = NULL;
// And the classes
PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManagerObsolete, PyMethods_IComponentManager)
PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)

View File

@@ -225,7 +225,7 @@ static void LogError(const char *fmt, ...)
else {
streamout << "Traceback (most recent call last):\n";
streamout << szTraceback;
PyMem_Free((ANY *)szTraceback);
PyMem_Free((void *)szTraceback);
}
}
PyObject *temp = PyObject_Str(exc_typ);

View File

@@ -56,7 +56,7 @@ extern void PyXPCOM_InterpreterState_Ensure();
#endif // XP_WIN
PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManagerObsolete, PyMethods_IComponentManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
@@ -170,7 +170,7 @@ PyXPCOMMethod_NS_GetGlobalComponentManager(PyObject *self, PyObject *args)
// Return a type based on the IID
// Can not auto-wrap the interface info manager as it is critical to
// building the support we need for autowrap.
return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsIComponentManager), PR_TRUE, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsIComponentManagerObsolete), PR_TRUE, PR_FALSE);
}
static PyObject *
@@ -594,7 +594,14 @@ init_xpcom() {
Py_nsIInterfaceInfo::InitType(dict);
Py_nsIInputStream::InitType(dict);
Py_nsIClassInfo::InitType(dict);
// yet another
{ // temp scope nsIComponentManagerObsolete hack :(
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(NS_GET_IID(nsIComponentManagerObsolete));
PyDict_SetItemString(dict, "IID_nsIComponentManager", iid_ob);
Py_DECREF(iid_ob);
} // end temp scope
// We have special support for proxies - may as well add their constants!
REGISTER_INT(PROXY_SYNC);
REGISTER_INT(PROXY_ASYNC);