Commit 111521eb authored by Jason Madden's avatar Jason Madden

Merge branch 'master' of https://github.com/gevent/gevent

parents df0163d0 b3537301
...@@ -87,13 +87,15 @@ ...@@ -87,13 +87,15 @@
- Greenlet objects now keep track of their spawning parent greenlet - Greenlet objects now keep track of their spawning parent greenlet
and the code location that spawned them, in addition to maintaining and the code location that spawned them, in addition to maintaining
a "spawn tree local" mapping. Based on a proposal from PayPal and a "spawn tree local" mapping. This adds some runtime overhead in
comments by Mahmoud Hashemi and Kurt Rose. See :issue:`755` and relative terms, but absolute numbers are still relatively small.
:pr:`1115`. As always, feedback is appreciated. Based on a proposal from PayPal and comments by Mahmoud Hashemi and
Kurt Rose. See :issue:`755` and :pr:`1115`. As always, feedback is
appreciated.
- The :mod:`gevent.greenlet` module is now compiled with Cython to - The :mod:`gevent.greenlet` module is now compiled with Cython to
offset any performance decrease due to :issue:`755`. Please open offset any performance decrease due to :issue:`755`. Please open
issues for any compatibility concerns. See :pr:`1115`. issues for any compatibility concerns. See :pr:`1115` and :pr:`1120`.
- Greenlet objects now have a ``minimal_ident`` property. It functions - Greenlet objects now have a ``minimal_ident`` property. It functions
similarly to ``Thread.ident`` or ``id`` by uniquely identifying the similarly to ``Thread.ident`` or ``id`` by uniquely identifying the
......
...@@ -4,6 +4,8 @@ cimport cython ...@@ -4,6 +4,8 @@ cimport cython
from gevent.__ident cimport IdentRegistry from gevent.__ident cimport IdentRegistry
cdef bint _greenlet_imported cdef bint _greenlet_imported
cdef bint _PYPY cdef bint _PYPY
cdef sys_getframe
cdef sys_exc_info
cdef extern from "greenlet/greenlet.h": cdef extern from "greenlet/greenlet.h":
...@@ -25,6 +27,23 @@ cdef inline void greenlet_init(): ...@@ -25,6 +27,23 @@ cdef inline void greenlet_init():
PyGreenlet_Import() PyGreenlet_Import()
_greenlet_imported = True _greenlet_imported = True
cdef extern from "Python.h":
ctypedef class types.CodeType [object PyCodeObject]:
pass
cdef extern from "frameobject.h":
ctypedef class types.FrameType [object PyFrameObject]:
cdef CodeType f_code
cdef int f_lineno
# We can't declare this in the object, because it's
# allowed to be NULL, and Cython can't handle that.
# We have to go through the python machinery to get a
# proper None instead.
# cdef FrameType f_back
cdef void _init() cdef void _init()
cdef class SpawnedLink: cdef class SpawnedLink:
...@@ -42,18 +61,18 @@ cdef class FailureSpawnedLink(SpawnedLink): ...@@ -42,18 +61,18 @@ cdef class FailureSpawnedLink(SpawnedLink):
@cython.final @cython.final
@cython.internal @cython.internal
cdef class _Frame: cdef class _Frame:
cdef readonly object f_code cdef readonly CodeType f_code
cdef readonly int f_lineno cdef readonly int f_lineno
cdef public _Frame f_back cdef readonly _Frame f_back
@cython.final @cython.final
@cython.locals( @cython.locals(frames=list,frame=FrameType)
previous=_Frame, cdef inline list _extract_stack(int limit)
first=_Frame,
next_frame=_Frame)
cdef _Frame _extract_stack(int limit, _Frame f_back)
@cython.final
@cython.locals(previous=_Frame, frame=tuple, f=_Frame)
cdef _Frame _Frame_from_list(list frames)
cdef class Greenlet(greenlet): cdef class Greenlet(greenlet):
...@@ -61,7 +80,10 @@ cdef class Greenlet(greenlet): ...@@ -61,7 +80,10 @@ cdef class Greenlet(greenlet):
cdef readonly args cdef readonly args
cdef readonly object spawning_greenlet cdef readonly object spawning_greenlet
cdef public dict spawn_tree_locals cdef public dict spawn_tree_locals
cdef readonly _Frame spawning_stack
# This is accessed with getattr() dynamically so it
# must be visible to Python
cdef readonly list _spawning_stack_frames
cdef list _links cdef list _links
cdef tuple _exc_info cdef tuple _exc_info
......
...@@ -2,13 +2,15 @@ ...@@ -2,13 +2,15 @@
# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False # cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
import sys from sys import _getframe as sys_getframe
from sys import exc_info as sys_exc_info
from weakref import ref as wref from weakref import ref as wref
from greenlet import greenlet from greenlet import greenlet
from gevent._compat import reraise from gevent._compat import reraise
from gevent._compat import PYPY as _PYPY
from gevent._tblib import dump_traceback from gevent._tblib import dump_traceback
from gevent._tblib import load_traceback from gevent._tblib import load_traceback
from gevent.hub import GreenletExit from gevent.hub import GreenletExit
...@@ -18,8 +20,7 @@ from gevent.hub import get_hub ...@@ -18,8 +20,7 @@ from gevent.hub import get_hub
from gevent.hub import iwait from gevent.hub import iwait
from gevent.hub import wait from gevent.hub import wait
from gevent.timeout import Timeout from gevent.timeout import Timeout
from gevent._util import Lazy
_PYPY = hasattr(sys, 'pypy_version_info')
__all__ = [ __all__ = [
...@@ -108,26 +109,28 @@ class _Frame(object): ...@@ -108,26 +109,28 @@ class _Frame(object):
self.f_lineno = f_lineno self.f_lineno = f_lineno
self.f_back = None self.f_back = None
f_globals = property(lambda _self: None) @property
def f_globals(self):
return None
def _extract_stack(limit, f_back): def _Frame_from_list(frames):
previous = None previous = None
frame = sys._getframe() for frame in reversed(frames):
first = None f = _Frame(*frame)
f.f_back = previous
previous = f
return previous
first = previous = _Frame(frame.f_code, frame.f_lineno) def _extract_stack(limit):
limit -= 1 frame = sys_getframe()
frame = frame.f_back frames = []
while limit and frame is not None: while limit and frame is not None:
limit -= 1 limit -= 1
next_frame = _Frame(frame.f_code, frame.f_lineno) frames.append((frame.f_code, frame.f_lineno))
previous.f_back = next_frame
previous = next_frame
frame = frame.f_back frame = frame.f_back
previous.f_back = f_back return frames
return first
_greenlet__init__ = greenlet.__init__ _greenlet__init__ = greenlet.__init__
...@@ -274,9 +277,16 @@ class Greenlet(greenlet): ...@@ -274,9 +277,16 @@ class Greenlet(greenlet):
# Its children get separate locals. # Its children get separate locals.
spawner.spawn_tree_locals = self.spawn_tree_locals spawner.spawn_tree_locals = self.spawn_tree_locals
self._spawning_stack_frames = _extract_stack(self.spawning_stack_limit)
self._spawning_stack_frames.extend(getattr(spawner, '_spawning_stack_frames', []))
self.spawning_stack = _extract_stack(self.spawning_stack_limit, @Lazy
getattr(spawner, 'spawning_stack', None)) def spawning_stack(self):
# Store this in the __dict__. We don't use it from the C
# code. It's tempting to discard _spawning_stack_frames
# after this, but child greenlets may still be created
# that need it.
return _Frame_from_list(self._spawning_stack_frames)
def _get_minimal_ident(self): def _get_minimal_ident(self):
reg = self.parent.ident_registry reg = self.parent.ident_registry
...@@ -476,9 +486,9 @@ class Greenlet(greenlet): ...@@ -476,9 +486,9 @@ class Greenlet(greenlet):
.. versionadded:: 1.1 .. versionadded:: 1.1
""" """
exc_info = self._exc_info ei = self._exc_info
if exc_info is not None and exc_info[0] is not None: if ei is not None and ei[0] is not None:
return (exc_info[0], exc_info[1], load_traceback(exc_info[2])) return (ei[0], ei[1], load_traceback(ei[2]))
def throw(self, *args): def throw(self, *args):
"""Immediately switch into the greenlet and raise an exception in it. """Immediately switch into the greenlet and raise an exception in it.
...@@ -708,7 +718,7 @@ class Greenlet(greenlet): ...@@ -708,7 +718,7 @@ class Greenlet(greenlet):
try: try:
result = self._run(*self.args, **self.kwargs) result = self._run(*self.args, **self.kwargs)
except: # pylint:disable=bare-except except: # pylint:disable=bare-except
self._report_error(sys.exc_info()) self._report_error(sys_exc_info())
return return
self._report_result(result) self._report_result(result)
finally: finally:
...@@ -801,7 +811,7 @@ class Greenlet(greenlet): ...@@ -801,7 +811,7 @@ class Greenlet(greenlet):
try: try:
link(self) link(self)
except: # pylint:disable=bare-except except: # pylint:disable=bare-except
self.parent.handle_error((link, self), *sys.exc_info()) self.parent.handle_error((link, self), *sys_exc_info())
class _dummy_event(object): class _dummy_event(object):
...@@ -828,7 +838,7 @@ def _kill(glet, exception, waiter): ...@@ -828,7 +838,7 @@ def _kill(glet, exception, waiter):
glet.throw(exception) glet.throw(exception)
except: # pylint:disable=bare-except except: # pylint:disable=bare-except
# XXX do we need this here? # XXX do we need this here?
glet.parent.handle_error(glet, *sys.exc_info()) glet.parent.handle_error(glet, *sys_exc_info())
if waiter is not None: if waiter is not None:
waiter.switch() waiter.switch()
...@@ -863,7 +873,7 @@ def _killall3(greenlets, exception, waiter): ...@@ -863,7 +873,7 @@ def _killall3(greenlets, exception, waiter):
try: try:
g.throw(exception) g.throw(exception)
except: # pylint:disable=bare-except except: # pylint:disable=bare-except
g.parent.handle_error(g, *sys.exc_info()) g.parent.handle_error(g, *sys_exc_info())
if not g.dead: if not g.dead:
diehards.append(g) diehards.append(g)
waiter.switch(diehards) waiter.switch(diehards)
...@@ -875,7 +885,7 @@ def _killall(greenlets, exception): ...@@ -875,7 +885,7 @@ def _killall(greenlets, exception):
try: try:
g.throw(exception) g.throw(exception)
except: # pylint:disable=bare-except except: # pylint:disable=bare-except
g.parent.handle_error(g, *sys.exc_info()) g.parent.handle_error(g, *sys_exc_info())
def killall(greenlets, exception=GreenletExit, block=True, timeout=None): def killall(greenlets, exception=GreenletExit, block=True, timeout=None):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment