mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 18:31:55 -04:00
added 'safe' mode to GarbageReport for dealing with C++ crashes in __repr__
This commit is contained in:
parent
7f31a5fb83
commit
8127bcb6b3
@ -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>'
|
||||
|
@ -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):
|
||||
|
Loading…
x
Reference in New Issue
Block a user