Пример #1
0
def send_exception(g, exc):
    # note: send_exception(g, exc)  can be now done with  g.throw(exc).
    # the purpose of this test is to explicitely check the propagation rules.
    def crasher(exc):
        raise exc
    g1 = Fiber(target=crasher, args=(exc, ), parent=g)
    g1.switch()
Пример #2
0
 def test_finished_parent(self):
     def f():
         return 42
     g = Fiber(f)
     g.switch()
     self.assertFalse(g.is_alive())
     self.assertRaises(ValueError, Fiber, parent=g)
Пример #3
0
def send_exception(g, exc):
    # note: send_exception(g, exc)  can be now done with  g.throw(exc).
    # the purpose of this test is to explicitely check the propagation rules.
    def crasher(exc):
        raise exc

    g1 = Fiber(target=crasher, args=(exc, ), parent=g)
    g1.switch()
Пример #4
0
    def test_finished_parent(self):
        def f():
            return 42

        g = Fiber(f)
        g.switch()
        self.assertFalse(g.is_alive())
        self.assertRaises(ValueError, Fiber, parent=g)
Пример #5
0
 def f():
     try:
         raise ValueError('fun')
     except:
         exc_info = sys.exc_info()
         t = Fiber(h)
         t.switch()
         self.assertEqual(exc_info, sys.exc_info())
         del t
Пример #6
0
 def test_kwarg_refs(self):
     kwargs = {'a': 1234}
     refcount_before = sys.getrefcount(kwargs)
     g = Fiber(lambda **x: None, kwargs=kwargs)
     self.assertEqual(sys.getrefcount(kwargs), refcount_before+1)
     g.switch()
     self.assertEqual(sys.getrefcount(kwargs), refcount_before)
     del g
     self.assertEqual(sys.getrefcount(kwargs), refcount_before)
Пример #7
0
 def test_arg_refs(self):
     args = ('a', 'b', 'c')
     refcount_before = sys.getrefcount(args)
     g = Fiber(target=lambda *x: None, args=args)
     self.assertEqual(sys.getrefcount(args), refcount_before+1)
     g.switch()
     self.assertEqual(sys.getrefcount(args), refcount_before)
     del g
     self.assertEqual(sys.getrefcount(args), refcount_before)
Пример #8
0
 def f():
     try:
         raise ValueError('fun')
     except:
         exc_info = sys.exc_info()
         t = Fiber(h)
         t.switch()
         self.assertEqual(exc_info, sys.exc_info())
         del t
Пример #9
0
 def test_kwarg_refs(self):
     if not has_refcount:
         return
     kwargs = {'a': 1234}
     refcount_before = sys.getrefcount(kwargs)
     g = Fiber(lambda **x: None, kwargs=kwargs)
     self.assertEqual(sys.getrefcount(kwargs), refcount_before + 1)
     g.switch()
     self.assertEqual(sys.getrefcount(kwargs), refcount_before)
     del g
     self.assertEqual(sys.getrefcount(kwargs), refcount_before)
Пример #10
0
 def test_arg_refs(self):
     if not has_refcount:
         return
     args = ('a', 'b', 'c')
     refcount_before = sys.getrefcount(args)
     g = Fiber(target=lambda *x: None, args=args)
     self.assertEqual(sys.getrefcount(args), refcount_before + 1)
     g.switch()
     self.assertEqual(sys.getrefcount(args), refcount_before)
     del g
     self.assertEqual(sys.getrefcount(args), refcount_before)
Пример #11
0
 def test_class(self):
     def f():
         try:
             switch("ok")
         except RuntimeError:
             switch("ok")
             return
         switch("fail")
     g = Fiber(f)
     res = g.switch()
     self.assertEqual(res, "ok")
     res = g.throw(RuntimeError)
     self.assertEqual(res, "ok")
Пример #12
0
 def test_kill(self):
     def f():
         try:
             switch("ok")
             switch("fail")
         except Exception as e:
             return e
     g = Fiber(f)
     res = g.switch()
     self.assertEqual(res, "ok")
     res = g.throw(ValueError)
     self.assertTrue(isinstance(res, ValueError))
     self.assertFalse(g.is_alive())
Пример #13
0
 def test_exception(self):
     seen = []
     g1 = Fiber(target=fmain, args=(seen, ))
     g2 = Fiber(target=fmain, args=(seen, ))
     g1.switch()
     g2.switch()
     g2.parent = g1
     self.assertEqual(seen, [])
     self.assertRaises(SomeError, g2.switch)
     self.assertEqual(seen, [SomeError])
Пример #14
0
    def test_class(self):
        def f():
            try:
                switch("ok")
            except RuntimeError:
                switch("ok")
                return
            switch("fail")

        g = Fiber(f)
        res = g.switch()
        self.assertEqual(res, "ok")
        res = g.throw(RuntimeError)
        self.assertEqual(res, "ok")
Пример #15
0
    def test_kill(self):
        def f():
            try:
                switch("ok")
                switch("fail")
            except Exception as e:
                return e

        g = Fiber(f)
        res = g.switch()
        self.assertEqual(res, "ok")
        res = g.throw(ValueError)
        self.assertTrue(isinstance(res, ValueError))
        self.assertFalse(g.is_alive())
Пример #16
0
    def test_simple2(self):
        lst = []

        def f():
            lst.append(1)
            current().parent.switch()
            lst.append(3)
        g = Fiber(f)
        lst.append(0)
        g.switch()
        lst.append(2)
        g.switch()
        lst.append(4)
        self.assertEqual(lst, list(range(5)))
Пример #17
0
    def test_two_recursive_children(self):
        lst = []

        def f():
            lst.append(1)
            current().parent.switch()

        def h():
            lst.append(1)
            i = Fiber(f)
            i.switch()
            lst.append(1)
        g = Fiber(h)
        g.switch()
        self.assertEqual(len(lst), 3)
Пример #18
0
    def test_two_recursive_children(self):
        lst = []

        def f():
            lst.append(1)
            current().parent.switch()

        def h():
            lst.append(1)
            i = Fiber(f)
            i.switch()
            lst.append(1)
        g = Fiber(h)
        g.switch()
        self.assertEqual(len(lst), 3)
Пример #19
0
    def test_exc_state(self):
        def f():
            try:
                raise ValueError('fun')
            except:
                exc_info = sys.exc_info()
                t = Fiber(h)
                t.switch()
                self.assertEqual(exc_info, sys.exc_info())
                del t

        def h():
            self.assertEqual(sys.exc_info(), (None, None, None))

        g = Fiber(f)
        g.switch()
Пример #20
0
 def test_instance_dict(self):
     def f():
         current().test = 42
     def deldict(g):
         del g.__dict__
     def setdict(g, value):
         g.__dict__ = value
     g = Fiber(f)
     self.assertEqual(g.__dict__, {})
     g.switch()
     self.assertEqual(g.test, 42)
     self.assertEqual(g.__dict__, {'test': 42})
     g.__dict__ = g.__dict__
     self.assertEqual(g.__dict__, {'test': 42})
     self.assertRaises(AttributeError, deldict, g)
     self.assertRaises(TypeError, setdict, g, 42)
Пример #21
0
    def test_exc_state(self):
        def f():
            try:
                raise ValueError('fun')
            except:
                exc_info = sys.exc_info()
                t = Fiber(h)
                t.switch()
                self.assertEqual(exc_info, sys.exc_info())
                del t

        def h():
            self.assertEqual(sys.exc_info(), (None, None, None))

        g = Fiber(f)
        g.switch()
Пример #22
0
 def test_instance_dict(self):
     if is_pypy:
         return
     def f():
         current().test = 42
     def deldict(g):
         del g.__dict__
     def setdict(g, value):
         g.__dict__ = value
     g = Fiber(f)
     self.assertEqual(g.__dict__, {})
     g.switch()
     self.assertEqual(g.test, 42)
     self.assertEqual(g.__dict__, {'test': 42})
     g.__dict__ = g.__dict__
     self.assertEqual(g.__dict__, {'test': 42})
     self.assertRaises(AttributeError, deldict, g)
     self.assertRaises(TypeError, setdict, g, 42)
Пример #23
0
    def await_all_tasks(cls, tasks):
        self = cls.get()
        fb = Fiber.current()

        def _callback(ts):
            self._fibers.append(fb)

        cls.watch_all_tasks(tasks, _callback)
        self._loop_fiber.switch()
Пример #24
0
    def async (cls, func, *args, **kwargs):
        self = cls.get()

        def _f():
            func(*args, **kwargs)
            self._loop_fiber.switch()

        fb = Fiber(target=_f)
        self._fibers.append(fb)
Пример #25
0
    def await_all_ps(cls, ps_set):
        self = cls.get()
        fb = Fiber.current()

        def _callback(pss):
            self._fibers.append(fb)

        cls.watch_all_ps(ps_set, _callback)
        self._loop_fiber.switch()
Пример #26
0
    def test_throw_goes_to_original_parent(self):
        main = fibers.current()

        def f1():
            try:
                main.switch("f1 ready to catch")
            except IndexError:
                return "caught"
            else:
                return "normal exit"

        def f2():
            main.switch("from f2")

        g1 = Fiber(f1)
        g2 = Fiber(target=f2, parent=g1)
        self.assertRaises(IndexError, g2.throw, IndexError)
        self.assertFalse(g2.is_alive())
        self.assertTrue(g1.is_alive())    # g1 is skipped because it was not started
Пример #27
0
        def worker():
            # main and additional *finished* greenlets
            ll = current().ll = []

            def additional():
                ll.append(current())

            for i in range(2):
                Fiber(additional).switch()
            gg.append(weakref.ref(current()))
Пример #28
0
 def switch(self):
     if not self._started:
         self._run(forever=False)
         return
     current = Fiber.current()
     assert current is not self.task, 'Cannot switch to MAIN from MAIN'
     try:
         if self.task.parent is not current:
             current.parent = self.task
     except ValueError:
         pass  # gets raised if there is a Fiber parent cycle
     return self.task.switch()
Пример #29
0
 def switch(self):
     if not self._started:
         self.run()
         return
     current = Fiber.current()
     assert current is not self.task, 'Cannot switch to MAIN from MAIN'
     try:
         if self.task.parent is not current:
             current.parent = self.task
     except ValueError:
         pass  # gets raised if there is a Fiber parent cycle
     return self.task.switch()
Пример #30
0
 def test_exception(self):
     seen = []
     g1 = Fiber(target=fmain, args=(seen, ))
     g2 = Fiber(target=fmain, args=(seen, ))
     g1.switch()
     g2.switch()
     g2.parent = g1
     self.assertEqual(seen, [])
     self.assertRaises(SomeError, g2.switch)
     self.assertEqual(seen, [SomeError])
Пример #31
0
    def test_finalizer_crash(self):
        # This test is designed to crash when active greenlets
        # are made garbage collectable, until the underlying
        # problem is resolved. How does it work:
        # - order of object creation is important
        # - array is created first, so it is moved to unreachable first
        # - we create a cycle between a greenlet and this array
        # - we create an object that participates in gc, is only
        #   referenced by a greenlet, and would corrupt gc lists
        #   on destruction, the easiest is to use an object with
        #   a finalizer
        # - because array is the first object in unreachable it is
        #   cleared first, which causes all references to greenlet
        #   to disappear and causes greenlet to be destroyed, but since
        #   it is still live it causes a switch during gc, which causes
        #   an object with finalizer to be destroyed, which causes stack
        #   corruption and then a crash
        class object_with_finalizer(object):
            def __del__(self):
                pass

        array = []
        parent = current()

        def greenlet_body():
            current().object = object_with_finalizer()
            try:
                parent.switch()
            finally:
                del current().object

        g = Fiber(greenlet_body)
        g.array = array
        array.append(g)
        g.switch()
        del array
        del g
        current()
        gc.collect()
Пример #32
0
    def test_threaded_updatecurrent(self):
        # FIXME (hangs?)
        return
        # released when main thread should execute
        lock1 = threading.Lock()
        lock1.acquire()
        # released when another thread should execute
        lock2 = threading.Lock()
        lock2.acquire()

        class finalized(object):
            def __del__(self):
                # happens while in green_updatecurrent() in main greenlet
                # should be very careful not to accidentally call it again
                # at the same time we must make sure another thread executes
                lock2.release()
                lock1.acquire()
                # now ts_current belongs to another thread
        def deallocator():
            current().parent.switch()

        def fthread():
            lock2.acquire()
            current()
            del g[0]
            lock1.release()
            lock2.acquire()
            current()
            lock1.release()

        main = current()
        g = [Fiber(deallocator)]
        g[0].bomb = finalized()
        g[0].switch()
        t = threading.Thread(target=fthread)
        t.start()
        # let another thread grab ts_current and deallocate g[0]
        lock2.release()
        lock1.acquire()
        # this is the corner stone
        # getcurrent() will notice that ts_current belongs to another thread
        # and start the update process, which would notice that g[0] should
        # be deallocated, and that will execute an object's finalizer. Now,
        # that object will let another thread run so it can grab ts_current
        # again, which would likely crash the interpreter if there's no
        # check for this case at the end of green_updatecurrent(). This test
        # passes if getcurrent() returns correct result, but it's likely
        # to randomly crash if it's not anyway.
        self.assertEqual(current(), main)
        # wait for another thread to complete, just in case
        t.join()
Пример #33
0
 def run(self, mode=RUN_DEFAULT):
     if Fiber.current() is not self.task.parent:
         raise RuntimeError('run() can only be called from MAIN fiber')
     if not self.task.is_alive():
         raise RuntimeError('event loop has already ended')
     if self._started:
         raise RuntimeError('event loop was already started')
     self._started = True
     self._running = True
     self._run_mode = mode
     try:
         self.task.switch()
     finally:
         self._running = False
Пример #34
0
 def run(self, mode=RUN_DEFAULT):
     if Fiber.current() is not self.task.parent:
         raise RuntimeError('run() can only be called from MAIN fiber')
     if not self.task.is_alive():
         raise RuntimeError('event loop has already ended')
     if self._started:
         raise RuntimeError('event loop was already started')
     self._started = True
     self._running = True
     self._run_mode = mode
     try:
         self.task.switch()
     finally:
         self._running = False
Пример #35
0
def sleep(seconds=0):
    """Yield control to another eligible coroutine until at least *seconds* have
    elapsed.

    *seconds* may be specified as an integer, or a float if fractional seconds
    are desired.
    """
    loop = evergreen.current.loop
    current = Fiber.current()
    assert loop.task is not current
    timer = loop.call_later(seconds, current.switch)
    try:
        loop.switch()
    finally:
        timer.cancel()
Пример #36
0
def sleep(seconds=0):
    """Yield control to another eligible coroutine until at least *seconds* have
    elapsed.

    *seconds* may be specified as an integer, or a float if fractional seconds
    are desired.
    """
    loop = evergreen.current.loop
    current = Fiber.current()
    assert loop.task is not current
    timer = loop.call_later(seconds, current.switch)
    try:
        loop.switch()
    finally:
        timer.cancel()
Пример #37
0
    def test_threaded_reparent(self):
        data = {}
        created_event = threading.Event()
        done_event = threading.Event()

        def foo():
            data['g'] = Fiber(lambda: None)
            created_event.set()
            done_event.wait()

        def blank():
            current().parent.switch()

        def setparent(g, value):
            g.parent = value

        thread = threading.Thread(target=foo)
        thread.start()
        created_event.wait()
        g = Fiber(blank)
        g.switch()
        self.assertRaises(ValueError, setparent, g, data['g'])
        done_event.set()
        thread.join()
Пример #38
0
    def test_threaded_reparent(self):
        data = {}
        created_event = threading.Event()
        done_event = threading.Event()

        def foo():
            data['g'] = Fiber(lambda: None)
            created_event.set()
            done_event.wait()

        def blank():
            current().parent.switch()

        def setparent(g, value):
            g.parent = value

        thread = threading.Thread(target=foo)
        thread.start()
        created_event.wait()
        g = Fiber(blank)
        g.switch()
        self.assertRaises(ValueError, setparent, g, data['g'])
        done_event.set()
        thread.join()
Пример #39
0
 def test_finalizer_crash(self):
     # This test is designed to crash when active greenlets
     # are made garbage collectable, until the underlying
     # problem is resolved. How does it work:
     # - order of object creation is important
     # - array is created first, so it is moved to unreachable first
     # - we create a cycle between a greenlet and this array
     # - we create an object that participates in gc, is only
     #   referenced by a greenlet, and would corrupt gc lists
     #   on destruction, the easiest is to use an object with
     #   a finalizer
     # - because array is the first object in unreachable it is
     #   cleared first, which causes all references to greenlet
     #   to disappear and causes greenlet to be destroyed, but since
     #   it is still live it causes a switch during gc, which causes
     #   an object with finalizer to be destroyed, which causes stack
     #   corruption and then a crash
     class object_with_finalizer(object):
         def __del__(self):
             pass
     array = []
     parent = current()
     def greenlet_body():
         current().object = object_with_finalizer()
         try:
             parent.switch()
         finally:
             del current().object
     g = Fiber(greenlet_body)
     g.array = array
     array.append(g)
     g.switch()
     del array
     del g
     current()
     gc.collect()
Пример #40
0
    def await_all_tasks(cls, tasks):
        """
        wait until a set of Tasks is complete.

        Parameters
        ---
        tasks : list of Task
        """
        self = cls._get()
        fb = Fiber.current()

        def _callback():
            self._fibers.append(fb)

        cls.watch_all_tasks(tasks, _callback)
        self._loop_fiber.switch()
Пример #41
0
    def await_task(cls, task):
        """
        wait until a Task is complete.

        Parameters
        ---
        task : Task
        """
        self = cls._get()
        fb = Fiber.current()

        def _callback():
            self._fibers.append(fb)

        cls.watch_task(task, _callback)
        self._loop_fiber.switch()
Пример #42
0
    def await_all_ps(cls, ps_set):
        """
        wait until a set of ParameterSets is complete.
        While waiting, other co-routines are concurrently executed.

        Parameters
        ---
        ps_set : list of ParameterSet
        """
        self = cls._get()
        fb = Fiber.current()

        def _callback():
            self._fibers.append(fb)

        cls.watch_all_ps(ps_set, _callback)
        self._loop_fiber.switch()
Пример #43
0
    def await_ps(cls, ps):
        """
        wait until parameterSet is complete.
        During waiting, other co-routines are concurrently executed.

        Parameters
        ---
        ps : ParameterSet
        """
        self = cls._get()
        fb = Fiber.current()

        def _callback():
            self._fibers.append(fb)

        cls.watch_ps(ps, _callback)
        self._loop_fiber.switch()
Пример #44
0
    def test_throw_goes_to_original_parent3(self):
        main = fibers.current()

        def f1():
            try:
                main.switch("f1 ready to catch")
            except IndexError:
                return "caught"
            else:
                return "normal exit"

        def f2():
            main.switch("from f2")

        g1 = Fiber(f1)
        g2 = Fiber(target=f2, parent=g1)
        res = g1.switch()
        self.assertEqual(res, "f1 ready to catch")
        res = g2.switch()
        self.assertEqual(res, "from f2")
        res = g2.throw(IndexError)
        self.assertEqual(res, "caught")
        self.assertFalse(g2.is_alive())
        self.assertFalse(g1.is_alive())
Пример #45
0
    def test_simple2(self):
        lst = []

        def f():
            lst.append(1)
            current().parent.switch()
            lst.append(3)
        g = Fiber(f)
        lst.append(0)
        g.switch()
        lst.append(2)
        g.switch()
        lst.append(4)
        self.assertEqual(lst, list(range(5)))
Пример #46
0
    def test_val(self):
        def f():
            try:
                switch("ok")
            except RuntimeError:
                val = sys.exc_info()[1]
                if str(val) == "ciao":
                    switch("ok")
                    return
            switch("fail")

        g = Fiber(f)
        res = g.switch()
        self.assertEqual(res, "ok")
        res = g.throw(RuntimeError("ciao"))
        self.assertEqual(res, "ok")

        g = Fiber(f)
        res = g.switch()
        self.assertEqual(res, "ok")
        res = g.throw(RuntimeError, "ciao")
        self.assertEqual(res, "ok")
Пример #47
0
    def do_async(cls, func, *args, **kwargs):
        """
        do coroutine asynchronously.

        Examples
        ---
        Server.do_async( lambda : Task.create(...) )

        Parameters
        ---
        tasks : list of Task
        callback : callable
        """
        self = cls._get()

        def _f():
            func(*args, **kwargs)
            self._loop_fiber.switch()

        fb = Fiber(target=_f)
        self._fibers.append(fb)
Пример #48
0
    def __init__(self):
        if getattr(_tls, 'loop', None) is not None:
            raise RuntimeError('cannot instantiate more than one event loop per thread')
        _tls.loop = self
        self._loop = pyuv.Loop()
        self._loop.excepthook = self._handle_error
        self._loop.event_loop = self
        self._threadpool = ThreadPool(self)
        self.task = Fiber(self._run_loop)

        self._destroyed = False
        self._started = False
        self._running = False

        self._fd_map = dict()
        self._signals = dict()
        self._timers = set()
        self._ready = deque()

        self._ready_processor = pyuv.Idle(self._loop)
        self._waker = pyuv.Async(self._loop, self._async_cb)
        self._waker.unref()

        self._install_signal_checker()
Пример #49
0
    def test_throw_goes_to_original_parent(self):
        main = fibers.current()

        def f1():
            try:
                main.switch("f1 ready to catch")
            except IndexError:
                return "caught"
            else:
                return "normal exit"

        def f2():
            main.switch("from f2")

        g1 = Fiber(f1)
        g2 = Fiber(target=f2, parent=g1)
        self.assertRaises(IndexError, g2.throw, IndexError)
        self.assertFalse(g2.is_alive())
        self.assertTrue(
            g1.is_alive())  # g1 is skipped because it was not started
Пример #50
0
    def test_throw_goes_to_original_parent3(self):
        main = fibers.current()

        def f1():
            try:
                main.switch("f1 ready to catch")
            except IndexError:
                return "caught"
            else:
                return "normal exit"

        def f2():
            main.switch("from f2")

        g1 = Fiber(f1)
        g2 = Fiber(target=f2, parent=g1)
        res = g1.switch()
        self.assertEqual(res, "f1 ready to catch")
        res = g2.switch()
        self.assertEqual(res, "from f2")
        res = g2.throw(IndexError)
        self.assertEqual(res, "caught")
        self.assertFalse(g2.is_alive())
        self.assertFalse(g1.is_alive())
Пример #51
0
    def test_val(self):
        def f():
            try:
                switch("ok")
            except RuntimeError:
                val = sys.exc_info()[1]
                if str(val) == "ciao":
                    switch("ok")
                    return
            switch("fail")

        g = Fiber(f)
        res = g.switch()
        self.assertEqual(res, "ok")
        res = g.throw(RuntimeError("ciao"))
        self.assertEqual(res, "ok")

        g = Fiber(f)
        res = g.switch()
        self.assertEqual(res, "ok")
        res = g.throw(RuntimeError, "ciao")
        self.assertEqual(res, "ok")
Пример #52
0
class EventLoop(object):

    def __init__(self):
        if getattr(_tls, 'loop', None) is not None:
            raise RuntimeError('cannot instantiate more than one event loop per thread')
        _tls.loop = self
        self._loop = pyuv.Loop()
        self._loop.excepthook = self._handle_error
        self._loop.event_loop = self
        self._threadpool = ThreadPool(self)
        self.task = Fiber(self._run_loop)

        self._destroyed = False
        self._started = False
        self._running = False

        self._fd_map = dict()
        self._signals = dict()
        self._timers = set()
        self._ready = deque()

        self._ready_processor = pyuv.Idle(self._loop)
        self._waker = pyuv.Async(self._loop, self._async_cb)
        self._waker.unref()

        self._install_signal_checker()

    @classmethod
    def current(cls):
        """Get the current event loop singleton object.
        """
        try:
            return _tls.loop
        except AttributeError:
            # create loop only for main thread
            if threading.current_thread().name == 'MainThread':
                _tls.loop = cls()
                return _tls.loop
            raise RuntimeError('there is no event loop created in the current thread')

    @property
    def running(self):
        return self._running

    def call_soon(self, callback, *args, **kw):
        handler = Handler(callback, *args, **kw)
        self._add_callback(handler)
        return handler

    def call_from_thread(self, callback, *args, **kw):
        handler = Handler(callback, *args, **kw)
        # Here we don't call self._add_callback on purpose, because it's not thread
        # safe to start pyuv handles. We just append the callback to the queue and
        # wakeup the loop. This is thread safe because the queue is only processed
        # in a single place and in a thread safe manner.
        self._ready.append(handler)
        self._waker.send()
        return handler

    def call_later(self, delay, callback, *args, **kw):
        if delay <= 0:
            return self.call_soon(callback, *args, **kw)
        timer_h = pyuv.Timer(self._loop)
        handler = Timer(timer_h, callback, *args, **kw)
        timer_h.handler = handler
        timer_h.start(self._timer_cb, delay, 0)
        self._timers.add(timer_h)
        return handler

    def call_at(self, when, callback, *args, **kw):
        return self.call_later(when-self.time(), callback, *args, **kw)

    def time(self):
        return _time()

    def add_reader(self, fd, callback, *args, **kw):
        handler = Handler(callback, *args, **kw)
        try:
            poll_h = self._fd_map[fd]
        except KeyError:
            poll_h = self._create_poll_handle(fd)
            self._fd_map[fd] = poll_h
        else:
            if poll_h.read_handler:
                raise RuntimeError('another reader is already registered for fd {}'.format(fd))
        poll_h.pevents |= pyuv.UV_READABLE
        poll_h.read_handler = handler
        poll_h.start(poll_h.pevents, self._poll_cb)

    def remove_reader(self, fd):
        try:
            poll_h = self._fd_map[fd]
        except KeyError:
            return False
        else:
            handler = poll_h.read_handler
            poll_h.pevents &= ~pyuv.UV_READABLE
            poll_h.read_handler = None
            if poll_h.pevents == 0:
                poll_h.close()
                del self._fd_map[fd]
            else:
                poll_h.start(poll_h.pevents, self._poll_cb)
            if handler:
                handler.cancel()
                return True
            return False

    def add_writer(self, fd, callback, *args, **kw):
        handler = Handler(callback, *args, **kw)
        try:
            poll_h = self._fd_map[fd]
        except KeyError:
            poll_h = self._create_poll_handle(fd)
            self._fd_map[fd] = poll_h
        else:
            if poll_h.write_handler:
                raise RuntimeError('another writer is already registered for fd {}'.format(fd))
        poll_h.pevents |= pyuv.UV_WRITABLE
        poll_h.write_handler = handler
        poll_h.start(poll_h.pevents, self._poll_cb)

    def remove_writer(self, fd):
        try:
            poll_h = self._fd_map[fd]
        except KeyError:
            return False
        else:
            handler = poll_h.write_handler
            poll_h.pevents &= ~pyuv.UV_WRITABLE
            poll_h.write_handler = None
            if poll_h.pevents == 0:
                poll_h.close()
                del self._fd_map[fd]
            else:
                poll_h.start(poll_h.pevents, self._poll_cb)
            if handler:
                handler.cancel()
                return True
            return False

    def add_signal_handler(self, sig, callback, *args, **kwargs):
        self._validate_signal(sig)
        signal_h = pyuv.Signal(self._loop)
        handler = SignalHandler(signal_h, callback, *args, **kwargs)
        signal_h.handler = handler
        signal_h.signum = sig
        try:
            signal_h.start(self._signal_cb, sig)
            signal_h.unref()
        except Exception as e:
            signal_h.close()
            raise RuntimeError(str(e))
        else:
            self._signals.setdefault(sig, set()).add(signal_h)
        return handler

    def remove_signal_handler(self, sig):
        self._validate_signal(sig)
        try:
            handles = self._signals.pop(sig)
        except KeyError:
            return False
        for signal_h in handles:
            del signal_h.handler
            signal_h.close()
        return True

    def switch(self):
        if not self._started:
            self.run()
            return
        current = Fiber.current()
        assert current is not self.task, 'Cannot switch to MAIN from MAIN'
        try:
            if self.task.parent is not current:
                current.parent = self.task
        except ValueError:
            pass  # gets raised if there is a Fiber parent cycle
        return self.task.switch()

    def run(self, mode=RUN_DEFAULT):
        if Fiber.current() is not self.task.parent:
            raise RuntimeError('run() can only be called from MAIN fiber')
        if not self.task.is_alive():
            raise RuntimeError('event loop has already ended')
        if self._started:
            raise RuntimeError('event loop was already started')
        self._started = True
        self._running = True
        self._run_mode = mode
        try:
            self.task.switch()
        finally:
            self._running = False

    def run_forever(self):
        self.run(mode=RUN_FOREVER)

    def stop(self):
        if not self._started:
            raise RuntimeError('event loop has not been started yet')
        if self._loop:
            self._loop.stop()

    def destroy(self):
        if self._running:
            raise RuntimeError('destroy() cannot be called while the loop is running')

        if self._destroyed:
            raise RuntimeError('Event loop already destroyed')

        loop = getattr(_tls, 'loop', None)
        if loop is not self:
            raise RuntimeError('destroy() can only be called from the same thread were the event loop was created')
        del _tls.loop, loop

        self._destroyed = True
        self._uninstall_signal_checker()

        self._cleanup_loop()
        self._loop.event_loop = None
        self._loop.excepthook = None
        self._loop = None
        self._threadpool = None

        self._ready_processor = None
        self._waker = None

        self._fd_map.clear()
        self._signals.clear()
        self._timers.clear()
        self._ready.clear()

    # internal

    def _add_callback(self, cb):
        self._ready.append(cb)
        if not self._ready_processor.active:
            self._ready_processor.start(self._process_ready)

    def _handle_error(self, typ, value, tb):
        if not issubclass(typ, SystemExit):
            traceback.print_exception(typ, value, tb)
        if issubclass(typ, (KeyboardInterrupt, SystemExit, SystemError)):
            assert Fiber.current() is self.task
            self.task.parent.throw(typ, value, tb)

    def _run_loop(self):
        if self._run_mode == RUN_FOREVER:
            self._waker.ref()
        self._loop.run(pyuv.UV_RUN_DEFAULT)

    def _cleanup_loop(self):
        def cb(handle):
            if not handle.closed:
                handle.close()
        self._loop.walk(cb)
        # All handles are now closed, run will not block
        self._loop.run(pyuv.UV_RUN_NOWAIT)

    def _create_poll_handle(self, fd):
        poll_h = pyuv.Poll(self._loop, fd)
        poll_h.pevents = 0
        poll_h.read_handler = None
        poll_h.write_handler = None
        return poll_h

    def _process_ready(self, handle):
        # Run all queued callbacks
        ntodo = len(self._ready)
        for x in range(ntodo):
            handler = self._ready.popleft()
            if not handler._cancelled:
                # loop.excepthook takes care of exception handling
                handler()
        if not self._ready:
            self._ready_processor.stop()

    def _async_cb(self, handle):
        if not self._ready_processor.active:
            self._ready_processor.start(self._process_ready)

    def _timer_cb(self, timer):
        assert not timer.handler._cancelled
        self._add_callback(timer.handler)
        if not timer.repeat:
            timer.close()
            self._timers.remove(timer)
            del timer.handler

    def _signal_cb(self, signal_h, signum):
        self._add_callback(signal_h.handler)

    def _poll_cb(self, poll_h, events, error):
        fd = poll_h.fileno()
        if error is not None:
            # An error happened, signal both readability and writability and
            # let the error propagate
            if poll_h.read_handler is not None:
                if poll_h.read_handler._cancelled:
                    self.remove_reader(fd)
                else:
                    self._add_callback(poll_h.read_handler)
            if poll_h.write_handler is not None:
                if poll_h.write_handler._cancelled:
                    self.remove_writer(fd)
                else:
                    self._add_callback(poll_h.write_handler)
            return

        old_events = poll_h.pevents
        modified = False

        if events & pyuv.UV_READABLE:
            if poll_h.read_handler is not None:
                if poll_h.read_handler._cancelled:
                    self.remove_reader(fd)
                    modified = True
                else:
                    self._add_callback(poll_h.read_handler)
            else:
                poll_h.pevents &= ~pyuv.UV_READABLE
        if events & pyuv.UV_WRITABLE:
            if poll_h.write_handler is not None:
                if poll_h.write_handler._cancelled:
                    self.remove_writer(fd)
                    modified = True
                else:
                    self._add_callback(poll_h.write_handler)
            else:
                poll_h.pevents &= ~pyuv.UV_WRITABLE

        if not modified and old_events != poll_h.pevents:
            # Rearm the handle
            poll_h.start(poll_h.pevents, self._poll_cb)

    def _install_signal_checker(self):
        self._socketpair = SocketPair()
        self._signal_checker = None
        if hasattr(signal, 'set_wakeup_fd') and os.name == 'posix':
            try:
                old_wakeup_fd = signal.set_wakeup_fd(self._socketpair.writer_fileno())
                if old_wakeup_fd != -1:
                    # Already set, restore it
                    signal.set_wakeup_fd(old_wakeup_fd)
                    self._socketpair.close()
                    self._socketpair = None
                else:
                    self._signal_checker = pyuv.util.SignalChecker(self._loop, self._socketpair.reader_fileno())
                    self._signal_checker.start()
                    self._signal_checker.unref()
            except ValueError:
                self._socketpair.close()
                self._socketpair = None

    def _uninstall_signal_checker(self):
        if self._signal_checker:
            self._signal_checker.close()
            self._signal_checker = None
        if self._socketpair:
            self._socketpair.close()
            self._socketpair = None

    def _validate_signal(self, sig):
        if not isinstance(sig, int):
            raise TypeError('sig must be an int, not {!r}'.format(sig))
        if signal is None:
            raise RuntimeError('Signals are not supported')
        if not (1 <= sig < signal.NSIG):
            raise ValueError('sig {} out of range(1, {})'.format(sig, signal.NSIG))
Пример #53
0
 def _handle_error(self, typ, value, tb):
     if not issubclass(typ, SystemExit):
         traceback.print_exception(typ, value, tb)
     if issubclass(typ, (KeyboardInterrupt, SystemExit, SystemError)):
         assert Fiber.current() is self.task
         self.task.parent.throw(typ, value, tb)
Пример #54
0
 def test_send_exception(self):
     seen = []
     g1 = Fiber(target=fmain, args=(seen, ))
     g1.switch()
     self.assertRaises(KeyError, send_exception, g1, KeyError)
     self.assertEqual(seen, [KeyError])
Пример #55
0
 def runner(x):
     g = Fiber(lambda: time.sleep(x))
     g.switch()
Пример #56
0
 def creator():
     g = Fiber(worker)
     g.switch()
     result.append(g)
Пример #57
0
 def _dead_fiber():
     g = Fiber(lambda: None)
     g.switch()
     return g
Пример #58
0
 def __init__(self, *args, **kwds):
     self.args = args
     self.kwds = kwds
     Fiber.__init__(self, target=self.run)
Пример #59
0
 def h():
     lst.append(1)
     i = Fiber(f)
     i.switch()
     lst.append(1)
Пример #60
0
    def test_two_children(self):
        lst = []

        def f():
            lst.append(1)
            current().parent.switch()
            lst.extend([1, 1])
        g = Fiber(f)
        h = Fiber(f)
        g.switch()
        self.assertEqual(len(lst), 1)
        h.switch()
        self.assertEqual(len(lst), 2)
        h.switch()
        self.assertEqual(len(lst), 4)
        self.assertEqual(h.is_alive(), False)
        g.switch()
        self.assertEqual(len(lst), 6)
        self.assertEqual(g.is_alive(), False)