* 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.
This commit is contained in:
markh%activestate.com 2002-01-08 01:58:58 +00:00
parent e36a625871
commit 88e93b42ba
14 changed files with 217 additions and 77 deletions

View File

@ -73,9 +73,13 @@ interface_cache = {}
# Keyed by [iid][name], each item is an unbound method.
interface_method_cache = {}
# Keyed by clsid from nsIClassInfo - everything ever queried for the CID.
contractid_info_cache = {}
def _shutdown():
interface_cache.clear()
interface_method_cache.clear()
contractid_info_cache.clear()
# Fully process the named method, generating method code etc.
def BuildMethod(method_info, iid):
@ -214,14 +218,27 @@ class Component(_XPCOMBase):
except COMException:
classinfo = None
if classinfo is not None:
# print "YAY - have class info!!", classinfo
real_cid = classinfo.contractID
if real_cid is not None:
if real_cid:
self.__dict__['_object_name_'] = real_cid
for nominated_iid in classinfo.getInterfaces():
# Interface may appear twice in the class info list, so check this here.
if not self.__dict__['_interface_infos_'].has_key(nominated_iid):
self._remember_interface_info(nominated_iid)
contractid_info = contractid_info_cache.get(real_cid)
else:
contractid_info = None
if contractid_info is None:
# print "YAY - have class info!!", classinfo
for nominated_iid in classinfo.getInterfaces():
# Interface may appear twice in the class info list, so check this here.
if not self.__dict__['_interface_infos_'].has_key(nominated_iid):
self._remember_interface_info(nominated_iid)
if real_cid is not None:
contractid_info = {}
contractid_info['_name_to_interface_name_'] = self.__dict__['_name_to_interface_name_']
contractid_info['_interface_infos_'] = self.__dict__['_interface_infos_']
contractid_info_cache[real_cid] = contractid_info
else:
for key, val in contractid_info.items():
self.__dict__[key].update(val)
self.__dict__['_com_classinfo_'] = classinfo
def _remember_interface_info(self, iid):
@ -307,7 +324,12 @@ class Component(_XPCOMBase):
setattr(interface, attr, val)
return
raise AttributeError, "XPCOM component '%s' can not set attribute '%s'" % (self._object_name_, attr)
def __repr__(self):
# We can advantage from nsIClassInfo - use it.
if not self._tried_classinfo_:
self._build_all_supported_interfaces_()
return _XPCOMBase.__repr__(self)
class _Interface(_XPCOMBase):
def __init__(self, comobj, iid, method_infos, getters, setters, constants):
self.__dict__['_comobj_'] = comobj

View File

@ -37,8 +37,11 @@ manager = xpcom.client.Component(_xpcom.NS_GetGlobalComponentManager(), _xpcom.I
# The "interfaceInfoManager" object - JS doesnt have this.
interfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager()
# The serviceManager - JS doesnt have this either!
serviceManager = _xpcom.GetGlobalServiceManager()
# The "Exception" object
Exception = xpcom.Exception
Exception = xpcom.COMException
# Base class for our collections.
# It appears that all objects supports "." and "[]" notation.
@ -80,6 +83,7 @@ class _ComponentCollection:
return self._dict_data[item]
return self._get_one(item)
_constants_by_iid_map = {}
class _Interface:
# An interface object.
@ -88,7 +92,6 @@ class _Interface:
d = self.__dict__
d['_iidobj_'] = iid # Allows the C++ framework to treat this as a native IID.
d['name'] = name
d['constants'] = None # Built first time an attribute is asked for.
def __cmp__(self, other):
this_iid = self._iidobj_
other_iid = getattr(other, "_iidobj_", other)
@ -105,13 +108,13 @@ class _Interface:
raise AttributeError, "Can not set attributes on components.Interface objects"
def __getattr__(self, attr):
# Support constants as attributes.
c = self.constants
c = _constants_by_iid_map.get(self._iidobj_)
if c is None:
c = {}
i = xpt.Interface(self._iidobj_)
for c_ob in i.constants:
c[c_ob.name] = c_ob.value
self.__dict__['constants'] = c
_constants_by_iid_map[self._iidobj_] = c
if c.has_key(attr):
return c[attr]
raise AttributeError, "'%s' interfaces do not define a constant '%s'" % (self.name, attr)
@ -153,7 +156,7 @@ class _Class:
import xpcom.client
return xpcom.client.Component(self.contractid, _get_good_iid(iid))
def getService(self, iid = None):
return _xpcom.GetGlobalServiceManager().getServiceByContractID(self.contractid, _get_good_iid(iid))
return serviceManager.getServiceByContractID(self.contractid, _get_good_iid(iid))
class _Classes(_ComponentCollection):
def __init__(self):
@ -186,11 +189,10 @@ ID = _xpcom.IID
class _ShutdownObserver:
_com_interfaces_ = interfaces.nsIObserver
def observe(self, service, topic, extra):
global manager
global interfaceInfoManager
global _shutdownObserver
manager = interfaceInfoManager = _shutdownObserver = None
global manager, interfaceInfoManager, _shutdownObserver, serviceManager, _constants_by_iid_map
manager = interfaceInfoManager = _shutdownObserver = serviceManager = _constants_by_iid_map = None
xpcom.client._shutdown()
xpcom.server._shutdown()
svc = _xpcom.GetGlobalServiceManager().getServiceByContractID("@mozilla.org/observer-service;1", interfaces.nsIObserverService)
# Observers will be QI'd for a weak-reference, so we must keep the

View File

@ -26,7 +26,10 @@ from xpcom import _xpcom
# of the real xpcom object. Presumably this "trace" object will delegate
# to the real object, but presumably also taking some other action, such
# as calling a profiler or debugger.
tracer = None
# tracer_unwrap is a function used to "unwrap" the tracer object.
# If is expected that tracer_unwrap will be called with an object
# previously returned by "tracer()".
tracer = tracer_unwrap = None
# Wrap an instance in an interface (via a policy)
def WrapObject(ob, iid, policy = None, bWrapClient = 1):
@ -42,7 +45,12 @@ def WrapObject(ob, iid, policy = None, bWrapClient = 1):
# Unwrap a Python object back into the Python object
def UnwrapObject(ob):
return _xpcom.UnwrapObject(ob)._obj_
if ob is None:
return None
ret = _xpcom.UnwrapObject(ob)._obj_
if tracer_unwrap is not None:
ret = tracer_unwrap(ret)
return ret
# Create the main module for the Python loader.
# This is a once only init process, and the returned object
@ -54,3 +62,7 @@ def NS_GetModule( serviceManager, nsIFile ):
import loader
iid = _xpcom.IID_nsIModule
return WrapObject(loader.MakePythonComponentLoaderModule(serviceManager, nsIFile), iid, bWrapClient = 0)
def _shutdown():
from policy import _shutdown
_shutdown()

View File

@ -68,15 +68,16 @@ def _GetNominatedInterfaces(obj):
## We cache class infos by class
class_info_cache = {}
def GetClassInfoForClass(klass):
# Note we do not store the wrapped object in the class - this would
# present us with shutdown problems (ie, needing to clear the
# cache), and also messes with lifetime issues.
def GetClassInfoForObject(ob):
if xpcom.server.tracer_unwrap is not None:
ob = xpcom.server.tracer_unwrap(ob)
klass = ob.__class__
ci = class_info_cache.get(klass)
if ci is None:
ci = DefaultClassInfo(klass)
ci = xpcom.server.WrapObject(ci, _xpcom.IID_nsIClassInfo, bWrapClient = 0)
class_info_cache[klass] = ci
return xpcom.server.WrapObject(ci, _xpcom.IID_nsIClassInfo, bWrapClient = 0)
return ci
class DefaultClassInfo:
_com_interfaces_ = _xpcom.IID_nsIClassInfo
@ -88,7 +89,12 @@ class DefaultClassInfo:
self.implementationLanguage = 3 # Python - avoid lookups just for this
self.flags = 0 # what to do here??
self.interfaces = None
def get_classID(self):
if self.classID is None:
raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED, "Class '%r' has no class ID" % (self.klass,))
return self.classID
def getInterfaces(self):
if self.interfaces is None:
self.interfaces = _GetNominatedInterfaces(self.klass)
@ -133,7 +139,7 @@ class DefaultPolicy:
# Always support nsIClassInfo
if iid == _xpcom.IID_nsIClassInfo:
return GetClassInfoForClass(self._obj_.__class__)
return GetClassInfoForObject(self._obj_)
# See if the instance has a QI
# use lower-case "_query_interface_" as win32com does, and it doesnt really matter.
@ -276,3 +282,6 @@ class SupportsPrimitive:
raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED)
def toString(self):
return str(self.get_data())
def _shutdown():
class_info_cache.clear()

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

View File

@ -29,4 +29,10 @@ for arg in sys.argv[1:]:
if arg[0] not in "-/":
tests.append(arg)
tests = tests or test.regrtest.findtests(path, [])
test.regrtest.main(tests, path)
try:
test.regrtest.main(tests, path)
finally:
from xpcom import _xpcom
_xpcom.NS_ShutdownXPCOM() # To get leak stats and otherwise ensure life is good.

View File

@ -17,7 +17,7 @@
#
DEPTH =..\..\..\..\..
MODULE=pyxpcom_test
################################################################################
## exports

View File

@ -19,6 +19,12 @@
from xpcom import components, _xpcom
import xpcom.server, xpcom.client
try:
from sys import gettotalrefcount
except ImportError:
# Not a Debug build - assume no references (can't be leaks then :-)
gettotalrefcount = lambda: 0
num_alive = 0
class koTestSimple:
@ -61,6 +67,30 @@ def test():
if num_alive != 0: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,)
if wr() is not None: raise RuntimeError, "Our weak-reference is not returning None when it should!"
def test_refcount(num_loops=-1):
# Do the test lots of times - can help shake-out ref-count bugs.
if num_loops == -1: num_loops = 10
for i in xrange(num_loops):
test()
if i==0:
# First loop is likely to "leak" as we cache things.
# Leaking after that is a problem.
num_refs = gettotalrefcount()
lost = gettotalrefcount() - num_refs
# Sometimes we get spurious counts off by 1 or 2.
# This can't indicate a real leak, as we have looped
# more than twice!
if abs(lost)>2:
print "*** Lost %d references" % (lost,)
test()
test_refcount()
print "Weak-reference tests appear to have worked!"
if __name__=='__main__':
_xpcom.NS_ShutdownXPCOM()
ni = xpcom._xpcom._GetInterfaceCount()
ng = xpcom._xpcom._GetGatewayCount()
if ni or ng:
print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng)