[Python-Dev] PEP Draft: Simplified Global Interpreter Lock acquisition for extensions

Mark Hammond mhammond@skippinet.com.au
Wed, 5 Feb 2003 14:33:52 +1100


This is a multi-part message in MIME format.

------=_NextPart_000_006D_01C2CD23.A1DD0080
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Hi all,
  Following the thread of a couple of months ago, I have prepared a first
draft of a PEP.  There is still more detail to be filled in the
"implementation" area, but I would still like feedback on all other areas.

Thanks,

Mark.

------=_NextPart_000_006D_01C2CD23.A1DD0080
Content-Type: text/plain;
	name="pep_gil.txt"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="pep_gil.txt"

PEP: xxx
Title: Simple Global Interpreter Lock acquisition for extensions
Version: $Revision: $
Last-Modified: $Date: $
Author: Mark Hammond <mhammond@skippinet.com.au>
Status:=20
Type:=20
Content-Type: text/plain
Created: Feb-2003
Post-History:


Abstract

    This PEP proposes a simplified API for access to the Global =
Interpreter
    Lock (GIL) for Python extension modules.  Specifically, it provides =
a=20
    solution for authors of complex multi-threaded extensions, where the
    current state of Python (i.e., the state of the GIL, or if Python is =

    currently using the GIL, or indeed if Python has been initialized) =
is
    unknown.

    This PEP proposes a new, optional API to manage the Python thread=20
    state.  This API is almost certain to require a platform =
implementation of
    Thread Local Storage (TLS), which will form an optional extension to =
the
    existing "Python threading" implementation required for all=20
    threading-enabled Python platforms.  Thus, before this new API will
    be available on a given platform, the TLS extensions to that =
platform's
    Python threading API must be implemented.
   =20
    An initial implementation of this PEP will target the Windows =
platform,
    and any platforms using a modern "pthreads" [1] implementation.

Rationale

    The current Python interpreter state API is suitable for simple,=20
    single-threaded extensions, but quickly becomes incredibly complex
    for non-trivial, multi-threaded extensions.
   =20
    Currently Python provides two mechanisms for dealing with the GIL:
   =20
    - Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS macros.
      These macros are provided primarily to allow a simple Python =
extension
      that already owns the GIL to temporarily release it while making =
an
      "external" (ie, non-Python), generally expensive, call.  Any =
existing=20
      Python threads that are blocked waiting for the GIL are then free =
to=20
      run.
     =20
    - PyThreadState and PyInterpreterState APIs.
      These API functions allow an extension/embedded application to
      acquire the GIL, but suffer from a serious boot-strapping problem =
- they
      require you to know the state of the Python interpreter and of the =
GIL=20
      before they can be used.  One particular problem is for extension=20
      authors that need to deal with threads never before seen by =
Python, but
      need to call Python from this thread.  It is very difficult, =
delicate=20
      and error prone to author an extension where these "new" threads =
always=20
      know the exact state of the GIL, and therefore can reliably =
interact=20
      with this API.
     =20
    For these reasons, the question of how such extensions should
    interact with Python is quickly becoming a FAQ.  The main impetus
    for this PEP, a thread on python-dev [2], immediately identified the
    following projects with this exact issue:

    - The win32all extensions.
    - Boost
    - ctypes
    - Python-GTK bindings
    - Uno

    Currently, there is no reasonable, portable solution to this =
problem,
    forcing each extension author to implement their own hand-rolled=20
    version.  Further, the problem is complex, meaning many=20
    implementations are likely to be incorrect, leading to a variety of=20
    problems that will often manifest simply as "Python has hung."
   =20
    While the biggest problem in the existing thread-state API is the =
lack
    of the ability to query the current state of the lock, it is felt =
that
    a more complete, simplified solution should be offered to extension=20
    authors.  Such a solution should encourage authors to provide=20
    error-free, complex extension modules that take full advantage of=20
    Python's threading mechanisms.

Limitations and Exclusions

    This proposal identifies a solution for extension authors with =
complex
    multi-threaded requirements, but that only require a single=20
    "PyInterpeterState".  There is no attempt to cater for extensions
    that require multiple interpreter states.  As at time of writing, no
    extension has been identified that requires multiple =
PyInterpreterStates,
    and indeed it is not clear if that facility works correctly in =
Python=20
    itself.
   =20
    It is intended that this API be all that is necessary to acquire the
    Python GIL.  Apart from the existing, standard =
Py_BEGIN_ALLOW_THREADS=20
    and Py_END_ALLOW_THREADS macros, it is assumed that no additional =
thread
    state API functions will be used by the extension.  Extensions with
    such complicated requirements are free to continue to use the =
existing
    thread state API.
   =20
Proposal

    This proposal recommends a new, optional API be added to Python to
    simplify the management of the GIL.
   =20
    The intent is that an extension author be able to use a small,=20
    well-defined "prologue dance", at any time and on any thread,
    and this dance will ensure Python is ready to be used on that =
thread.
    After the extension has finished with Python, it must also perform =
an
    "epilogue dance" to release any resources previously acquired.  =
Ideally,
    these dances will be able to be expressed in a single line.

    Specifically, the following new APIs are proposed:
   =20
    /*
    Ensure that the current thread is ready to call the Python
    C API, regardless of the current state of Python, or of its
    thread lock.  This may be called as many times as desired
    by a thread, so long as each call is matched with a call to
    PyAutoThreadState_Release()
   =20
    When the function returns, the current thread will hold the GIL.  =
Thus,
    the GIL is held by the thread until PyAutoThreadState_Release() is =
called.
    (Note that as happens now in Python, calling a Python API function =
may=20
    indeed cause a thread-switch and therefore a GIL ownership change. =20
    However, Python gurantees that when the API function returns, the =
GIL will
    again be owned by the thread making the call)

    Failure is a fatal error.
    */
    void PyAutoThreadState_Ensure(void);
   =20
    /*
    Release any resources previously acquired.  After this call, =
Python's
    state will again be indeterminate, so the API can not be used.
   =20
    Every call to PyAutoThreadState_Ensure must be matched by a
    call to PyAutoThreadState_Release on the same thread.
    */
    void PyAutoThreadState_Release(void);
   =20
    As this PEP develops, it may become obvious that certain =
optimizations
    are possible over this simplified API, assuming extension authors =
are able=20
    to provide some context.  These will be described and implemented =
during
    the development of this PEP.

Design and Implementation

    The general operation of PyAutoThreadState_Ensure() will be:
    - Ensure Python is initialized.
    - If the current thread does not own the GIL, acquire it.
    - Increment a counter for how many calls to PyAutoThreadState_Ensure
      have been made on the current thread.
    - return
   =20
    The general operation of PyAutoThreadState_Release() will be:
      - assert our thread currently holds the lock.
    - Decrement the PyAutoThreadState_Ensure counter for the thread.
    - If counter =3D=3D 0:
      - release the lock.
      - release any additional resources consumed.
    - return

    The implementation of this functionality will require some =
additional
    functionality from Python's hosting platform.  These requirements =
are:
   =20
    [tbd]

References

    [1] pthreads???

    [2] =
http://mail.python.org/pipermail/python-dev/2002-December/031424.html

    [3]=20



Copyright

    This document has been placed in the public domain.


=0C
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:

------=_NextPart_000_006D_01C2CD23.A1DD0080--