Add python-eventlet 0.16.1
[packages/trusty/python-eventlet.git] / eventlet / eventlet / hubs / pyevent.py
diff --git a/eventlet/eventlet/hubs/pyevent.py b/eventlet/eventlet/hubs/pyevent.py
new file mode 100644 (file)
index 0000000..a46c571
--- /dev/null
@@ -0,0 +1,178 @@
+import sys
+import traceback
+import event
+import types
+
+from eventlet.support import greenlets as greenlet, six
+from eventlet.hubs.hub import BaseHub, READ, WRITE
+
+
+class event_wrapper(object):
+
+    def __init__(self, impl=None, seconds=None):
+        self.impl = impl
+        self.seconds = seconds
+
+    def __repr__(self):
+        if self.impl is not None:
+            return repr(self.impl)
+        else:
+            return object.__repr__(self)
+
+    def __str__(self):
+        if self.impl is not None:
+            return str(self.impl)
+        else:
+            return object.__str__(self)
+
+    def cancel(self):
+        if self.impl is not None:
+            self.impl.delete()
+            self.impl = None
+
+    @property
+    def pending(self):
+        return bool(self.impl and self.impl.pending())
+
+
+class Hub(BaseHub):
+
+    SYSTEM_EXCEPTIONS = (KeyboardInterrupt, SystemExit)
+
+    def __init__(self):
+        super(Hub, self).__init__()
+        event.init()
+
+        self.signal_exc_info = None
+        self.signal(
+            2,
+            lambda signalnum, frame: self.greenlet.parent.throw(KeyboardInterrupt))
+        self.events_to_add = []
+
+    def dispatch(self):
+        loop = event.loop
+        while True:
+            for e in self.events_to_add:
+                if e is not None and e.impl is not None and e.seconds is not None:
+                    e.impl.add(e.seconds)
+                    e.seconds = None
+            self.events_to_add = []
+            result = loop()
+
+            if getattr(event, '__event_exc', None) is not None:
+                # only have to do this because of bug in event.loop
+                t = getattr(event, '__event_exc')
+                setattr(event, '__event_exc', None)
+                assert getattr(event, '__event_exc') is None
+                six.reraise(t[0], t[1], t[2])
+
+            if result != 0:
+                return result
+
+    def run(self):
+        while True:
+            try:
+                self.dispatch()
+            except greenlet.GreenletExit:
+                break
+            except self.SYSTEM_EXCEPTIONS:
+                raise
+            except:
+                if self.signal_exc_info is not None:
+                    self.schedule_call_global(
+                        0, greenlet.getcurrent().parent.throw, *self.signal_exc_info)
+                    self.signal_exc_info = None
+                else:
+                    self.squelch_timer_exception(None, sys.exc_info())
+
+    def abort(self, wait=True):
+        self.schedule_call_global(0, self.greenlet.throw, greenlet.GreenletExit)
+        if wait:
+            assert self.greenlet is not greenlet.getcurrent(
+            ), "Can't abort with wait from inside the hub's greenlet."
+            self.switch()
+
+    def _getrunning(self):
+        return bool(self.greenlet)
+
+    def _setrunning(self, value):
+        pass  # exists for compatibility with BaseHub
+    running = property(_getrunning, _setrunning)
+
+    def add(self, evtype, fileno, real_cb, real_tb, mac):
+        # this is stupid: pyevent won't call a callback unless it's a function,
+        # so we have to force it to be one here
+        if isinstance(real_cb, types.BuiltinMethodType):
+            def cb(_d):
+                real_cb(_d)
+        else:
+            cb = real_cb
+
+        if evtype is READ:
+            evt = event.read(fileno, cb, fileno)
+        elif evtype is WRITE:
+            evt = event.write(fileno, cb, fileno)
+
+        return super(Hub, self).add(evtype, fileno, evt, real_tb, mac)
+
+    def signal(self, signalnum, handler):
+        def wrapper():
+            try:
+                handler(signalnum, None)
+            except:
+                self.signal_exc_info = sys.exc_info()
+                event.abort()
+        return event_wrapper(event.signal(signalnum, wrapper))
+
+    def remove(self, listener):
+        super(Hub, self).remove(listener)
+        listener.cb.delete()
+
+    def remove_descriptor(self, fileno):
+        for lcontainer in six.itervalues(self.listeners):
+            listener = lcontainer.pop(fileno, None)
+            if listener:
+                try:
+                    listener.cb.delete()
+                except self.SYSTEM_EXCEPTIONS:
+                    raise
+                except:
+                    traceback.print_exc()
+
+    def schedule_call_local(self, seconds, cb, *args, **kwargs):
+        current = greenlet.getcurrent()
+        if current is self.greenlet:
+            return self.schedule_call_global(seconds, cb, *args, **kwargs)
+        event_impl = event.event(_scheduled_call_local, (cb, args, kwargs, current))
+        wrapper = event_wrapper(event_impl, seconds=seconds)
+        self.events_to_add.append(wrapper)
+        return wrapper
+
+    schedule_call = schedule_call_local
+
+    def schedule_call_global(self, seconds, cb, *args, **kwargs):
+        event_impl = event.event(_scheduled_call, (cb, args, kwargs))
+        wrapper = event_wrapper(event_impl, seconds=seconds)
+        self.events_to_add.append(wrapper)
+        return wrapper
+
+    def _version_info(self):
+        baseversion = event.__version__
+        return baseversion
+
+
+def _scheduled_call(event_impl, handle, evtype, arg):
+    cb, args, kwargs = arg
+    try:
+        cb(*args, **kwargs)
+    finally:
+        event_impl.delete()
+
+
+def _scheduled_call_local(event_impl, handle, evtype, arg):
+    cb, args, kwargs, caller_greenlet = arg
+    try:
+        if not caller_greenlet.dead:
+            cb(*args, **kwargs)
+    finally:
+        event_impl.delete()