added 'safe' mode to GarbageReport for dealing with C++ crashes in __repr__

This commit is contained in:
Darren Ranalli 2007-11-13 21:23:28 +00:00
parent 7f31a5fb83
commit 8127bcb6b3
2 changed files with 49 additions and 14 deletions

View File

@ -3,7 +3,7 @@
__all__ = ['FakeObject', '_createGarbage', 'GarbageReport', 'GarbageLogger']
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.showbase.PythonUtil import gcDebugOn, safeRepr, fastRepr
from direct.showbase.PythonUtil import gcDebugOn, safeRepr, fastRepr, printListEnumGen, printNumberedTypesGen
from direct.showbase.Job import Job
import gc
@ -26,7 +26,8 @@ class GarbageReport(Job):
NotGarbage = 'NG'
def __init__(self, name, log=True, verbose=False, fullReport=False, findCycles=True,
threaded=False, doneCallback=None, autoDestroy=False, priority=None):
threaded=False, doneCallback=None, autoDestroy=False, priority=None,
safeMode=False):
# if autoDestroy is True, GarbageReport will self-destroy after logging
# if false, caller is responsible for calling destroy()
# if threaded is True, processing will be performed over multiple frames
@ -34,7 +35,7 @@ class GarbageReport(Job):
# stick the arguments onto a ScratchPad so we can delete them all at once
self._args = ScratchPad(name=name, log=log, verbose=verbose, fullReport=fullReport,
findCycles=findCycles, doneCallback=doneCallback,
autoDestroy=autoDestroy)
autoDestroy=autoDestroy, safeMode=safeMode)
if priority is not None:
self.setPriority(priority)
jobMgr.add(self)
@ -48,25 +49,34 @@ class GarbageReport(Job):
if not wasOn:
gc.set_debug(gc.DEBUG_SAVEALL)
gc.collect()
yield None
# don't repr the garbage list if we don't have to
if self.notify.getDebug():
self.notify.debug('gc.garbage == %s' % fastRepr(gc.garbage))
yield None
self.garbage = list(gc.garbage)
# only yield if there's more time-consuming work to do,
# if there's no garbage, give instant feedback
if len(self.garbage) > 0:
yield None
# don't repr the garbage list if we don't have to
if self.notify.getDebug():
self.notify.debug('self.garbage == %s' % self.garbage)
self.notify.debug('self.garbage == %s' % safeRepr(self.garbage))
del gc.garbage[:]
if not wasOn:
gc.set_debug(oldFlags)
self.numGarbage = len(self.garbage)
yield None
# only yield if there's more time-consuming work to do,
# if there's no garbage, give instant feedback
if self.numGarbage > 0:
yield None
if self._args.verbose:
self.notify.info('found %s garbage items' % self.numGarbage)
# print the types of the garbage first, in case the repr of an object
# causes a crash
if self.numGarbage > 0:
self.notify.info('TYPES ONLY (this is only needed if a crash occurs before GarbageReport finishes):')
for result in printNumberedTypesGen(self.garbage):
yield None
self.referrersByReference = {}
self.referrersByNumber = {}
@ -149,7 +159,11 @@ class GarbageReport(Job):
for i in xrange(numGarbage):
yield None
id = garbageIds[i]
objStr = safeRepr(self.garbage[id])
if self._args.safeMode:
# in safe mode, don't try to repr any of the objects
objStr = repr(itype(self.garbage[id]))
else:
objStr = safeRepr(self.garbage[id])
maxLen = 5000
if len(objStr) > maxLen:
snip = '<SNIP>'

View File

@ -2159,7 +2159,7 @@ class Singleton(type):
class SingletonError(ValueError):
""" Used to indicate an inappropriate value for a Singleton."""
def printListEnum(l):
def printListEnumGen(l):
# log each individual item with a number in front of it
digits = 0
n = len(l)
@ -2169,6 +2169,11 @@ def printListEnum(l):
format = '%0' + '%s' % digits + 'i:%s'
for i in range(len(l)):
print format % (i, l[i])
yield None
def printListEnum(l):
for result in printListEnumGen(l):
pass
def gcDebugOn():
import gc
@ -2463,15 +2468,31 @@ def printNumberedTyped(items, maxLen=5000):
n /= 10
digits = digits
format = '%0' + '%s' % digits + 'i:%s \t%s'
first = True
for i in xrange(len(items)):
first = False
objStr = fastRepr(items[i])
if len(objStr) > maxLen:
snip = '<SNIP>'
objStr = '%s%s' % (objStr[:(maxLen-len(snip))], snip)
print format % (i, itype(items[i]), objStr)
def printNumberedTypesGen(items, maxLen=5000):
digits = 0
n = len(items)
while n > 0:
digits += 1
n /= 10
digits = digits
format = '%0' + '%s' % digits + 'i:%s'
for i in xrange(len(items)):
print format % (i, itype(items[i]))
yield None
def printNumberedTypes(items, maxLen=5000):
"""print out the type of each item of the list on its own line,
with each item numbered on the left from zero"""
for result in printNumberedTypesGen(items, maxLen):
yield result
class DelayedCall:
""" calls a func after a specified delay """
def __init__(self, func, name=None, delay=None):