aboutsummaryrefslogtreecommitdiffstats
path: root/python/gevent/threading.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/gevent/threading.py')
-rw-r--r--python/gevent/threading.py235
1 files changed, 0 insertions, 235 deletions
diff --git a/python/gevent/threading.py b/python/gevent/threading.py
deleted file mode 100644
index 570ccd6..0000000
--- a/python/gevent/threading.py
+++ /dev/null
@@ -1,235 +0,0 @@
-"""
-Implementation of the standard :mod:`threading` using greenlets.
-
-.. note::
-
- This module is a helper for :mod:`gevent.monkey` and is not
- intended to be used directly. For spawning greenlets in your
- applications, prefer higher level constructs like
- :class:`gevent.Greenlet` class or :func:`gevent.spawn`. Attributes
- in this module like ``__threading__`` are implementation artifacts subject
- to change at any time.
-
-.. versionchanged:: 1.2.3
-
- Defer adjusting the stdlib's list of active threads until we are
- monkey patched. Previously this was done at import time. We are
- documented to only be used as a helper for monkey patching, so this should
- functionally be the same, but some applications ignore the documentation and
- directly import this module anyway.
-
- A positive consequence is that ``import gevent.threading,
- threading; threading.current_thread()`` will no longer return a DummyThread
- before monkey-patching.
-"""
-from __future__ import absolute_import
-
-
-__implements__ = [
- 'local',
- '_start_new_thread',
- '_allocate_lock',
- 'Lock',
- '_get_ident',
- '_sleep',
- '_DummyThread',
-]
-
-
-import threading as __threading__
-_DummyThread_ = __threading__._DummyThread
-from gevent.local import local
-from gevent.thread import start_new_thread as _start_new_thread, allocate_lock as _allocate_lock, get_ident as _get_ident
-from gevent.hub import sleep as _sleep, getcurrent
-
-# Exports, prevent unused import warnings
-local = local
-start_new_thread = _start_new_thread
-allocate_lock = _allocate_lock
-_get_ident = _get_ident
-_sleep = _sleep
-getcurrent = getcurrent
-
-Lock = _allocate_lock
-
-
-def _cleanup(g):
- __threading__._active.pop(_get_ident(g), None)
-
-def _make_cleanup_id(gid):
- def _(_r):
- __threading__._active.pop(gid, None)
- return _
-
-_weakref = None
-
-class _DummyThread(_DummyThread_):
- # We avoid calling the superclass constructor. This makes us about
- # twice as fast (1.16 vs 0.68usec on PyPy, 29.3 vs 17.7usec on
- # CPython 2.7), and has the important effect of avoiding
- # allocation and then immediate deletion of _Thread__block, a
- # lock. This is especially important on PyPy where locks go
- # through the cpyext API and Cython, which is known to be slow and
- # potentially buggy (e.g.,
- # https://bitbucket.org/pypy/pypy/issues/2149/memory-leak-for-python-subclass-of-cpyext#comment-22347393)
-
- # These objects are constructed quite frequently in some cases, so
- # the optimization matters: for example, in gunicorn, which uses
- # pywsgi.WSGIServer, every request is handled in a new greenlet,
- # and every request uses a logging.Logger to write the access log,
- # and every call to a log method captures the current thread (by
- # default).
- #
- # (Obviously we have to duplicate the effects of the constructor,
- # at least for external state purposes, which is potentially
- # slightly fragile.)
-
- # For the same reason, instances of this class will cleanup their own entry
- # in ``threading._active``
-
- # This class also solves a problem forking process with subprocess: after forking,
- # Thread.__stop is called, which throws an exception when __block doesn't
- # exist.
-
- # Capture the static things as class vars to save on memory/
- # construction time.
- # In Py2, they're all private; in Py3, they become protected
- _Thread__stopped = _is_stopped = _stopped = False
- _Thread__initialized = _initialized = True
- _Thread__daemonic = _daemonic = True
- _Thread__args = _args = ()
- _Thread__kwargs = _kwargs = None
- _Thread__target = _target = None
- _Thread_ident = _ident = None
- _Thread__started = _started = __threading__.Event()
- _Thread__started.set()
- _tstate_lock = None
-
- def __init__(self): # pylint:disable=super-init-not-called
- #_DummyThread_.__init__(self)
-
- # It'd be nice to use a pattern like "greenlet-%d", but maybe somebody out
- # there is checking thread names...
- self._name = self._Thread__name = __threading__._newname("DummyThread-%d")
- # All dummy threads in the same native thread share the same ident
- # (that of the native thread)
- self._set_ident()
-
- g = getcurrent()
- gid = _get_ident(g)
- __threading__._active[gid] = self
- rawlink = getattr(g, 'rawlink', None)
- if rawlink is not None:
- # raw greenlet.greenlet greenlets don't
- # have rawlink...
- rawlink(_cleanup)
- else:
- # ... so for them we use weakrefs.
- # See https://github.com/gevent/gevent/issues/918
- global _weakref
- if _weakref is None:
- _weakref = __import__('weakref')
- ref = _weakref.ref(g, _make_cleanup_id(gid))
- self.__raw_ref = ref
-
- def _Thread__stop(self):
- pass
-
- _stop = _Thread__stop # py3
-
- def _wait_for_tstate_lock(self, *args, **kwargs):
- # pylint:disable=arguments-differ
- pass
-
-if hasattr(__threading__, 'main_thread'): # py 3.4+
- def main_native_thread():
- return __threading__.main_thread() # pylint:disable=no-member
-else:
- def main_native_thread():
- main_threads = [v for v in __threading__._active.values()
- if isinstance(v, __threading__._MainThread)]
- assert len(main_threads) == 1, "Too many main threads"
-
- return main_threads[0]
-
-import sys
-if sys.version_info[:2] >= (3, 4):
- # XXX: Issue 18808 breaks us on Python 3.4.
- # Thread objects now expect a callback from the interpreter itself
- # (threadmodule.c:release_sentinel). Because this never happens
- # when a greenlet exits, join() and friends will block forever.
- # The solution below involves capturing the greenlet when it is
- # started and deferring the known broken methods to it.
-
- class Thread(__threading__.Thread):
- _greenlet = None
-
- def is_alive(self):
- return bool(self._greenlet)
-
- isAlive = is_alive
-
- def _set_tstate_lock(self):
- self._greenlet = getcurrent()
-
- def run(self):
- try:
- super(Thread, self).run()
- finally:
- # avoid ref cycles, but keep in __dict__ so we can
- # distinguish the started/never-started case
- self._greenlet = None
- self._stop() # mark as finished
-
- def join(self, timeout=None):
- if '_greenlet' not in self.__dict__:
- raise RuntimeError("Cannot join an inactive thread")
- if self._greenlet is None:
- return
- self._greenlet.join(timeout=timeout)
-
- def _wait_for_tstate_lock(self, *args, **kwargs):
- # pylint:disable=arguments-differ
- raise NotImplementedError()
-
- __implements__.append('Thread')
-
- class Timer(Thread, __threading__.Timer): # pylint:disable=abstract-method,inherit-non-class
- pass
-
- __implements__.append('Timer')
-
- # The main thread is patched up with more care
- # in _gevent_will_monkey_patch
-
-if sys.version_info[:2] >= (3, 3):
- __implements__.remove('_get_ident')
- __implements__.append('get_ident')
- get_ident = _get_ident
- __implements__.remove('_sleep')
-
- # Python 3 changed the implementation of threading.RLock
- # Previously it was a factory function around threading._RLock
- # which in turn used _allocate_lock. Now, it wants to use
- # threading._CRLock, which is imported from _thread.RLock and as such
- # is implemented in C. So it bypasses our _allocate_lock function.
- # Fortunately they left the Python fallback in place
- assert hasattr(__threading__, '_CRLock'), "Unsupported Python version"
- _CRLock = None
- __implements__.append('_CRLock')
-
-def _gevent_will_monkey_patch(native_module, items, warn): # pylint:disable=unused-argument
- # Make sure the MainThread can be found by our current greenlet ID,
- # otherwise we get a new DummyThread, which cannot be joined.
- # Fixes tests in test_threading_2 under PyPy.
- main_thread = main_native_thread()
- if __threading__.current_thread() != main_thread:
- warn("Monkey-patching outside the main native thread. Some APIs "
- "will not be available. Expect a KeyError to be printed at shutdown.")
- return
-
- if _get_ident() not in __threading__._active:
- main_id = main_thread.ident
- del __threading__._active[main_id]
- main_thread._ident = main_thread._Thread__ident = _get_ident()
- __threading__._active[_get_ident()] = main_thread