From 408841b98926c95399caab9afabeb6c598a97eaf Mon Sep 17 00:00:00 2001 From: Ramin Yaghoubzadeh <ryaghoubzadeh@uni-bielefeld.de> Date: Sat, 5 Dec 2015 00:24:34 +0100 Subject: [PATCH] Py: OutputBuffer instances are tracked automatically in the lib They are torn down on program exit (retracting all live IUs) --- ipaacalib/python/src/ipaaca/buffer.py | 45 +++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/ipaacalib/python/src/ipaaca/buffer.py b/ipaacalib/python/src/ipaaca/buffer.py index ab97df6..761e247 100644 --- a/ipaacalib/python/src/ipaaca/buffer.py +++ b/ipaacalib/python/src/ipaaca/buffer.py @@ -37,6 +37,9 @@ import threading import uuid import traceback +import weakref +import atexit + import rsb import ipaaca_pb2 @@ -54,6 +57,27 @@ __all__ = [ LOGGER = ipaaca.misc.get_library_logger() +# set of objects to auto-clean on exit, assumes _teardown() method +TEARDOWN_OBJECTS = set() + +def atexit_cleanup_function(): + '''Function to call at program exit to auto-clean objects.''' + global TEARDOWN_OBJECTS + for obj_r in TEARDOWN_OBJECTS: + obj = obj_r() + if obj is not None: # if weakref still valid + obj._teardown() +atexit.register(atexit_cleanup_function) + +def auto_teardown_instances(fn): + '''Decorator function for object constructors, to add + new instances to the object set to auto-clean at exit.''' + def auto_teardown_instances_wrapper(instance, *args, **kwargs): + global TEARDOWN_OBJECTS + fn(instance, *args, **kwargs) + TEARDOWN_OBJECTS.add(weakref.ref(instance)) + return auto_teardown_instances_wrapper + class IUStore(dict): """A dictionary storing IUs.""" def __init__(self): @@ -207,7 +231,7 @@ class InputBuffer(Buffer): self._add_category_listener(str(self._uuid)) if category_interests is not None: self.add_category_interests(category_interests) - + def _get_remote_server(self, iu): '''Return (or create, store and return) a remote server.''' _owner = None @@ -364,6 +388,7 @@ class OutputBuffer(Buffer): """An OutputBuffer that holds local IUs.""" + @auto_teardown_instances def __init__(self, owning_component_name, channel=None, participant_config=None): '''Create an OutputBuffer. @@ -382,6 +407,16 @@ class OutputBuffer(Buffer): self._id_prefix = str(owning_component_name)+'-'+str(self._uuid)+'-IU-' self.__iu_id_counter_lock = threading.Lock() + def _teardown(self): + '''OutputBuffer retracts remaining live IUs on teardown''' + self._retract_all_internal() + def __del__(self): + '''Perform teardown (IU retractions) as soon as Buffer is lost. + Note that at program exit the teardown might be called + twice for live objects (atexit, then del), but the + _retract_all_internal method prevents double retractions.''' + self._retract_all_internal() + def _remote_update_links(self, update): '''Apply a remotely requested update to one of the stored IU's links.''' if update.uid not in self._iu_store: @@ -508,12 +543,18 @@ class OutputBuffer(Buffer): def _retract_iu(self, iu): '''Retract an IU.''' + iu._retracted = True iu_retraction = ipaaca_pb2.IURetraction() iu_retraction.uid = iu.uid iu_retraction.revision = iu.revision informer = self._get_informer(iu._category) informer.publishData(iu_retraction) - iu._retracted = True + + def _retract_all_internal(self): + '''Retract all IUs without removal (for Buffer teardown).''' + for iu in self._iu_store.values(): + if not iu._retracted: + self._retract_iu(iu) def _send_iu_commission(self, iu, writer_name): '''Send IU commission. -- GitLab