Commit d7b8b4e8 authored by Jason Madden's avatar Jason Madden

Support non-indexable containers for killall. Fixes #404.

parent 4b59a304
......@@ -51,6 +51,9 @@ Unreleased
:issue:`230` by Lx Yu.
- Fork watchers are more likely to (eventually) get called in a
multi-threaded program.
- ``gevent.killall`` accepts an arbitrary iterable for the greenlets
to kill. Reported in :issue:`404` by Martin Bachwerk; seen in
combination with older versions of simple-requests.
1.1a1 (Jun 29, 2015)
====================
......
......@@ -454,7 +454,7 @@ def joinall(greenlets, timeout=None, raise_error=False, count=None):
"""
Wait for the ``greenlets`` to finish.
:param greenlets: A sequence of greenlets to wait for.
:param greenlets: A sequence (supporting :func:`len`) of greenlets to wait for.
:keyword float timeout: If given, the maximum number of seconds to wait.
:return: A sequence of the greenlets that finished before the timeout (if any)
expired.
......@@ -496,6 +496,26 @@ def _killall(greenlets, exception):
def killall(greenlets, exception=GreenletExit, block=True, timeout=None):
"""
Forceably terminate all the ``greenlets`` by causing them to raise ``exception``.
:param greenlets: A bounded iterable of the non-None greenlets to terminate.
*All* the items in this iterable must be greenlets that belong to the same thread.
:keyword exception: The exception to raise in the greenlets. By default this is
:class:`GreenletExit`.
:keyword bool block: If True (the default) then this function only returns when all the
greenlets are dead; the current greenlet is unscheduled during that process.
If greenlets ignore the initial exception raised in them,
then they will be joined (with :func:`gevent.joinall`) and allowed to die naturally.
If False, this function returns immediately and greenlets will raise
the exception asynchronously.
:keyword float timeout: A time in seconds to wait for greenlets to die. If given, it is
only honored when ``block`` is True.
:raises Timeout: If blocking and a timeout is given that elapses before
all the greenlets are dead.
"""
# support non-indexable containers like iterators or set objects
greenlets = list(greenlets)
if not greenlets:
return
loop = greenlets[0].loop
......
......@@ -150,6 +150,9 @@ class signal(object):
def reinit():
# An internal, undocumented function. Called by gevent.os.fork
# in the child process. The loop reinit function in turn calls
# libev's ev_loop_fork function.
hub = _get_hub()
if hub is not None:
hub.loop.reinit()
......@@ -659,7 +662,7 @@ def iwait(objects, timeout=None, count=None):
"""
Yield objects as they are ready, until all (or `count`) are ready or `timeout` expired.
:param objects: A list (supporting `len`) containing objects
:param objects: A sequence (supporting :func:`len`) containing objects
implementing the wait protocol (rawlink() and unlink()).
:param count: If not `None`, then a number specifying the maximum number
of objects to wait for.
......@@ -718,7 +721,7 @@ def wait(objects=None, timeout=None, count=None):
- all servers were stopped
- all event loop watchers were stopped.
If ``count`` is ``None`` (the default), wait for all ``object``s
If ``count`` is ``None`` (the default), wait for all ``objects``
to become ready.
If ``count`` is a number, wait for (up to) ``count`` objects to become
......
......@@ -2,6 +2,7 @@ import time
import greentest
import gevent
from gevent import pool
from gevent.timeout import Timeout
DELAY = 0.1
......@@ -121,6 +122,36 @@ class Test(greentest.TestCase):
s = pool.Group([p1, p2])
s.kill()
def test_killall_iterable_argument_non_block(self):
p1 = GreenletSubclass.spawn(lambda: gevent.sleep(0.5))
p2 = GreenletSubclass.spawn(lambda: gevent.sleep(0.5))
s = set()
s.add(p1)
s.add(p2)
gevent.killall(s, block=False)
gevent.sleep(0.5)
for g in s:
assert g.dead
def test_killall_iterable_argument_timeout(self):
def f():
try:
gevent.sleep(1.5)
except:
gevent.sleep(1)
p1 = GreenletSubclass.spawn(f)
p2 = GreenletSubclass.spawn(f)
s = set()
s.add(p1)
s.add(p2)
try:
gevent.killall(s, timeout=0.5)
except Timeout:
for g in s:
assert not g.dead
else:
self.fail("Should raise timeout")
class GreenletSubclass(gevent.Greenlet):
pass
......
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