Commit 41319891 authored by Jason Madden's avatar Jason Madden

Documentation and comment tweaks. [skip ci]

parent 4fcd6f8f
......@@ -37,7 +37,8 @@ PyPy Notes
PyPy has been tested on OS X and 64-bit Linux from version 2.6.1
through 4.0.0 and 4.0.1.
.. note:: PyPy is not supported on Windows.
.. note:: PyPy is not supported on Windows. (gevent's CFFI backend is not
available on Windows.)
- Version 2.6.1 or above is required for proper signal handling. Prior
to 2.6.1 and its inclusion of `cffi 1.3.0`_, signals could be
......@@ -50,19 +51,20 @@ through 4.0.0 and 4.0.1.
of PyPy. The benchmarks distributed with gevent typically perform as
well or better on PyPy than on CPython at least on some platforms.
Things that are known or expected to be (relatively) slower under
PyPy include the :mod:`c-ares resolver <gevent.resolver_ares>`.
Whether or not these matter will depend on the workload of each
application.
.. caution:: The ``c-ares`` resolver is not recommended for use under
PyPy. Released versions of PyPy through at least 4.0.1
have `a bug`_ that can cause a memory leak when
subclassing objects that are implemented in Cython, as is
the c-ares resolver. things mentioned above. The
``c-ares`` package has not been audited for this issue.
In addition, thanks to reports like :issue:`704`, we know
that the PyPy garbage collector can interact badly with
Cython-compiled code, leading to crashes.
PyPy include the :mod:`c-ares resolver <gevent.resolver_ares>` and
:class:`~gevent.lock.Semaphore`. Whether or not these matter will
depend on the workload of each application.
.. caution:: The ``c-ares`` resolver is considered highly experimental
under PyPy and is not recommended for production use.
Released versions of PyPy through at least 4.0.1 have `a
bug`_ that can cause a memory leak when subclassing
objects that are implemented in Cython, as is the c-ares
resolver. In addition, thanks to reports like
:issue:`704`, we know that the PyPy garbage collector can
interact badly with Cython-compiled code, leading to
crashes. While the intended use of the ares resolver has
been loosely audited for these issues, no guarantees are made.
.. note:: PyPy 4.0.x on Linux is known to *rarely* (once per 24 hours)
encounter crashes when running heavily loaded, heavily
......
......@@ -17,7 +17,13 @@ class Semaphore(object):
If not given, ``value`` defaults to 1.
This Semaphore's ``__exit__`` method does not call the trace function.
The semaphore is a context manager and can be used in ``with`` statements.
This Semaphore's ``__exit__`` method does not call the trace function
on CPython, but does under PyPy.
.. seealso:: :class:`BoundedSemaphore` for a safer version that prevents
some classes of bugs.
"""
def __init__(self, value=1):
......@@ -53,6 +59,9 @@ class Semaphore(object):
return self.counter <= 0
def release(self):
"""
Release the semaphore, notifying any waiters if needed.
"""
self.counter += 1
self._start_notify()
return self.counter
......@@ -112,6 +121,9 @@ class Semaphore(object):
*callback* will be called in the :class:`Hub <gevent.hub.Hub>`, so it must not use blocking gevent API.
*callback* will be passed one argument: this instance.
This method is normally called automatically by :meth:`acquire` and :meth:`wait`; most code
will not need to use it.
"""
if not callable(callback):
raise TypeError('Expected callable:', callback)
......@@ -125,7 +137,10 @@ class Semaphore(object):
"""
unlink(callback) -> None
Remove the callback set by :meth:`rawlink`
Remove the callback set by :meth:`rawlink`.
This method is normally called automatically by :meth:`acquire` and :meth:`wait`; most
code will not need to use it.
"""
try:
self._links.remove(callback)
......@@ -169,7 +184,7 @@ class Semaphore(object):
Wait until it is possible to acquire this semaphore, or until the optional
*timeout* elapses.
.. warning:: If this semaphore was initialized with a size of 0,
.. caution:: If this semaphore was initialized with a size of 0,
this method will block forever if no timeout is given.
:keyword float timeout: If given, specifies the maximum amount of seconds
......@@ -189,7 +204,7 @@ class Semaphore(object):
Acquire the semaphore.
.. warning:: If this semaphore was initialized with a size of 0,
.. caution:: If this semaphore was initialized with a size of 0,
this method will block forever (unless a timeout is given or blocking is
set to false).
......@@ -233,6 +248,8 @@ class Semaphore(object):
class BoundedSemaphore(Semaphore):
"""
BoundedSemaphore(value=1) -> BoundedSemaphore
A bounded semaphore checks to make sure its current value doesn't
exceed its initial value. If it does, :class:`ValueError` is
raised. In most situations semaphores are used to guard resources
......@@ -242,11 +259,12 @@ class BoundedSemaphore(Semaphore):
If not given, *value* defaults to 1.
"""
#: For monkey-patching, allow changing the class of error we raise
_OVER_RELEASE_ERROR = ValueError
def __init__(self, value=1):
Semaphore.__init__(self, value)
self._initial_value = value
def __init__(self, *args, **kwargs):
Semaphore.__init__(self, *args, **kwargs)
self._initial_value = self.counter
def release(self):
if self.counter >= self._initial_value:
......
......@@ -161,7 +161,7 @@ def wait_read(fileno, timeout=None, timeout_exc=_NONE):
For the meaning of the other parameters and possible exceptions,
see :func:`wait`.
.. seealso: :func:`cancel_wait`
.. seealso:: :func:`cancel_wait`
"""
io = get_hub().loop.io(fileno, 1)
return wait(io, timeout, timeout_exc)
......@@ -177,7 +177,7 @@ def wait_write(fileno, timeout=None, timeout_exc=_NONE, event=_NONE):
:keyword event: Ignored. Applications should not pass this parameter.
In the future, it may become an error.
.. seealso: :func:`cancel_wait`
.. seealso:: :func:`cancel_wait`
"""
io = get_hub().loop.io(fileno, 2)
return wait(io, timeout, timeout_exc)
......@@ -194,7 +194,7 @@ def wait_readwrite(fileno, timeout=None, timeout_exc=_NONE, event=_NONE):
:keyword event: Ignored. Applications should not pass this parameter.
In the future, it may become an error.
.. seealso: :func:`cancel_wait`
.. seealso:: :func:`cancel_wait`
"""
io = get_hub().loop.io(fileno, 3)
return wait(io, timeout, timeout_exc)
......
......@@ -13,8 +13,8 @@ __all__ = ['Semaphore', 'DummySemaphore', 'BoundedSemaphore', 'RLock']
# duration, ensuring that no other thread can interrupt us in an
# unsafe state (only when we _do_wait do we call back into Python and
# allow switching threads). Simulate that here through the use of a manual
# lock. (In theory we could use a lock per Semaphore and thus potentially
# scale better than the GIL, but it probably doesn't matter.)
# lock. (We use a separate lock for each semaphore to allow sys.settrace functions
# to use locks *other* than the one being traced.)
if PYPY:
# TODO: Need to use monkey.get_original?
from thread import allocate_lock as _allocate_lock
......@@ -115,6 +115,8 @@ if PYPY:
class DummySemaphore(object):
"""
DummySemaphore(value=None) -> DummySemaphore
A Semaphore initialized with "infinite" initial value. None of its
methods ever block.
......@@ -139,6 +141,13 @@ class DummySemaphore(object):
# determines whether it should lock around IO to the underlying
# file object.
def __init__(self, value=None):
"""
.. versionchanged:: 1.1rc3
Accept and ignore a *value* argument for compatibility with Semaphore.
"""
pass
def __str__(self):
return '<%s>' % self.__class__.__name__
......@@ -147,6 +156,7 @@ class DummySemaphore(object):
return False
def release(self):
"""Releasing a dummy semaphore does nothing."""
pass
def rawlink(self, callback):
......@@ -157,6 +167,7 @@ class DummySemaphore(object):
pass
def wait(self, timeout=None):
"""Waiting for a DummySemaphore returns immediately."""
pass
def acquire(self, blocking=True, timeout=None):
......
......@@ -10,6 +10,7 @@ from os.path import join, abspath, basename, dirname
from subprocess import check_call
from glob import glob
PYPY = hasattr(sys, 'pypy_version_info')
WIN = sys.platform.startswith('win')
CFFI_WIN_BUILD_ANYWAY = os.environ.get("PYPY_WIN_BUILD_ANYWAY")
......@@ -31,6 +32,8 @@ if WIN:
# Make sure the env vars that make.cmd needs are set
if not os.environ.get('PYTHON_EXE'):
os.environ['PYTHON_EXE'] = 'pypy' if PYPY else 'python'
if not os.environ.get('PYEXE'):
os.environ['PYEXE'] = os.environ['PYTHON_EXE']
import distutils
......
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