mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
* 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:
parent
e36a625871
commit
88e93b42ba
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#
|
||||
|
||||
DEPTH =..\..\..\..\..
|
||||
MODULE=pyxpcom_test
|
||||
|
||||
|
||||
################################################################################
|
||||
## exports
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user