def __init__(self, **kwargs): kwargs['ParentEmissionThread'] = None self.IsParentEmissionThread = kwargs.get('IsParentEmissionThread', False) thread_id = setID(kwargs.get('thread_id')) if thread_id in _THREADS: newid = '__'.join([thread_id, setID(None)]) self.LOG.warning('thread_id %s already exists using %s' % (thread_id, newid)) thread_id = newid _THREADS[thread_id] = self self.AllowedEmissionThreads = set() self.AllowedEmissionThreads |= set(kwargs.get('AllowedEmissionThreads', [])) self.AllowedEmissionThreads.add(thread_id) threading.Thread.__init__(self, name=thread_id) OSCBaseObject.__init__(self, **kwargs) self._thread_id = thread_id self._insertion_lock = Lock() self.Events = {} timed_events = [] for cls in iterbases(self, 'OSCBaseObject'): if not hasattr(cls, '_Events'): continue for key in cls._Events.iterkeys(): e = self.Properties[key] self.Events[key] = e if e.wait_timeout is not None: timed_events.append(e.name) self._threaded_calls_idle = True timed_events.reverse() self.timed_events = timed_events self._threaded_calls_queue = collections.deque() self._timed_calls_queue = TimeQueue() self.disable_threaded_call_waits = kwargs.get('disable_threaded_call_waits', False)
def __init__(self, **kwargs): kwargs['ParentEmissionThread'] = None self.IsParentEmissionThread = kwargs.get('IsParentEmissionThread', False) thread_id = setID(kwargs.get('thread_id')) if thread_id in _THREADS: newid = '__'.join([thread_id, setID(None)]) self.LOG.warning('thread_id %s already exists using %s' % (thread_id, newid)) thread_id = newid _THREADS[thread_id] = self self.AllowedEmissionThreads = set() self.AllowedEmissionThreads |= set( kwargs.get('AllowedEmissionThreads', [])) self.AllowedEmissionThreads.add(thread_id) threading.Thread.__init__(self, name=thread_id) OSCBaseObject.__init__(self, **kwargs) self._thread_id = thread_id self._insertion_lock = Lock() self.Events = {} timed_events = [] for cls in iterbases(self, 'OSCBaseObject'): if not hasattr(cls, '_Events'): continue for key in cls._Events.iterkeys(): e = self.Properties[key] self.Events[key] = e if e.wait_timeout is not None: timed_events.append(e.name) self._threaded_calls_idle = True timed_events.reverse() self.timed_events = timed_events self._threaded_calls_queue = collections.deque() self._timed_calls_queue = TimeQueue() self.disable_threaded_call_waits = kwargs.get( 'disable_threaded_call_waits', False)
class BaseThread(OSCBaseObject, threading.Thread): _Events = {'_running':{}, '_stopped':{}, '_threaded_call_ready':dict(wait_timeout=.1), '_threaded_calls_idle':{}} _Properties = {'_thread_id':dict(default='')} def __new__(*args, **kwargs): events_by_cls = {} props_by_cls = {} cls = args[0] if cls != BaseThread: while issubclass(cls, BaseThread): d = {} p = {} events = cls.__dict__.get('_Events') if events is None: cls = cls.__bases__[0] continue props = cls.__dict__.get('_Properties', {}) for key, val in events.iteritems(): e_kwargs = val.copy() e_kwargs.setdefault('default', False) additional_kwargs = e_kwargs.get('additional_property_kwargs', {}) additional_kwargs['wait_timeout'] = e_kwargs.get('wait_timeout') e_kwargs['additional_property_kwargs'] = additional_kwargs e_kwargs['ObjPropertyClass'] = Event props[key] = e_kwargs setattr(cls, '_Properties', props) cls = cls.__bases__[0] return OSCBaseObject.__new__(*args, **kwargs) def __init__(self, **kwargs): kwargs['ParentEmissionThread'] = None self.IsParentEmissionThread = kwargs.get('IsParentEmissionThread', False) thread_id = setID(kwargs.get('thread_id')) if thread_id in _THREADS: newid = '__'.join([thread_id, setID(None)]) self.LOG.warning('thread_id %s already exists using %s' % (thread_id, newid)) thread_id = newid _THREADS[thread_id] = self self.AllowedEmissionThreads = set() self.AllowedEmissionThreads |= set(kwargs.get('AllowedEmissionThreads', [])) self.AllowedEmissionThreads.add(thread_id) threading.Thread.__init__(self, name=thread_id) OSCBaseObject.__init__(self, **kwargs) self._thread_id = thread_id self._insertion_lock = Lock() self.Events = {} timed_events = [] for cls in iterbases(self, 'OSCBaseObject'): if not hasattr(cls, '_Events'): continue for key in cls._Events.iterkeys(): e = self.Properties[key] self.Events[key] = e if e.wait_timeout is not None: timed_events.append(e.name) self._threaded_calls_idle = True timed_events.reverse() self.timed_events = timed_events self._threaded_calls_queue = collections.deque() self._timed_calls_queue = TimeQueue() self.disable_threaded_call_waits = kwargs.get('disable_threaded_call_waits', False) @property def pethread_log(self): return pethread_logger @property def can_currentthread_emit(self): name = threading.currentThread().name val = name in self.AllowedEmissionThreads #print 'Thread %s can emit=%s currentthread=%s' % (self.name, val, name) return val def get_now_for_timed_calls(self): return time.time() def insert_threaded_call(self, call, *args, **kwargs): p = None if self.can_currentthread_emit: call(*args, **kwargs) return with self._insertion_lock: if self.IsParentEmissionThread: self.pethread_log('insert call', call, ' to PEThread %s' % (self.name)) kwargs = kwargs.copy() kwargs['__PartialObjOwnerThread__'] = self p = WeakPartial(call, self._on_WeakPartial_dead, *args, **kwargs) if p.call_time is not None: self._timed_calls_queue.put(p.call_time, p) else: self._threaded_calls_queue.append(p) self._threaded_calls_idle = False self._cancel_event_timeouts() return p def _on_WeakPartial_dead(self, p): callqueue = self._threaded_calls_queue timequeue = self._timed_calls_queue print '%s WeakPartial %s dead' % (self._thread_id, p) with self._insertion_lock: if p in callqueue: callqueue.remove(p) print '%s removed %s from callqueue' % (self._thread_id, p) if p.call_time is not None and p.call_time in timequeue.times: r = timequeue.remove(time=p.call_time, item=p) print '%s removed %s from timequeue, result=%s' % (self._thread_id, p, r) def _cancel_event_timeouts(self, events=None): if events is None: events = self.timed_events for key in events: e = self.Events.get(key) if not e: continue e.set() def run(self): disable_call_waits = self.disable_threaded_call_waits do_threaded_calls = self._do_threaded_calls do_timed_calls = self._do_timed_calls loop_iteration = self._thread_loop_iteration self._running = True while self._running: if True:#self._running: loop_iteration() if not disable_call_waits: self._threaded_call_ready.wait() do_threaded_calls() do_timed_calls() self._stopped = True def stop(self, **kwargs): blocking = kwargs.get('blocking', False) wait_for_queues = kwargs.get('wait_for_queues', True) self._running = False if self._thread_id in _THREADS: del _THREADS[self._thread_id] if wait_for_queues: if not len(self._threaded_calls_queue): self._threaded_call_ready = True self._cancel_event_timeouts() else: self._threaded_calls_queue.clear() self._threaded_call_ready = True if not self.isAlive(): self._stopped = True if blocking and threading.currentThread() != self: if type(blocking) in [float, int]: timeout = float(blocking) else: timeout = None self._stopped.wait(timeout) def _thread_loop_iteration(self): pass def _do_threaded_calls(self): queue = self._threaded_calls_queue with self._insertion_lock: if not len(queue): if self._running: if not len(self._timed_calls_queue): self._threaded_call_ready = False self._threaded_calls_idle = True return p = queue.popleft() if p.is_dead: print 'PARTIAL %s already dead' % (p) if self.IsParentEmissionThread: self.pethread_log('do_call: ', repr(p)) try: #result = p() result = self._really_do_call(p) return (result, p.cb, p.args, p.kwargs) except: self.LOG.warning(traceback.format_exc()) def _do_timed_calls(self): queue = self._timed_calls_queue with self._insertion_lock: lowest_time = queue.lowest_time() now = self.get_now_for_timed_calls() if lowest_time is None or now < lowest_time: if self._running: if not len(self._threaded_calls_queue): self._threaded_call_ready = False self._threaded_calls_idle = True return p = queue.pop(lowest_time) if self.IsParentEmissionThread: self.pethread_log('do_timed_call, now=%s: %r' % (now, p)) try: result = self._really_do_call(p) return (result, p.cb, p.args, p.kwargs) except: self.LOG.warning(traceback.format_exc()) def _really_do_call(self, p): return p()
class BaseThread(OSCBaseObject, threading.Thread): _Events = { '_running': {}, '_stopped': {}, '_threaded_call_ready': dict(wait_timeout=.1), '_threaded_calls_idle': {} } _Properties = {'_thread_id': dict(default='')} def __new__(*args, **kwargs): events_by_cls = {} props_by_cls = {} cls = args[0] if cls != BaseThread: while issubclass(cls, BaseThread): d = {} p = {} events = cls.__dict__.get('_Events') if events is None: cls = cls.__bases__[0] continue props = cls.__dict__.get('_Properties', {}) for key, val in events.iteritems(): e_kwargs = val.copy() e_kwargs.setdefault('default', False) additional_kwargs = e_kwargs.get( 'additional_property_kwargs', {}) additional_kwargs['wait_timeout'] = e_kwargs.get( 'wait_timeout') e_kwargs['additional_property_kwargs'] = additional_kwargs e_kwargs['ObjPropertyClass'] = Event props[key] = e_kwargs setattr(cls, '_Properties', props) cls = cls.__bases__[0] return OSCBaseObject.__new__(*args, **kwargs) def __init__(self, **kwargs): kwargs['ParentEmissionThread'] = None self.IsParentEmissionThread = kwargs.get('IsParentEmissionThread', False) thread_id = setID(kwargs.get('thread_id')) if thread_id in _THREADS: newid = '__'.join([thread_id, setID(None)]) self.LOG.warning('thread_id %s already exists using %s' % (thread_id, newid)) thread_id = newid _THREADS[thread_id] = self self.AllowedEmissionThreads = set() self.AllowedEmissionThreads |= set( kwargs.get('AllowedEmissionThreads', [])) self.AllowedEmissionThreads.add(thread_id) threading.Thread.__init__(self, name=thread_id) OSCBaseObject.__init__(self, **kwargs) self._thread_id = thread_id self._insertion_lock = Lock() self.Events = {} timed_events = [] for cls in iterbases(self, 'OSCBaseObject'): if not hasattr(cls, '_Events'): continue for key in cls._Events.iterkeys(): e = self.Properties[key] self.Events[key] = e if e.wait_timeout is not None: timed_events.append(e.name) self._threaded_calls_idle = True timed_events.reverse() self.timed_events = timed_events self._threaded_calls_queue = collections.deque() self._timed_calls_queue = TimeQueue() self.disable_threaded_call_waits = kwargs.get( 'disable_threaded_call_waits', False) @property def pethread_log(self): return pethread_logger @property def can_currentthread_emit(self): name = threading.currentThread().name val = name in self.AllowedEmissionThreads #print 'Thread %s can emit=%s currentthread=%s' % (self.name, val, name) return val def get_now_for_timed_calls(self): return time.time() def insert_threaded_call(self, call, *args, **kwargs): p = None if self.can_currentthread_emit: call(*args, **kwargs) return with self._insertion_lock: if self.IsParentEmissionThread: self.pethread_log('insert call', call, ' to PEThread %s' % (self.name)) kwargs = kwargs.copy() kwargs['__PartialObjOwnerThread__'] = self p = WeakPartial(call, self._on_WeakPartial_dead, *args, **kwargs) if p.call_time is not None: self._timed_calls_queue.put(p.call_time, p) else: self._threaded_calls_queue.append(p) self._threaded_calls_idle = False self._cancel_event_timeouts() return p def _on_WeakPartial_dead(self, p): callqueue = self._threaded_calls_queue timequeue = self._timed_calls_queue print '%s WeakPartial %s dead' % (self._thread_id, p) with self._insertion_lock: if p in callqueue: callqueue.remove(p) print '%s removed %s from callqueue' % (self._thread_id, p) if p.call_time is not None and p.call_time in timequeue.times: r = timequeue.remove(time=p.call_time, item=p) print '%s removed %s from timequeue, result=%s' % ( self._thread_id, p, r) def _cancel_event_timeouts(self, events=None): if events is None: events = self.timed_events for key in events: e = self.Events.get(key) if not e: continue e.set() def run(self): disable_call_waits = self.disable_threaded_call_waits do_threaded_calls = self._do_threaded_calls do_timed_calls = self._do_timed_calls loop_iteration = self._thread_loop_iteration self._running = True while self._running: if True: #self._running: loop_iteration() if not disable_call_waits: self._threaded_call_ready.wait() do_threaded_calls() do_timed_calls() self._stopped = True def stop(self, **kwargs): blocking = kwargs.get('blocking', False) wait_for_queues = kwargs.get('wait_for_queues', True) self._running = False if self._thread_id in _THREADS: del _THREADS[self._thread_id] if wait_for_queues: if not len(self._threaded_calls_queue): self._threaded_call_ready = True self._cancel_event_timeouts() else: self._threaded_calls_queue.clear() self._threaded_call_ready = True if not self.isAlive(): self._stopped = True if blocking and threading.currentThread() != self: if type(blocking) in [float, int]: timeout = float(blocking) else: timeout = None self._stopped.wait(timeout) def _thread_loop_iteration(self): pass def _do_threaded_calls(self): queue = self._threaded_calls_queue with self._insertion_lock: if not len(queue): if self._running: if not len(self._timed_calls_queue): self._threaded_call_ready = False self._threaded_calls_idle = True return p = queue.popleft() if p.is_dead: print 'PARTIAL %s already dead' % (p) if self.IsParentEmissionThread: self.pethread_log('do_call: ', repr(p)) try: #result = p() result = self._really_do_call(p) return (result, p.cb, p.args, p.kwargs) except: self.LOG.warning(traceback.format_exc()) def _do_timed_calls(self): queue = self._timed_calls_queue with self._insertion_lock: lowest_time = queue.lowest_time() now = self.get_now_for_timed_calls() if lowest_time is None or now < lowest_time: if self._running: if not len(self._threaded_calls_queue): self._threaded_call_ready = False self._threaded_calls_idle = True return p = queue.pop(lowest_time) if self.IsParentEmissionThread: self.pethread_log('do_timed_call, now=%s: %r' % (now, p)) try: result = self._really_do_call(p) return (result, p.cb, p.args, p.kwargs) except: self.LOG.warning(traceback.format_exc()) def _really_do_call(self, p): return p()