Commit 62802671 authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #1156 from gevent/cython-waiter

Compile the important hub operations that use Waiters with Cython
parents 821e7fc8 a4fbd046
......@@ -16,6 +16,8 @@ src/gevent/event.c
src/gevent/_hub_local.c
src/gevent/_waiter.c
src/gevent/queue.c
src/gevent/_hub_primitives.c
src/gevent/_greenlet_primitives.c
src/gevent/libev/corecext.c
src/gevent/libev/corecext.h
src/gevent/libev/_corecffi.c
......
......@@ -51,7 +51,8 @@ Enhancements
- The classes `gevent.event.Event` and `gevent.event.AsyncResult`
are compiled with Cython for improved performance, as is the
``gevent.queue`` module and ``gevent.hub.Waiter``. Please report any
``gevent.queue`` module and ``gevent.hub.Waiter`` and certain
time-sensitive parts of the hub itself. Please report any
compatibility issues.
Monitoring and Debugging
......
# -*- coding: utf-8 -*-
"""
Benchmarks for hub primitive operations.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import perf
from perf import perf_counter
import gevent
from greenlet import greenlet
from greenlet import getcurrent
N = 1000
def bench_switch():
class Parent(type(gevent.get_hub())):
def run(self):
parent = self.parent
for _ in range(N):
parent.switch()
def child():
parent = getcurrent().parent
# Back to the hub, which in turn goes
# back to the main greenlet
for _ in range(N):
parent.switch()
hub = Parent(None, None)
child_greenlet = greenlet(child, hub)
for _ in range(N):
child_greenlet.switch()
def bench_wait_ready():
class Watcher(object):
def start(self, cb, obj):
# Immediately switch back to the waiter, mark as ready
cb(obj)
def stop(self):
pass
watcher = Watcher()
hub = gevent.get_hub()
for _ in range(1000):
hub.wait(watcher)
def bench_cancel_wait():
class Watcher(object):
active = True
callback = object()
def close(self):
pass
watcher = Watcher()
hub = gevent.get_hub()
loop = hub.loop
for _ in range(1000):
# Schedule all the callbacks.
hub.cancel_wait(watcher, None, True)
# Run them!
for cb in loop._callbacks:
if cb.callback:
cb.callback(*cb.args)
cb.stop() # so the real loop won't do it
# destroy the loop so we don't keep building these functions
# up
hub.destroy(True)
def bench_wait_func_ready():
from gevent.hub import wait
class ToWatch(object):
def rawlink(self, cb):
cb(self)
watched_objects = [ToWatch() for _ in range(N)]
t0 = perf_counter()
wait(watched_objects)
return perf_counter() - t0
def main():
runner = perf.Runner()
runner.bench_func('multiple wait ready',
bench_wait_func_ready,
inner_loops=N)
runner.bench_func('wait ready',
bench_wait_ready,
inner_loops=N)
runner.bench_func('cancel wait',
bench_cancel_wait,
inner_loops=N)
runner.bench_func('switch',
bench_switch,
inner_loops=N)
if __name__ == '__main__':
main()
......@@ -10,6 +10,9 @@
:members:
:undoc-members:
.. automethod:: wait
.. automethod:: cancel_wait
.. autoclass:: Waiter
.. autoclass:: LoopExit
......@@ -119,17 +119,32 @@ WAITER = Extension(name="gevent.__waiter",
depends=['src/gevent/__waiter.pxd'],
include_dirs=include_dirs)
HUB_PRIMITIVES = Extension(name="gevent.__hub_primitives",
sources=["src/gevent/_hub_primitives.py"],
depends=['src/gevent/__hub_primitives.pxd'],
include_dirs=include_dirs)
GLT_PRIMITIVES = Extension(name="gevent.__greenlet_primitives",
sources=["src/gevent/_greenlet_primitives.py"],
depends=['src/gevent/__greenlet_primitives.pxd'],
include_dirs=include_dirs)
_to_cythonize = [
GLT_PRIMITIVES,
HUB_PRIMITIVES,
HUB_LOCAL,
WAITER,
GREENLET,
SEMAPHORE,
LOCAL,
GREENLET,
IDENT,
IMAP,
EVENT,
QUEUE,
HUB_LOCAL,
WAITER,
]
EXT_MODULES = [
......@@ -144,6 +159,8 @@ EXT_MODULES = [
QUEUE,
HUB_LOCAL,
WAITER,
HUB_PRIMITIVES,
GLT_PRIMITIVES,
]
LIBEV_CFFI_MODULE = 'src/gevent/libev/_corecffi_build.py:ffi'
......@@ -221,6 +238,12 @@ if PYPY:
EXT_MODULES.remove(WAITER)
_to_cythonize.remove(WAITER)
EXT_MODULES.remove(GLT_PRIMITIVES)
_to_cythonize.remove(GLT_PRIMITIVES)
EXT_MODULES.remove(HUB_PRIMITIVES)
_to_cythonize.remove(HUB_PRIMITIVES)
for mod in _to_cythonize:
EXT_MODULES.remove(mod)
EXT_MODULES.append(cythonize1(mod))
......
cimport cython
# This file must not cimport anything from gevent.
cdef wref
cdef BlockingSwitchOutError
cdef extern from "greenlet/greenlet.h":
ctypedef class greenlet.greenlet [object PyGreenlet]:
pass
# These are actually macros and so much be included
# (defined) in each .pxd, as are the two functions
# that call them.
greenlet PyGreenlet_GetCurrent()
object PyGreenlet_Switch(greenlet self, void* args, void* kwargs)
void PyGreenlet_Import()
@cython.final
cdef inline greenlet getcurrent():
return PyGreenlet_GetCurrent()
cdef bint _greenlet_imported
cdef inline void greenlet_init():
global _greenlet_imported
if not _greenlet_imported:
PyGreenlet_Import()
_greenlet_imported = True
cdef inline object _greenlet_switch(greenlet self):
return PyGreenlet_Switch(self, NULL, NULL)
cdef class TrackedRawGreenlet(greenlet):
pass
cdef class SwitchOutGreenletWithLoop(TrackedRawGreenlet):
cdef public loop
cpdef switch(self)
cpdef switch_out(self)
from gevent.__greenlet_primitives cimport SwitchOutGreenletWithLoop
cdef _threadlocal
cpdef get_hub_class()
cpdef get_hub_if_exists()
cpdef set_hub(hub)
cpdef SwitchOutGreenletWithLoop get_hub_if_exists()
cpdef set_hub(SwitchOutGreenletWithLoop hub)
cpdef get_loop()
cpdef set_loop(loop)
# We can't cdef this, it won't do varargs.
# cpdef WaitOperationsGreenlet get_hub(*args, **kwargs)
# XXX: TODO: Move the definition of TrackedRawGreenlet
# into a file that can be cython compiled so get_hub can
# return that.
cpdef get_hub_noargs()
cpdef SwitchOutGreenletWithLoop get_hub_noargs()
cimport cython
from gevent.__greenlet_primitives cimport SwitchOutGreenletWithLoop
from gevent.__hub_local cimport get_hub_noargs as get_hub
from gevent.__waiter cimport Waiter
from gevent.__waiter cimport MultipleWaiter
cdef InvalidSwitchError
cdef _waiter
cdef _greenlet_primitives
cdef traceback
cdef _timeout_error
cdef Timeout
cdef extern from "greenlet/greenlet.h":
ctypedef class greenlet.greenlet [object PyGreenlet]:
pass
# These are actually macros and so much be included
# (defined) in each .pxd, as are the two functions
# that call them.
greenlet PyGreenlet_GetCurrent()
void PyGreenlet_Import()
@cython.final
cdef inline greenlet getcurrent():
return PyGreenlet_GetCurrent()
cdef bint _greenlet_imported
cdef inline void greenlet_init():
global _greenlet_imported
if not _greenlet_imported:
PyGreenlet_Import()
_greenlet_imported = True
cdef class WaitOperationsGreenlet(SwitchOutGreenletWithLoop):
cpdef wait(self, watcher)
cpdef cancel_wait(self, watcher, error, close_watcher=*)
cpdef _cancel_wait(self, watcher, error, close_watcher)
cdef class _WaitIterator:
cdef SwitchOutGreenletWithLoop _hub
cdef MultipleWaiter _waiter
cdef _switch
cdef _timeout
cdef _objects
cdef _timer
cdef Py_ssize_t _count
cdef bint _begun
cdef _cleanup(self)
cpdef iwait_on_objects(objects, timeout=*, count=*)
cpdef wait_on_objects(objects=*, timeout=*, count=*)
cdef _primitive_wait(watcher, timeout, timeout_exc, WaitOperationsGreenlet hub)
cpdef wait_on_watcher(watcher, timeout=*, timeout_exc=*, WaitOperationsGreenlet hub=*)
cpdef wait_read(fileno, timeout=*, timeout_exc=*)
cpdef wait_write(fileno, timeout=*, timeout_exc=*, event=*)
cpdef wait_readwrite(fileno, timeout=*, timeout_exc=*, event=*)
cpdef wait_on_socket(socket, watcher, timeout_exc=*)
......@@ -20,5 +20,7 @@ cdef class IdentRegistry:
cdef object _registry
cdef list _available_idents
@cython.final
cpdef object get_ident(self, obj)
@cython.final
cpdef _return_ident(self, ValuedWeakRef ref)
# cython: auto_pickle=False
cimport cython
from gevent.__hub_local cimport get_hub_noargs as get_hub
cdef Timeout
......
cimport cython
from gevent.__greenlet_primitives cimport SwitchOutGreenletWithLoop
from gevent.__hub_local cimport get_hub_noargs as get_hub
cdef sys
cdef ConcurrentObjectUseError
from gevent.__hub_local cimport get_hub_noargs as get_hub
cdef bint _greenlet_imported
cdef _NONE
......@@ -29,11 +31,17 @@ cdef inline void greenlet_init():
_greenlet_imported = True
cdef class Waiter:
cdef readonly hub
cdef readonly greenlet
cdef readonly SwitchOutGreenletWithLoop hub
cdef readonly greenlet greenlet
cdef readonly value
cdef _exception
cpdef get(self)
cpdef clear(self)
# cpdef of switch leads to parameter errors...
#cpdef switch(self, value)
@cython.final
@cython.internal
cdef class MultipleWaiter(Waiter):
......
cimport cython
from gevent.__greenlet_primitives cimport SwitchOutGreenletWithLoop
from gevent.__hub_local cimport get_hub_noargs as get_hub
cdef _None
cdef reraise
cdef dump_traceback
cdef load_traceback
cdef get_hub
cdef InvalidSwitchError
cdef Timeout
......@@ -35,7 +38,7 @@ cdef void _init()
cdef class _AbstractLinkable:
cdef _notifier
cdef set _links
cdef readonly hub
cdef readonly SwitchOutGreenletWithLoop hub
cpdef rawlink(self, callback)
cpdef bint ready(self)
......
......@@ -9,6 +9,8 @@ cdef bint _PYPY
cdef sys_getframe
cdef sys_exc_info
cdef Timeout
cdef GreenletExit
cdef InvalidSwitchError
cdef extern from "greenlet/greenlet.h":
......@@ -141,14 +143,12 @@ cdef _threadlocal
cdef get_hub_class
cdef wref
cdef Timeout
cdef dump_traceback
cdef load_traceback
cdef Waiter
cdef wait
cdef iwait
cdef reraise
cdef InvalidSwitchError
cpdef GEVENT_CONFIG
......
# -*- coding: utf-8 -*-
# copyright (c) 2018 gevent. See LICENSE.
# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False
"""
A collection of primitives used by the hub, and suitable for
compilation with Cython because of their frequency of use.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from weakref import ref as wref
from greenlet import greenlet
from gevent.exceptions import BlockingSwitchOutError
# In Cython, we define these as 'cdef inline' functions. The
# compilation unit cannot have a direct assignment to them (import
# is assignment) without generating a 'lvalue is not valid target'
# error.
locals()['getcurrent'] = __import__('greenlet').getcurrent
locals()['greenlet_init'] = lambda: None
locals()['_greenlet_switch'] = greenlet.switch
__all__ = [
'TrackedRawGreenlet',
'SwitchOutGreenletWithLoop',
]
class TrackedRawGreenlet(greenlet):
def __init__(self, function, parent):
greenlet.__init__(self, function, parent)
# See greenlet.py's Greenlet class. We capture the cheap
# parts to maintain the tree structure, but we do not capture
# the stack because that's too expensive for 'spawn_raw'.
current = getcurrent() # pylint:disable=undefined-variable
self.spawning_greenlet = wref(current)
# See Greenlet for how trees are maintained.
try:
self.spawn_tree_locals = current.spawn_tree_locals
except AttributeError:
self.spawn_tree_locals = {}
if current.parent:
current.spawn_tree_locals = self.spawn_tree_locals
class SwitchOutGreenletWithLoop(TrackedRawGreenlet):
# Subclasses must define:
# - self.loop
# This class defines loop in its .pxd for Cython. This lets us avoid
# circular dependencies with the hub.
def switch(self):
switch_out = getattr(getcurrent(), 'switch_out', None) # pylint:disable=undefined-variable
if switch_out is not None:
switch_out()
return _greenlet_switch(self) # pylint:disable=undefined-variable
def switch_out(self):
raise BlockingSwitchOutError('Impossible to call blocking function in the event loop callback')
def _init():
greenlet_init() # pylint:disable=undefined-variable
_init()
from gevent._util import import_c_accel
import_c_accel(globals(), 'gevent.__greenlet_primitives')
This diff is collapsed.
......@@ -70,6 +70,10 @@ class IdentRegistry(object):
def _return_ident(self, vref):
# By the time this is called, self._registry has been
# updated
if heappush is not None:
# Under some circumstances we can get called
# when the interpreter is shutting down, and globals
# aren't available any more.
heappush(self._available_idents, vref.value)
def __len__(self):
......
......@@ -103,6 +103,7 @@ class _closedsocket(object):
timeout_default = object()
from gevent._hub_primitives import wait_on_socket as _wait_on_socket
class socket(object):
"""
......@@ -180,22 +181,7 @@ class socket(object):
ref = property(_get_ref, _set_ref)
def _wait(self, watcher, timeout_exc=timeout('timed out')):
"""Block the current greenlet until *watcher* has pending events.
If *timeout* is non-negative, then *timeout_exc* is raised after *timeout* second has passed.
By default *timeout_exc* is ``socket.timeout('timed out')``.
If :func:`cancel_wait` is called, raise ``socket.error(EBADF, 'File descriptor was closed in another greenlet')``.
"""
if watcher.callback is not None:
raise _socketcommon.ConcurrentObjectUseError('This socket is already used by another greenlet: %r' % (watcher.callback, ))
timeout = Timeout._start_new_or_dummy(self.timeout, timeout_exc, ref=False)
try:
self.hub.wait(watcher)
finally:
timeout.close()
_wait = _wait_on_socket
def accept(self):
sock = self._sock
......
......@@ -67,6 +67,7 @@ class _wrefsocket(_socket.socket):
timeout = property(lambda s: s.gettimeout(),
lambda s, nv: s.settimeout(nv))
from gevent._hub_primitives import wait_on_socket as _wait_on_socket
class socket(object):
"""
......@@ -181,22 +182,7 @@ class socket(object):
ref = property(_get_ref, _set_ref)
def _wait(self, watcher, timeout_exc=timeout('timed out')):
"""Block the current greenlet until *watcher* has pending events.
If *timeout* is non-negative, then *timeout_exc* is raised after *timeout* second has passed.
By default *timeout_exc* is ``socket.timeout('timed out')``.
If :func:`cancel_wait` is called, raise ``socket.error(EBADF, 'File descriptor was closed in another greenlet')``.
"""
if watcher.callback is not None:
raise _socketcommon.ConcurrentObjectUseError('This socket is already used by another greenlet: %r' % (watcher.callback, ))
timer = Timeout._start_new_or_dummy(self.timeout, timeout_exc, ref=False)
try:
self.hub.wait(watcher)
finally:
timer.close()
_wait = _wait_on_socket
def dup(self):
"""dup() -> socket object
......
......@@ -134,96 +134,13 @@ del _name, _value
_timeout_error = timeout # pylint: disable=undefined-variable
from gevent import _hub_primitives
_hub_primitives.set_default_timeout_error(_timeout_error)
def wait(io, timeout=None, timeout_exc=_NONE):
"""
Block the current greenlet until *io* is ready.
If *timeout* is non-negative, then *timeout_exc* is raised after
*timeout* second has passed. By default *timeout_exc* is
``socket.timeout('timed out')``.
If :func:`cancel_wait` is called on *io* by another greenlet,
raise an exception in this blocking greenlet
(``socket.error(EBADF, 'File descriptor was closed in another
greenlet')`` by default).
:param io: A libev watcher, most commonly an IO watcher obtained from
:meth:`gevent.core.loop.io`
:keyword timeout_exc: The exception to raise if the timeout expires.
By default, a :class:`socket.timeout` exception is raised.
If you pass a value for this keyword, it is interpreted as for
:class:`gevent.timeout.Timeout`.
"""
if io.callback is not None:
raise ConcurrentObjectUseError('This socket is already used by another greenlet: %r' % (io.callback, ))
timeout = Timeout._start_new_or_dummy(
timeout,
(timeout_exc
if timeout_exc is not _NONE or timeout is None
else _timeout_error('timed out')))
with timeout:
return get_hub().wait(io)
# rename "io" to "watcher" because wait() works with any watcher
def wait_read(fileno, timeout=None, timeout_exc=_NONE):
"""
Block the current greenlet until *fileno* is ready to read.
For the meaning of the other parameters and possible exceptions,
see :func:`wait`.
.. seealso:: :func:`cancel_wait`
"""
io = get_hub().loop.io(fileno, 1)
try:
return wait(io, timeout, timeout_exc)
finally:
io.close()
def wait_write(fileno, timeout=None, timeout_exc=_NONE, event=_NONE):
"""
Block the current greenlet until *fileno* is ready to write.
For the meaning of the other parameters and possible exceptions,
see :func:`wait`.
:keyword event: Ignored. Applications should not pass this parameter.
In the future, it may become an error.
.. seealso:: :func:`cancel_wait`
"""
# pylint:disable=unused-argument
io = get_hub().loop.io(fileno, 2)
try:
return wait(io, timeout, timeout_exc)
finally:
io.close()
def wait_readwrite(fileno, timeout=None, timeout_exc=_NONE, event=_NONE):
"""
Block the current greenlet until *fileno* is ready to read or
write.
For the meaning of the other parameters and possible exceptions,
see :func:`wait`.
:keyword event: Ignored. Applications should not pass this parameter.
In the future, it may become an error.
.. seealso:: :func:`cancel_wait`
"""
# pylint:disable=unused-argument
io = get_hub().loop.io(fileno, 3)
try:
return wait(io, timeout, timeout_exc)
finally:
io.close()
wait = _hub_primitives.wait_on_watcher
wait_read = _hub_primitives.wait_read
wait_write = _hub_primitives.wait_write
wait_readwrite = _hub_primitives.wait_readwrite
#: The exception raised by default on a call to :func:`cancel_wait`
class cancel_wait_ex(error): # pylint: disable=undefined-variable
......@@ -238,8 +155,6 @@ def cancel_wait(watcher, error=cancel_wait_ex):
get_hub().cancel_wait(watcher, error)
def gethostbyname(hostname):
"""
gethostbyname(host) -> address
......
......@@ -99,8 +99,14 @@ class Waiter(object):
if self._exception is not _NONE:
return self._exception
def switch(self, value=None):
"""Switch to the greenlet if one's available. Otherwise store the value."""
def switch(self, value):
"""
Switch to the greenlet if one's available. Otherwise store the
*value*.
.. versionchanged:: 1.3b1
The *value* is no longer optional.
"""
greenlet = self.greenlet
if greenlet is None:
self.value = value
......@@ -178,7 +184,7 @@ class MultipleWaiter(Waiter):
# here can be impractical (see https://github.com/gevent/gevent/issues/652)
self._values = list()
def switch(self, value): # pylint:disable=signature-differs
def switch(self, value):
self._values.append(value)
Waiter.switch(self, True)
......
......@@ -9,9 +9,9 @@ from gevent._util import _NONE
from gevent._compat import reraise
from gevent._tblib import dump_traceback, load_traceback
from gevent.hub import _get_hub_noargs as get_hub
from gevent._hub_local import get_hub_noargs as get_hub
from gevent.hub import InvalidSwitchError
from gevent.exceptions import InvalidSwitchError
from gevent.timeout import Timeout
......@@ -23,8 +23,6 @@ __all__ = [
locals()['getcurrent'] = __import__('greenlet').getcurrent
locals()['greenlet_init'] = lambda: None
import cython
class _AbstractLinkable(object):
# Encapsulates the standard parts of the linking and notifying protocol
......
......@@ -7,16 +7,18 @@ from sys import _getframe as sys_getframe
from sys import exc_info as sys_exc_info
from weakref import ref as wref
# XXX: How to get cython to let us rename this as RawGreenlet
# like we prefer?
from greenlet import greenlet
from greenlet import GreenletExit
from gevent._compat import reraise
from gevent._compat import PYPY as _PYPY
from gevent._tblib import dump_traceback
from gevent._tblib import load_traceback
from gevent.hub import GreenletExit
from gevent.hub import InvalidSwitchError
from gevent.exceptions import InvalidSwitchError
from gevent.hub import iwait
from gevent.hub import wait
......@@ -875,7 +877,7 @@ def _kill(glet, exception, waiter):
# XXX do we need this here?
glet.parent.handle_error(glet, *sys_exc_info())
if waiter is not None:
waiter.switch()
waiter.switch(None)
def joinall(greenlets, timeout=None, raise_error=False, count=None):
......
This diff is collapsed.
......@@ -347,7 +347,7 @@ class Values(object):
else:
self.error = source.exception
if self.count <= 0:
self.waiter.switch()
self.waiter.switch(None)
def get(self):
self.waiter.get()
......
......@@ -18,8 +18,8 @@ from __future__ import absolute_import, print_function, division
from gevent._compat import string_types
from gevent._util import _NONE
from gevent.hub import getcurrent
from gevent.hub import _get_hub_noargs as get_hub
from greenlet import getcurrent
from gevent._hub_local import get_hub_noargs as get_hub
__all__ = [
'Timeout',
......
......@@ -77,7 +77,7 @@ from greentest.skipping import skipOnLibuvOnCIOnPyPy
from greentest.skipping import skipOnLibuvOnPyPyOnWin
from greentest.skipping import skipOnPurePython
from greentest.skipping import skipWithCExtensions
from greentest.skipping import skipOnLibuvOnTravisOnCPython27
from greentest.exception import ExpectedException
......
......@@ -49,6 +49,7 @@ skipOnLibuvOnWin = _do_not_skip
skipOnLibuvOnCI = _do_not_skip
skipOnLibuvOnCIOnPyPy = _do_not_skip
skipOnLibuvOnPyPyOnWin = _do_not_skip
skipOnLibuvOnTravisOnCPython27 = _do_not_skip
skipOnLibev = _do_not_skip
......@@ -99,6 +100,10 @@ if sysinfo.LIBUV:
skipOnLibuvOnCI = unittest.skip
if sysinfo.PYPY:
skipOnLibuvOnCIOnPyPy = unittest.skip
if sysinfo.RUNNING_ON_TRAVIS:
if sysinfo.CPYTHON:
if sysinfo.PY27_ONLY:
skipOnLibuvOnTravisOnCPython27 = unittest.skip
if sysinfo.WIN:
skipOnLibuvOnWin = unittest.skip
......
......@@ -87,6 +87,8 @@ elif sys.version_info[0] == 2:
PYPY3 = PYPY and PY3
PY27_ONLY = sys.version_info[0] == 2 and sys.version_info[1] == 7
PYGTE279 = (
sys.version_info[0] == 2
and sys.version_info[1] >= 7
......
......@@ -6,8 +6,8 @@ from gevent import backdoor
def read_until(conn, postfix):
read = b''
if not isinstance(postfix, bytes):
postfix = postfix.encode('utf-8')
assert isinstance(postfix, bytes)
while not read.endswith(postfix):
result = conn.recv(1)
if not result:
......@@ -53,7 +53,9 @@ class Test(greentest.TestCase):
conn.close()
self.close_on_teardown.remove(conn)
@greentest.skipOnAppVeyor("Times out")
@greentest.skipOnLibuvOnTravisOnCPython27(
"segfaults; "
"See https://github.com/gevent/gevent/pull/1156")
def test_multi(self):
self._make_server()
......@@ -100,7 +102,7 @@ class Test(greentest.TestCase):
conn = self._create_connection()
read_until(conn, b'>>> ')
conn.sendall(b'locals()["__builtins__"]\r\n')
response = read_until(conn, '>>> ')
response = read_until(conn, b'>>> ')
self.assertTrue(len(response) < 300, msg="locals() unusable: %s..." % response)
self._close(conn)
......@@ -123,7 +125,7 @@ class Test(greentest.TestCase):
conn = self._create_connection()
read_until(conn, b'>>> ')
conn.sendall(b'bad()\r\n')
response = read_until(conn, '>>> ')
response = read_until(conn, b'>>> ')
response = response.replace('\r\n', '\n')
self.assertEqual('switching out, then throwing in\nGot Empty\nswitching out\nswitched in\n>>> ', response)
......
......@@ -208,8 +208,8 @@ class TestReturn_link(LinksTestCase):
self.assertFalse(p)
self.assertIsInstance(event.get(), greenlet.GreenletExit)
self.assertIsInstance(queue.get().get(), greenlet.GreenletExit)
self.assertIsInstance(event.get(), gevent.GreenletExit)
self.assertIsInstance(queue.get().get(), gevent.GreenletExit)
sleep(DELAY)
self.assertFalse(callback_flag)
......
......@@ -95,7 +95,7 @@ class TestWaiterGet(greentest.timing.AbstractGenericWaitTestCase):
def wait(self, timeout):
with get_hub().loop.timer(timeout) as evt:
evt.start(self.waiter.switch)
evt.start(self.waiter.switch, None)
return self.waiter.get()
......
......@@ -408,25 +408,15 @@ class TestFunctions(greentest.TestCase):
# Issue #635
import gevent.socket
import gevent._socketcommon
orig_get_hub = gevent.socket.get_hub
class get_hub(object):
def wait(self, _io):
gevent.sleep(10)
class io(object):
callback = None
gevent._socketcommon.get_hub = get_hub
try:
try:
def start(self, *_args):
gevent.sleep(10)
with self.assertRaises(gevent.socket.timeout):
gevent.socket.wait(io(), timeout=0.01)
except gevent.socket.timeout:
pass
else:
self.fail("Should raise timeout error")
finally:
gevent._socketcommon.get_hub = orig_get_hub
def test_signatures(self):
......
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