Commit 5c27926c authored by Denis Bilenko's avatar Denis Bilenko

reimplement loop.run_callback

now run_callback is based on a list and a single prepare watcher

- remove loop.callback
- update sleep(0) to use run_callback (and to truly switch to other greenlets)
- updated related tests
parent 357cccea
......@@ -37,7 +37,7 @@ class Semaphore(object):
self._start_notify()
def _start_notify(self):
if self._links and self.counter > 0 and (self._notifier is None or not self._notifier.active):
if self._links and self.counter > 0 and not self._notifier:
self._notifier = get_hub().loop.run_callback(self._notify_links)
def _notify_links(self):
......
......@@ -134,6 +134,45 @@ end:
}
static void gevent_call(struct PyGeventLoopObject* loop, struct PyGeventCallbackObject* cb) {
GIL_DECLARE;
PyObject *result, *callback, *args;
GIL_ENSURE;
if (!loop || !cb)
return;
callback = cb->callback;
args = cb->args;
if (!callback || !args)
return;
if (callback == Py_None || args == Py_None)
return;
Py_INCREF(loop);
Py_INCREF(callback);
Py_INCREF(args);
Py_INCREF(Py_None);
Py_DECREF(cb->callback);
cb->callback = Py_None;
result = PyObject_Call(callback, args, NULL);
if (result) {
Py_DECREF(result);
}
else {
gevent_handle_error(loop, cb);
}
Py_INCREF(Py_None);
Py_DECREF(cb->args);
cb->args = Py_None;
Py_DECREF(callback);
Py_DECREF(args);
Py_DECREF(loop);
GIL_RELEASE;
}
#undef DEFINE_CALLBACK
#define DEFINE_CALLBACK(WATCHER_LC, WATCHER_TYPE) \
static void gevent_callback_##WATCHER_LC(struct ev_loop *_loop, void *c_watcher, int revents) { \
......@@ -145,10 +184,23 @@ end:
DEFINE_CALLBACKS
static void gevent_signal_check(struct ev_loop *_loop, void *watcher, int revents) {
static void gevent_run_callbacks(struct ev_loop *_loop, void *watcher, int revents) {
struct PyGeventLoopObject* loop;
PyObject *result;
GIL_DECLARE;
GIL_ENSURE;
gevent_check_signals(GET_OBJECT(PyGeventLoopObject, watcher, _signal_checker));
loop = GET_OBJECT(PyGeventLoopObject, watcher, _signal_checker);
Py_INCREF(loop);
gevent_check_signals(loop);
result = ((struct __pyx_vtabstruct_6gevent_4core_loop *)loop->__pyx_vtab)->_run_callbacks(loop);
if (result) {
Py_DECREF(result);
}
else {
PyErr_Print();
PyErr_Clear();
}
Py_DECREF(loop);
GIL_RELEASE;
}
......
......@@ -29,9 +29,11 @@
DEFINE_CALLBACKS
static void gevent_signal_check(struct ev_loop *, void *, int);
static void gevent_run_callbacks(struct ev_loop *, void *, int);
struct PyGeventLoopObject;
static void gevent_handle_error(struct PyGeventLoopObject* loop, PyObject* context);
struct PyGeventCallbackObject;
static void gevent_call(struct PyGeventLoopObject* loop, struct PyGeventCallbackObject* cb);
#if defined(_WIN32)
static void gevent_periodic_signal_check(struct ev_loop *, void *, int);
......
......@@ -28,8 +28,9 @@ cdef extern from "callbacks.h":
void gevent_callback_async(libev.ev_loop, void*, int)
void gevent_callback_child(libev.ev_loop, void*, int)
void gevent_callback_stat(libev.ev_loop, void*, int)
void gevent_signal_check(libev.ev_loop, void*, int)
void gevent_run_callbacks(libev.ev_loop, void*, int)
void gevent_periodic_signal_check(libev.ev_loop, void*, int)
void gevent_call(object, object)
cdef extern from *:
int errno
......@@ -226,6 +227,7 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
cdef libev.ev_loop* _ptr
cdef public object error_handler
cdef libev.ev_prepare _signal_checker
cdef public list _callbacks
#ifdef _WIN32
cdef libev.ev_timer _periodic_signal_checker
#endif
......@@ -233,7 +235,7 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
def __init__(self, object flags=None, object default=True, size_t ptr=0):
cdef unsigned int c_flags
cdef object old_handler = None
libev.ev_prepare_init(&self._signal_checker, <void*>gevent_signal_check)
libev.ev_prepare_init(&self._signal_checker, <void*>gevent_run_callbacks)
#ifdef _WIN32
libev.ev_timer_init(&self._periodic_signal_checker, <void*>gevent_periodic_signal_check, 0.3, 0.3)
#endif
......@@ -261,8 +263,19 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
raise SystemError("ev_loop_new(%s) failed" % (c_flags, ))
if default or __SYSERR_CALLBACK is None:
set_syserr_cb(self._handle_syserr)
self._callbacks = []
cdef _run_callbacks(self):
cdef callback cb
cdef object callbacks
while self._callbacks:
callbacks = self._callbacks
self._callbacks = []
for cb in callbacks:
libev.ev_unref(self._ptr)
gevent_call(self, cb)
def _stop_signal_checker(self):
def _stop_watchers(self):
if libev.ev_is_active(&self._signal_checker):
libev.ev_ref(self._ptr)
libev.ev_prepare_stop(self._ptr, &self._signal_checker)
......@@ -275,7 +288,7 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
def destroy(self):
global _default_loop_destroyed
if self._ptr:
self._stop_signal_checker()
self._stop_watchers()
if __SYSERR_CALLBACK == self._handle_syserr:
set_syserr_cb(None)
if libev.ev_is_default_loop(self._ptr):
......@@ -285,7 +298,7 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
def __dealloc__(self):
if self._ptr:
self._stop_signal_checker()
self._stop_watchers()
if not libev.ev_is_default_loop(self._ptr):
libev.ev_loop_destroy(self._ptr)
self._ptr = NULL
......@@ -326,7 +339,6 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
cpdef _default_handle_error(self, context, type, value, tb):
# note: Hub sets its own error handler so this is not used by gevent
# this is here to make core.loop usable without the rest of gevent
import traceback
traceback.print_exception(type, value, tb)
libev.ev_break(self._ptr, libev.EVBREAK_ONE)
......@@ -432,13 +444,11 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
def stat(self, bytes path, float interval=0.0, ref=True, priority=None):
return stat(self, path, interval, ref, priority)
def callback(self, priority=None):
return callback(self, priority)
def run_callback(self, func, *args, priority=None):
cdef callback result = callback(self, priority)
result.start(func, *args)
return result
def run_callback(self, func, *args):
cdef callback cb = callback(func, args)
self._callbacks.append(cb)
libev.ev_ref(self._ptr)
return cb
def _format(self):
cdef object msg = self.backend
......@@ -497,6 +507,54 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
#endif
cdef public class callback [object PyGeventCallbackObject, type PyGeventCallback_Type]:
cdef public object callback
cdef public tuple args
def __init__(self, callback, args):
self.callback = callback
self.args = args
def stop(self):
self.callback = None
self.args = None
# Note, that __nonzero__ and pending are different
# nonzero is used in contexts where we need to know whether to schedule another callback,
# so it's true if it's pending or currently running
# 'pending' has the same meaning as libev watchers: it is cleared before entering callback
def __nonzero__(self):
# it's nonzero if it's pending or currently executing
return self.args is not None
property pending:
def __get__(self):
return self.callback is not None
def __repr__(self):
if Py_ReprEnter(<PyObjectPtr>self) != 0:
return "<...>"
try:
format = self._format()
result = "<yy %s at 0x%x%s" % (self.__class__.__name__, id(self), format)
if self.pending:
result += " pending"
if self.callback is not None:
result += " callback=%r" % (self.callback, )
if self.args is not None:
result += " args=%r" % (self.args, )
if self.callback is None and self.args is None:
result += " stopped"
return result + ">"
finally:
Py_ReprLeave(<PyObjectPtr>self)
def _format(self):
return ''
#define PYTHON_INCREF if not self._flags & 1: \
Py_INCREF(<PyObjectPtr>self) \
self._flags |= 1
......@@ -932,30 +990,6 @@ cdef public class stat(watcher) [object PyGeventStatObject, type PyGeventStat_Ty
return self._watcher.interval
cdef public class callback(watcher) [object PyGeventCallbackObject, type PyGeventCallback_Type]:
"""Pseudo-watcher used to execute a callback in the loop as soon as possible."""
# does not matter which type we actually use, since we are going to feed() events, not start watchers
WATCHER_BASE(prepare)
INIT(prepare,,)
def start(self, object callback, *args):
if callback is None:
raise TypeError('callback must be callable, not None')
self.callback = callback
self.args = args
libev.ev_feed_event(self.loop._ptr, &self._watcher, libev.EV_CUSTOM)
PYTHON_INCREF
property active:
def __get__(self):
return self.callback is not None
PENDING
__SYSERR_CALLBACK = None
......
......@@ -4,6 +4,7 @@
import sys
from gevent.hub import get_hub, getcurrent, _NONE, PY3
from gevent.timeout import Timeout
from collections import deque
if PY3:
xrange = range
......@@ -24,7 +25,7 @@ class Event(object):
self._todo = set()
self._flag = False
self.hub = get_hub()
self._notifier = self.hub.loop.callback()
self._notifier = None
def __str__(self):
return '<%s %s _links[%s]>' % (self.__class__.__name__, (self._flag and 'set') or 'clear', len(self._links))
......@@ -42,9 +43,8 @@ class Event(object):
"""
self._flag = True
self._todo.update(self._links)
if self._todo and not self._notifier.active:
# schedule a job to notify the links already set
self._notifier.start(self._notify_links)
if self._todo and not self._notifier:
self._notifier = self.hub.loop.run_callback(self._notify_links)
def clear(self):
"""Reset the internal flag to false.
......@@ -95,9 +95,9 @@ class Event(object):
if not callable(callback):
raise TypeError('Expected callable: %r' % (callback, ))
self._links.add(callback)
if self._flag and not self._notifier.active:
if self._flag and not self._notifier:
self._todo.add(callback)
self._notifier.start(self._notify_links)
self._notifier = self.hub.loop.run_callback(self._notify_links)
def unlink(self, callback):
"""Remove the callback set by :meth:`rawlink`"""
......@@ -150,11 +150,11 @@ class AsyncResult(object):
ZeroDivisionError: integer division or modulo by zero
"""
def __init__(self):
self._links = set()
self._links = deque()
self.value = None
self._exception = _NONE
self.hub = get_hub()
self._notifier = self.hub.loop.callback()
self._notifier = None
def __str__(self):
result = '<%s ' % (self.__class__.__name__, )
......@@ -189,8 +189,8 @@ class AsyncResult(object):
"""
self.value = value
self._exception = None
if self._links and not self._notifier.active:
self._notifier.start(self._notify_links)
if self._links and not self._notifier:
self._notifier = self.hub.loop.run_callback(self._notify_links)
def set_exception(self, exception):
"""Store the exception. Wake up the waiters.
......@@ -199,8 +199,8 @@ class AsyncResult(object):
Sequential calls to :meth:`wait` and :meth:`get` will not block at all.
"""
self._exception = exception
if self._links and not self._notifier.active:
self._notifier.start(self._notify_links)
if self._links and not self._notifier:
self._notifier = self.hub.loop.run_callback(self._notify_links)
def get(self, block=True, timeout=None):
"""Return the stored value or raise the exception.
......@@ -282,7 +282,7 @@ class AsyncResult(object):
def _notify_links(self):
while self._links:
link = self._links.pop()
link = self._links.popleft()
try:
link(self)
except:
......@@ -296,13 +296,16 @@ class AsyncResult(object):
"""
if not callable(callback):
raise TypeError('Expected callable: %r' % (callback, ))
self._links.add(callback)
if self.ready() and not self._notifier.active:
self._notifier.start(self._notify_links)
self._links.append(callback)
if self.ready() and not self._notifier:
self._notifier = self.hub.loop.run_callback(self._notify_links)
def unlink(self, callback):
"""Remove the callback set by :meth:`rawlink`"""
self._links.discard(callback)
try:
self._links.remove(callback)
except ValueError:
pass
# link protocol
def __call__(self, source):
......
......@@ -82,7 +82,7 @@ class Greenlet(greenlet):
self.value = None
self._exception = _NONE
loop = hub.loop
self._notifier = loop.callback()
self._notifier = None
self._start_event = None
@property
......@@ -185,8 +185,7 @@ class Greenlet(greenlet):
def start(self):
"""Schedule the greenlet to run in this loop iteration"""
if self._start_event is None:
self._start_event = self.parent.loop.callback()
self._start_event.start(self.switch)
self._start_event = self.parent.loop.run_callback(self.switch)
def start_later(self, seconds):
"""Schedule the greenlet to run in the future loop iteration *seconds* later"""
......@@ -304,8 +303,8 @@ class Greenlet(greenlet):
def _report_result(self, result):
self._exception = None
self.value = result
if self._links and not self._notifier.active:
self._notifier.start(self._notify_links)
if self._links and not self._notifier:
self._notifier = self.parent.loop.run_callback(self._notify_links)
def _report_error(self, exc_info):
exception = exc_info[1]
......@@ -314,8 +313,8 @@ class Greenlet(greenlet):
return
self._exception = exception
if self._links and not self._notifier.active:
self._notifier.start(self._notify_links)
if self._links and not self._notifier:
self._notifier = self.parent.loop.run_callback(self._notify_links)
self.parent.handle_error(self, *exc_info)
......@@ -344,8 +343,8 @@ class Greenlet(greenlet):
if not callable(callback):
raise TypeError('Expected callable: %r' % (callback, ))
self._links.append(callback)
if self.ready() and not self._notifier.active:
self._notifier.start(self._notify_links)
if self.ready() and self._links and not self._notifier:
self._notifier = self.parent.loop.run_callback(self._notify_links)
def link(self, receiver, SpawnedLink=SpawnedLink):
"""Link greenlet's completion to a callable.
......@@ -392,6 +391,7 @@ def _kill(greenlet, exception, waiter):
try:
greenlet.throw(exception)
except:
# XXX do we need this here?
greenlet.parent.handle_error(greenlet, *sys.exc_info())
waiter.switch()
......
......@@ -89,11 +89,11 @@ def sleep(seconds=0, ref=True):
hub = get_hub()
loop = hub.loop
if seconds <= 0:
watcher = loop.idle(ref=ref)
watcher.priority = loop.MAXPRI
waiter = Waiter()
loop.run_callback(waiter.switch)
waiter.get()
else:
watcher = loop.timer(seconds, ref=ref)
hub.wait(watcher)
hub.wait(loop.timer(seconds, ref=ref))
def idle(priority=0):
......
......@@ -9,6 +9,7 @@ __all__ = ['Semaphore', 'DummySemaphore', 'BoundedSemaphore', 'RLock']
class DummySemaphore(object):
# XXX what is this used for?
"""A Semaphore initialized with "infinite" initial value. Neither of its methods ever block."""
def __str__(self):
......@@ -21,6 +22,7 @@ class DummySemaphore(object):
pass
def rawlink(self, callback):
# XXX should still work and notify?
pass
def unlink(self, callback):
......
......@@ -61,7 +61,7 @@ class Queue(object):
self.getters = set()
self.putters = set()
self.hub = get_hub()
self._event_unlock = self.hub.loop.callback()
self._event_unlock = None
if items:
self._init(maxsize, items)
else:
......@@ -275,13 +275,10 @@ class Queue(object):
getter.switch(getter)
if not repeat:
return
# testcase: 2 greenlets: while True: q.put(q.get()) - nothing else has a change to execute
# to avoid this, schedule unlock with timer(0, ...) once in a while
# replace 'while True' with 'for _ in xrange(100): ...; self._timer.start(self._unlock)
# but then I need _timer and self._event_unlock to play with each other
def _schedule_unlock(self):
self._event_unlock.start(self._unlock)
if not self._event_unlock:
self._event_unlock = self.hub.loop.run_callback(self._unlock)
def __iter__(self):
return self
......@@ -401,7 +398,7 @@ class Channel(object):
self.getters = collections.deque()
self.putters = collections.deque()
self.hub = get_hub()
self._event_unlock = self.hub.loop.callback()
self._event_unlock = None
def __repr__(self):
return '<%s at %s %s>' % (type(self).__name__, hex(id(self)), self._format())
......@@ -499,7 +496,8 @@ class Channel(object):
putter.switch(putter)
def _schedule_unlock(self):
self._event_unlock.start(self._unlock)
if not self._event_unlock:
self._event_unlock = self.hub.loop.run_callback(self._unlock)
def __iter__(self):
return self
......
......@@ -133,10 +133,15 @@ disabled_tests = \
, 'test_thread.ThreadRunningTests.test__count'
# XXX
, 'test_threading.ThreadedTests.test_ident_of_no_threading_threads'
, 'test_threading.ThreadedTests.test_foreign_thread'
# XXX remove these:
#, 'test_threading.ThreadedTests.test_ident_of_no_threading_threads'
#, 'test_threading.ThreadedTests.test_foreign_thread'
# this assert that dummy thread id is in threading._active
# however, we clean that up
, 'test_urllib2net.OtherNetworkTests.test_urlwithfrag'
# fails dues to some changes on python.org
]
# if 'signalfd' in os.environ.get('GEVENT_BACKEND', ''):
......
......@@ -65,10 +65,8 @@ class Test(greentest.TestCase):
def _test_wait_read_invalid_switch(self, sleep):
sock1, sock2 = socket.socketpair()
try:
lst = []
gevent.get_hub().loop.run_callback(switch_None, lst)
p = gevent.spawn(util.wrap_errors(AssertionError, socket.wait_read), sock1.fileno())
lst.append(p)
gevent.get_hub().loop.run_callback(switch_None, p)
if sleep is not None:
gevent.sleep(sleep)
result = p.get()
......@@ -91,7 +89,7 @@ class Test(greentest.TestCase):
def switch_None(g):
g[0].switch(None)
g.switch(None)
class TestTimers(greentest.TestCase):
......
......@@ -10,23 +10,20 @@ def f():
def main():
loop = get_hub().loop
x = loop.callback()
x.start(f)
x = loop.run_callback(f)
assert x.active, x.pending
assert x, x
gevent.sleep(0)
assert x.pending == 0, x.pending
assert called == [1], called
assert not x, (x, bool(x))
x = loop.callback()
x.start(f)
assert x.pending == 1, x.pending
x = loop.run_callback(f)
assert x, x
x.stop()
assert x.pending == 0, x.pending
assert not x, x
gevent.sleep(0)
assert called == [1], called
assert x.pending == 0, x.pending
gevent.sleep(0.1)
assert not x, x
if __name__ == '__main__':
......
......@@ -70,9 +70,9 @@ class Test(greentest.TestCase):
assert len(s) == 2, s
s.kill(block=False)
assert len(s) == 2, s
gevent.sleep(0)
assert not s, s
gevent.sleep(0.0001)
assert len(s) == 0, s
assert not s, s
def test_kill_fires_once(self):
u1 = Undead()
......
......@@ -8,6 +8,6 @@ def incr():
count += 1
loop = loop()
loop.callback().start(incr)
loop.run_callback(incr)
loop.run()
assert count == 1, count
......@@ -56,8 +56,5 @@ def sleep0(lst, param):
lst.append(param + 'B')
del TestSleep0 # XXX
if __name__ == '__main__':
greentest.main()
from __future__ import with_statement
from time import time
import gevent
from gevent import pool
......@@ -7,8 +8,10 @@ import random
from greentest import ExpectedException
import six
import unittest
class TestCoroutinePool(greentest.TestCase):
class TestCoroutinePool(unittest.TestCase):
klass = pool.Pool
def test_apply_async(self):
......@@ -86,7 +89,8 @@ class TestCoroutinePool(greentest.TestCase):
try:
sys.stderr = FakeFile()
waiter = pool.spawn(crash)
self.assertRaises(RuntimeError, waiter.get)
with gevent.Timeout(2):
self.assertRaises(RuntimeError, waiter.get)
# the pool should have something free at this point since the
# waiter returned
# pool.Pool change: if an exception is raised during execution of a link,
......@@ -111,7 +115,9 @@ def crash(*args, **kw):
class FakeFile(object):
write = crash
def write(*args):
raise RuntimeError('Whaaa')
class PoolBasicTests(greentest.TestCase):
......@@ -211,6 +217,10 @@ def sqr(x, wait=0.0):
return x * x
def squared(x):
return x * x
def sqr_random_sleep(x):
gevent.sleep(random.random() * 0.1)
return x * x
......@@ -232,13 +242,13 @@ class TestPool(greentest.TestCase):
def test_apply(self):
papply = self.pool.apply
self.assertEqual(papply(sqr, (5,)), sqr(5))
self.assertEqual(papply(sqr, (), {'x': 3}), sqr(x=3))
self.assertEqual(papply(sqr, (5,)), 25)
self.assertEqual(papply(sqr, (), {'x': 3}), 9)
def test_map(self):
pmap = self.pool.map
self.assertEqual(pmap(sqr, range(10)), list(map(sqr, range(10))))
self.assertEqual(pmap(sqr, range(100)), list(map(sqr, range(100))))
self.assertEqual(pmap(sqr, range(10)), list(map(squared, range(10))))
self.assertEqual(pmap(sqr, range(100)), list(map(squared, range(100))))
def test_async(self):
res = self.pool.apply_async(sqr, (7, TIMEOUT1,))
......@@ -264,7 +274,7 @@ class TestPool(greentest.TestCase):
def test_imap(self):
it = self.pool.imap(sqr, range(10))
self.assertEqual(list(it), list(map(sqr, range(10))))
self.assertEqual(list(it), list(map(squared, range(10))))
it = self.pool.imap(sqr, range(10))
for i in range(10):
......@@ -278,18 +288,18 @@ class TestPool(greentest.TestCase):
def test_imap_random(self):
it = self.pool.imap(sqr_random_sleep, range(10))
self.assertEqual(list(it), list(map(sqr, range(10))))
self.assertEqual(list(it), list(map(squared, range(10))))
def test_imap_unordered(self):
it = self.pool.imap_unordered(sqr, range(1000))
self.assertEqual(sorted(it), list(map(sqr, range(1000))))
self.assertEqual(sorted(it), list(map(squared, range(1000))))
it = self.pool.imap_unordered(sqr, range(1000))
self.assertEqual(sorted(it), list(map(sqr, range(1000))))
self.assertEqual(sorted(it), list(map(squared, range(1000))))
def test_imap_unordered_random(self):
it = self.pool.imap_unordered(sqr_random_sleep, range(10))
self.assertEqual(sorted(it), list(map(sqr, range(10))))
self.assertEqual(sorted(it), list(map(squared, range(10))))
def test_empty(self):
it = self.pool.imap_unordered(sqr, [])
......
......@@ -298,11 +298,11 @@ class TestNoWait(TestCase):
assert q.empty(), q
assert q.full(), q
gevent.sleep(0)
gevent.sleep(0.001)
assert q.empty(), q
assert q.full(), q
get_hub().loop.run_callback(store_result, q.get_nowait)
gevent.sleep(0)
gevent.sleep(0.001)
assert q.empty(), q
assert q.full(), q
assert result == [5], result
......@@ -321,12 +321,12 @@ class TestNoWait(TestCase):
assert q.empty(), q
assert not q.full(), q
gevent.sleep(0)
gevent.sleep(0.001)
assert q.empty(), q
assert not q.full(), q
get_hub().loop.run_callback(store_result, q.put_nowait, 10)
assert not p.ready(), p
gevent.sleep(0)
gevent.sleep(0.001)
assert result == [None], result
assert p.ready(), p
assert not q.full(), q
......
......@@ -64,7 +64,7 @@ class Settings:
class TestCase(greentest.TestCase):
__timeout__ = 10
__timeout__ = 5
def cleanup(self):
if getattr(self, 'server', None) is not None:
......@@ -78,7 +78,8 @@ class TestCase(greentest.TestCase):
return sock
def makefile(self, timeout=0.1, bufsize=1):
sock = socket.create_connection((self.server.server_host, self.server.server_port))
sock = socket.socket()
sock.connect((self.server.server_host, self.server.server_port))
fobj = sock.makefile(bufsize=bufsize)
fobj._sock.settimeout(timeout)
return fobj
......
......@@ -48,15 +48,11 @@ class Test(greentest.TestCase):
class TestCallback(Test):
def setUp(self):
super(TestCallback, self).setUp()
self.x = get_hub().loop.callback()
def tearDown(self):
assert not self.x.pending, self.x
def start(self, *args):
self.x.start(*args)
self.x = get_hub().loop.run_callback(*args)
class TestSpawn(Test):
......
......@@ -144,9 +144,7 @@ class ThreadTests(unittest.TestCase):
done.wait()
self.assertFalse(ident[0] is None)
# Kill the "immortal" _DummyThread
# in gevent, we already cleaned that up
#del threading._active[ident[0]]
assert ident[0] not in threading._active
del threading._active[ident[0]]
# run with a small(ish) thread stack size (256kB)
def test_various_ops_small_stack(self):
......@@ -187,12 +185,11 @@ class ThreadTests(unittest.TestCase):
tid = thread.start_new_thread(f, (mutex,))
# Wait for the thread to finish.
mutex.acquire()
# in gevent, we clean up the entry, so the following fails:
#self.assert_(tid in threading._active)
#self.assert_(isinstance(threading._active[tid],
# threading._DummyThread))
#del threading._active[tid]
self.assert_(tid not in threading._active)
self.assert_(tid in threading._active)
self.assert_(isinstance(threading._active[tid],
threading._DummyThread))
del threading._active[tid]
# in gevent, we actually clean up threading._active, but it's not happended there yet
# PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently)
# exposed at the Python level. This test relies on ctypes to get at it.
......
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