* 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:
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user