1# Copyright (c) 2009-2016 Denis Bilenko, gevent contributors. See LICENSE for details.
2# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False,infer_types=True
3
4"""Basic synchronization primitives: Event and AsyncResult"""
5from __future__ import print_function
6
7from gevent._util import _NONE
8from gevent._compat import reraise
9from gevent._tblib import dump_traceback, load_traceback
10
11from gevent.timeout import Timeout
12
13
14__all__ = [
15    'Event',
16    'AsyncResult',
17]
18
19def _get_linkable():
20    x = __import__('gevent._abstract_linkable')
21    return x._abstract_linkable.AbstractLinkable
22locals()['AbstractLinkable'] = _get_linkable()
23del _get_linkable
24
25
26class Event(AbstractLinkable): # pylint:disable=undefined-variable
27    """
28    A synchronization primitive that allows one greenlet to wake up
29    one or more others. It has the same interface as
30    :class:`threading.Event` but works across greenlets.
31
32    .. important::
33       This object is for communicating among greenlets within the
34       same thread *only*! Do not try to use it to communicate across threads.
35
36    An event object manages an internal flag that can be set to true
37    with the :meth:`set` method and reset to false with the
38    :meth:`clear` method. The :meth:`wait` method blocks until the
39    flag is true; as soon as the flag is set to true, all greenlets
40    that are currently blocked in a call to :meth:`wait` will be scheduled
41    to awaken.
42
43    Note that the flag may be cleared and set many times before
44    any individual greenlet runs; all the greenlet can know for sure is that the
45    flag was set *at least once* while it was waiting.
46    If the greenlet cares whether the flag is still
47    set, it must check with :meth:`ready` and possibly call back into
48    :meth:`wait` again.
49
50    .. note::
51
52        The exact order and timing in which waiting greenlets are awakened is not determined.
53
54        Once the event is set, other greenlets may run before any waiting greenlets
55        are awakened.
56
57        While the code here will awaken greenlets in the order in which they
58        waited, each such greenlet that runs may in turn cause other greenlets
59        to run.
60
61        These details may change in the future.
62
63    .. versionchanged:: 1.5a3
64
65        Waiting greenlets are now awakened in
66        the order in which they waited.
67
68    .. versionchanged:: 1.5a3
69
70        The low-level ``rawlink`` method (most users won't use this) now
71        automatically unlinks waiters before calling them.
72
73    .. versionchanged:: 20.5.1
74
75        Callers to ``wait`` that find the event already set will now run
76        after any other waiters that had to block. See :issue:`1520`.
77    """
78
79    __slots__ = ('_flag',)
80
81    def __init__(self):
82        super(Event, self).__init__()
83        self._flag = False
84
85    def __str__(self):
86        return '<%s %s _links[%s]>' % (
87            self.__class__.__name__,
88            'set' if self._flag else 'clear',
89            self.linkcount()
90        )
91
92    def is_set(self):
93        """Return true if and only if the internal flag is true."""
94        return self._flag
95
96    def isSet(self):
97        # makes it a better drop-in replacement for threading.Event
98        return self._flag
99
100    def ready(self):
101        # makes it compatible with AsyncResult and Greenlet (for
102        # example in wait())
103        return self._flag
104
105    def set(self):
106        """
107        Set the internal flag to true.
108
109        All greenlets waiting for it to become true are awakened in
110        some order at some time in the future. Greenlets that call
111        :meth:`wait` once the flag is true will not block at all
112        (until :meth:`clear` is called).
113        """
114        self._flag = True
115        self._check_and_notify()
116
117    def clear(self):
118        """
119        Reset the internal flag to false.
120
121        Subsequently, threads calling :meth:`wait` will block until
122        :meth:`set` is called to set the internal flag to true again.
123        """
124        self._flag = False
125
126    def _wait_return_value(self, waited, wait_success):
127        # To avoid the race condition outlined in http://bugs.python.org/issue13502,
128        # if we had to wait, then we need to return whether or not
129        # the condition got changed. Otherwise we simply echo
130        # the current state of the flag (which should be true)
131        if not waited:
132            flag = self._flag
133            assert flag, "if we didn't wait we should already be set"
134            return flag
135
136        return wait_success
137
138    def wait(self, timeout=None):
139        """
140        Block until this object is :meth:`ready`.
141
142        If the internal flag is true on entry, return immediately. Otherwise,
143        block until another thread (greenlet) calls :meth:`set` to set the flag to true,
144        or until the optional *timeout* expires.
145
146        When the *timeout* argument is present and not ``None``, it should be a
147        floating point number specifying a timeout for the operation in seconds
148        (or fractions thereof).
149
150        :return: This method returns true if and only if the internal flag has been set to
151            true, either before the wait call or after the wait starts, so it will
152            always return ``True`` except if a timeout is given and the operation
153            times out.
154
155        .. versionchanged:: 1.1
156            The return value represents the flag during the elapsed wait, not
157            just after it elapses. This solves a race condition if one greenlet
158            sets and then clears the flag without switching, while other greenlets
159            are waiting. When the waiters wake up, this will return True; previously,
160            they would still wake up, but the return value would be False. This is most
161            noticeable when the *timeout* is present.
162        """
163        return self._wait(timeout)
164
165    def _reset_internal_locks(self): # pragma: no cover
166        # for compatibility with threading.Event
167        #  Exception AttributeError: AttributeError("'Event' object has no attribute '_reset_internal_locks'",)
168        # in <module 'threading' from '/usr/lib/python2.7/threading.pyc'> ignored
169        pass
170
171
172class AsyncResult(AbstractLinkable): # pylint:disable=undefined-variable
173    """
174    A one-time event that stores a value or an exception.
175
176    Like :class:`Event` it wakes up all the waiters when :meth:`set`
177    or :meth:`set_exception` is called. Waiters may receive the passed
178    value or exception by calling :meth:`get` instead of :meth:`wait`.
179    An :class:`AsyncResult` instance cannot be reset.
180
181    .. important::
182       This object is for communicating among greenlets within the
183       same thread *only*! Do not try to use it to communicate across threads.
184
185    To pass a value call :meth:`set`. Calls to :meth:`get` (those that
186    are currently blocking as well as those made in the future) will
187    return the value::
188
189        >>> from gevent.event import AsyncResult
190        >>> result = AsyncResult()
191        >>> result.set(100)
192        >>> result.get()
193        100
194
195    To pass an exception call :meth:`set_exception`. This will cause
196    :meth:`get` to raise that exception::
197
198        >>> result = AsyncResult()
199        >>> result.set_exception(RuntimeError('failure'))
200        >>> result.get()
201        Traceback (most recent call last):
202         ...
203        RuntimeError: failure
204
205    :class:`AsyncResult` implements :meth:`__call__` and thus can be
206    used as :meth:`link` target::
207
208        >>> import gevent
209        >>> result = AsyncResult()
210        >>> gevent.spawn(lambda : 1/0).link(result)
211        >>> try:
212        ...     result.get()
213        ... except ZeroDivisionError:
214        ...     print('ZeroDivisionError')
215        ZeroDivisionError
216
217    .. note::
218
219        The order and timing in which waiting greenlets are awakened is not determined.
220        As an implementation note, in gevent 1.1 and 1.0, waiting greenlets are awakened in a
221        undetermined order sometime *after* the current greenlet yields to the event loop. Other greenlets
222        (those not waiting to be awakened) may run between the current greenlet yielding and
223        the waiting greenlets being awakened. These details may change in the future.
224
225    .. versionchanged:: 1.1
226
227       The exact order in which waiting greenlets
228       are awakened is not the same as in 1.0.
229
230    .. versionchanged:: 1.1
231
232       Callbacks :meth:`linked <rawlink>` to this object are required to
233       be hashable, and duplicates are merged.
234
235    .. versionchanged:: 1.5a3
236
237       Waiting greenlets are now awakened in the order in which they
238       waited.
239
240    .. versionchanged:: 1.5a3
241
242       The low-level ``rawlink`` method
243       (most users won't use this) now automatically unlinks waiters
244       before calling them.
245    """
246
247    __slots__ = ('_value', '_exc_info', '_imap_task_index')
248
249    def __init__(self):
250        super(AsyncResult, self).__init__()
251        self._value = _NONE
252        self._exc_info = ()
253
254    @property
255    def _exception(self):
256        return self._exc_info[1] if self._exc_info else _NONE
257
258    @property
259    def value(self):
260        """
261        Holds the value passed to :meth:`set` if :meth:`set` was called. Otherwise,
262        ``None``
263        """
264        return self._value if self._value is not _NONE else None
265
266    @property
267    def exc_info(self):
268        """
269        The three-tuple of exception information if :meth:`set_exception` was called.
270        """
271        if self._exc_info:
272            return (self._exc_info[0], self._exc_info[1], load_traceback(self._exc_info[2]))
273        return ()
274
275    def __str__(self):
276        result = '<%s ' % (self.__class__.__name__, )
277        if self.value is not None or self._exception is not _NONE:
278            result += 'value=%r ' % self.value
279        if self._exception is not None and self._exception is not _NONE:
280            result += 'exception=%r ' % self._exception
281        if self._exception is _NONE:
282            result += 'unset '
283        return result + ' _links[%s]>' % self.linkcount()
284
285    def ready(self):
286        """Return true if and only if it holds a value or an exception"""
287        return self._exc_info or self._value is not _NONE
288
289    def successful(self):
290        """Return true if and only if it is ready and holds a value"""
291        return self._value is not _NONE
292
293    @property
294    def exception(self):
295        """Holds the exception instance passed to :meth:`set_exception` if :meth:`set_exception` was called.
296        Otherwise ``None``."""
297        if self._exc_info:
298            return self._exc_info[1]
299
300    def set(self, value=None):
301        """Store the value and wake up any waiters.
302
303        All greenlets blocking on :meth:`get` or :meth:`wait` are awakened.
304        Subsequent calls to :meth:`wait` and :meth:`get` will not block at all.
305        """
306        self._value = value
307        self._check_and_notify()
308
309    def set_exception(self, exception, exc_info=None):
310        """Store the exception and wake up any waiters.
311
312        All greenlets blocking on :meth:`get` or :meth:`wait` are awakened.
313        Subsequent calls to :meth:`wait` and :meth:`get` will not block at all.
314
315        :keyword tuple exc_info: If given, a standard three-tuple of type, value, :class:`traceback`
316            as returned by :func:`sys.exc_info`. This will be used when the exception
317            is re-raised to propagate the correct traceback.
318        """
319        if exc_info:
320            self._exc_info = (exc_info[0], exc_info[1], dump_traceback(exc_info[2]))
321        else:
322            self._exc_info = (type(exception), exception, dump_traceback(None))
323
324        self._check_and_notify()
325
326    def _raise_exception(self):
327        reraise(*self.exc_info)
328
329    def get(self, block=True, timeout=None):
330        """Return the stored value or raise the exception.
331
332        If this instance already holds a value or an exception, return  or raise it immediately.
333        Otherwise, block until another greenlet calls :meth:`set` or :meth:`set_exception` or
334        until the optional timeout occurs.
335
336        When the *timeout* argument is present and not ``None``, it should be a
337        floating point number specifying a timeout for the operation in seconds
338        (or fractions thereof). If the *timeout* elapses, the *Timeout* exception will
339        be raised.
340
341        :keyword bool block: If set to ``False`` and this instance is not ready,
342            immediately raise a :class:`Timeout` exception.
343        """
344        if self._value is not _NONE:
345            return self._value
346        if self._exc_info:
347            return self._raise_exception()
348
349        if not block:
350            # Not ready and not blocking, so immediately timeout
351            raise Timeout()
352
353        self._capture_hub(True)
354
355        # Wait, raising a timeout that elapses
356        self._wait_core(timeout, ())
357
358        # by definition we are now ready
359        return self.get(block=False)
360
361    def get_nowait(self):
362        """
363        Return the value or raise the exception without blocking.
364
365        If this object is not yet :meth:`ready <ready>`, raise
366        :class:`gevent.Timeout` immediately.
367        """
368        return self.get(block=False)
369
370    def _wait_return_value(self, waited, wait_success):
371        # pylint:disable=unused-argument
372        # Always return the value. Since this is a one-shot event,
373        # no race condition should reset it.
374        return self.value
375
376    def wait(self, timeout=None):
377        """Block until the instance is ready.
378
379        If this instance already holds a value, it is returned immediately. If this
380        instance already holds an exception, ``None`` is returned immediately.
381
382        Otherwise, block until another greenlet calls :meth:`set` or :meth:`set_exception`
383        (at which point either the value or ``None`` will be returned, respectively),
384        or until the optional timeout expires (at which point ``None`` will also be
385        returned).
386
387        When the *timeout* argument is present and not ``None``, it should be a
388        floating point number specifying a timeout for the operation in seconds
389        (or fractions thereof).
390
391        .. note:: If a timeout is given and expires, ``None`` will be returned
392            (no timeout exception will be raised).
393
394        """
395        return self._wait(timeout)
396
397    # link protocol
398    def __call__(self, source):
399        if source.successful():
400            self.set(source.value)
401        else:
402            self.set_exception(source.exception, getattr(source, 'exc_info', None))
403
404    # Methods to make us more like concurrent.futures.Future
405
406    def result(self, timeout=None):
407        return self.get(timeout=timeout)
408
409    set_result = set
410
411    def done(self):
412        return self.ready()
413
414    # we don't support cancelling
415
416    def cancel(self):
417        return False
418
419    def cancelled(self):
420        return False
421
422    # exception is a method, we use it as a property
423
424
425from gevent._util import import_c_accel
426import_c_accel(globals(), 'gevent._event')
427