PEP 539: update draft to omit two functions (#314)
This commit is contained in:
parent
76f6614ff0
commit
e648e57384
81
pep-0539.txt
81
pep-0539.txt
|
@ -16,7 +16,9 @@ Abstract
|
||||||
|
|
||||||
The proposal is to add a new Thread Local Storage (TLS) API to CPython which
|
The proposal is to add a new Thread Local Storage (TLS) API to CPython which
|
||||||
would supersede use of the existing TLS API within the CPython interpreter,
|
would supersede use of the existing TLS API within the CPython interpreter,
|
||||||
while deprecating the existing API.
|
while deprecating the existing API. The new API is named "Thread Specific
|
||||||
|
Storage (TSS) API" (see `Rationale for Proposed Solution`_ for the origin of
|
||||||
|
the name).
|
||||||
|
|
||||||
Because the existing TLS API is only used internally (it is not mentioned in
|
Because the existing TLS API is only used internally (it is not mentioned in
|
||||||
the documentation, and the header that defines it, ``pythread.h``, is not
|
the documentation, and the header that defines it, ``pythread.h``, is not
|
||||||
|
@ -54,8 +56,10 @@ These would be superseded by a new set of analogous functions::
|
||||||
PyAPI_FUNC(void) PyThread_tss_delete(Py_tss_t *key)
|
PyAPI_FUNC(void) PyThread_tss_delete(Py_tss_t *key)
|
||||||
PyAPI_FUNC(int) PyThread_tss_set(Py_tss_t *key, void *value)
|
PyAPI_FUNC(int) PyThread_tss_set(Py_tss_t *key, void *value)
|
||||||
PyAPI_FUNC(void *) PyThread_tss_get(Py_tss_t *key)
|
PyAPI_FUNC(void *) PyThread_tss_get(Py_tss_t *key)
|
||||||
PyAPI_FUNC(void) PyThread_tss_delete_value(Py_tss_t *key)
|
|
||||||
PyAPI_FUNC(void) PyThread_ReInitTSS(void)
|
``PyThread_delete_key_value`` and ``PyThread_ReInitTLS`` don't provide
|
||||||
|
on the new TSS API because these functions are for the CPython's own TLS
|
||||||
|
implementation that was removed [8]_.
|
||||||
|
|
||||||
The specification also adds a few new features:
|
The specification also adds a few new features:
|
||||||
|
|
||||||
|
@ -64,10 +68,10 @@ The specification also adds a few new features:
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool _is_initialized;
|
bool _is_initialized;
|
||||||
NATIVE_TLS_KEY_T _key;
|
NATIVE_TSS_KEY_T _key;
|
||||||
} Py_tss_t;
|
} Py_tss_t;
|
||||||
|
|
||||||
where ``NATIVE_TLS_KEY_T`` is a macro whose value depends on the
|
where ``NATIVE_TSS_KEY_T`` is a macro whose value depends on the
|
||||||
underlying native TLS implementation (e.g. ``pthread_key_t``).
|
underlying native TLS implementation (e.g. ``pthread_key_t``).
|
||||||
|
|
||||||
* A constant default value for ``Py_tss_t`` variables,
|
* A constant default value for ``Py_tss_t`` variables,
|
||||||
|
@ -82,9 +86,10 @@ The specification also adds a few new features:
|
||||||
The first two are needed for dynamic (de-)allocation of a `Py_tss_t`,
|
The first two are needed for dynamic (de-)allocation of a `Py_tss_t`,
|
||||||
particularly in extension modules built with `Py_LIMITED_API`, where
|
particularly in extension modules built with `Py_LIMITED_API`, where
|
||||||
static allocation of this type is not possible due to its implementation
|
static allocation of this type is not possible due to its implementation
|
||||||
being opaque at build time. ``PyThread_tss_is_created`` returns ``true``
|
being opaque at build time. The value returned by ``PyThread_tss_alloc``
|
||||||
if the given ``Py_tss_t`` has been initialized (i.e. by
|
is the same state (not yet initialized key) as statically allocated with
|
||||||
``PyThread_tss_create``).
|
``Py_tss_NEEDS_INIT``. ``PyThread_tss_is_created`` returns ``true`` if the
|
||||||
|
given ``Py_tss_t`` has been initialized (i.e. by ``PyThread_tss_create``).
|
||||||
|
|
||||||
The new ``PyThread_tss_`` functions are almost exactly analogous to their
|
The new ``PyThread_tss_`` functions are almost exactly analogous to their
|
||||||
original counterparts with a minor difference: Whereas
|
original counterparts with a minor difference: Whereas
|
||||||
|
@ -92,7 +97,7 @@ original counterparts with a minor difference: Whereas
|
||||||
``int``, ``PyThread_tss_create`` takes a ``Py_tss_t*`` as an argument and
|
``int``, ``PyThread_tss_create`` takes a ``Py_tss_t*`` as an argument and
|
||||||
returns an ``int`` status code. The behavior of ``PyThread_tss_create`` is
|
returns an ``int`` status code. The behavior of ``PyThread_tss_create`` is
|
||||||
undefined if the value pointed to by the ``key`` argument is not initialized
|
undefined if the value pointed to by the ``key`` argument is not initialized
|
||||||
by ``Py_tss_NEEDS_INIT``. The returned status status code is zero on success
|
by ``Py_tss_NEEDS_INIT``. The returned status code is zero on success
|
||||||
and non-zero on failure. The meanings of non-zero status codes are not
|
and non-zero on failure. The meanings of non-zero status codes are not
|
||||||
otherwise defined by this specification.
|
otherwise defined by this specification.
|
||||||
|
|
||||||
|
@ -135,6 +140,18 @@ The rest of the API is used analogously to the old API::
|
||||||
assert(!PyThread_tss_is_created(&tss_key));
|
assert(!PyThread_tss_is_created(&tss_key));
|
||||||
|
|
||||||
|
|
||||||
|
Platform Support Changes
|
||||||
|
========================
|
||||||
|
|
||||||
|
A new "Native thread implementation" section will be added to PEP 11 that
|
||||||
|
states:
|
||||||
|
|
||||||
|
* As of CPython 3.7, in the case of enabling thread support, all platforms are
|
||||||
|
required to provide at least one of native thread implementation (as of
|
||||||
|
pthreads or Windows) to implement TSS API. Any TSS API problems that occur
|
||||||
|
in the implementation without native thread will be closed as "won't fix".
|
||||||
|
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
@ -144,15 +161,15 @@ TLS values, as defined by the original PyThread TLS API.
|
||||||
The original TLS API was added to Python by GvR back in 1997, and at the
|
The original TLS API was added to Python by GvR back in 1997, and at the
|
||||||
time the key used to represent a TLS value was an ``int``, and so it has
|
time the key used to represent a TLS value was an ``int``, and so it has
|
||||||
been to the time of writing. This used CPython's own TLS implementation,
|
been to the time of writing. This used CPython's own TLS implementation,
|
||||||
the current generation of which can still be found, largely unchanged, in
|
but the current generation of which hasn't been used, largely unchanged, in
|
||||||
Python/thread.c. Support for implementation of the API on top of native
|
Python/thread.c. Support for implementation of the API on top of native
|
||||||
thread implementations (NT and pthreads) was added much later, and the
|
thread implementations (pthreads and Windows) was added much later, and the
|
||||||
built-in implementation may still be used on other platforms.
|
own implementation has been no longer necessary and removed [9]_.
|
||||||
|
|
||||||
The problem with the choice of ``int`` to represent a TLS key, is that while
|
The problem with the choice of ``int`` to represent a TLS key, is that while
|
||||||
it was fine for CPython's internal TLS implementation, and happens to be
|
it was fine for CPython's own TLS implementation, and happens to be
|
||||||
compatible with NT (which uses ``DWORD`` for the analogous data), it is not
|
compatible with Windows (which uses ``DWORD`` for the analogous data), it is
|
||||||
compatible with the POSIX standard for the pthreads API, which defines
|
not compatible with the POSIX standard for the pthreads API, which defines
|
||||||
``pthread_key_t`` as an opaque type not further defined by the standard (as
|
``pthread_key_t`` as an opaque type not further defined by the standard (as
|
||||||
with ``Py_tss_t`` described above). This leaves it up to the underlying
|
with ``Py_tss_t`` described above). This leaves it up to the underlying
|
||||||
implementation how a ``pthread_key_t`` value is used to look up
|
implementation how a ``pthread_key_t`` value is used to look up
|
||||||
|
@ -185,8 +202,7 @@ Rationale for Proposed Solution
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
The use of an opaque type (``Py_tss_t``) to key TLS values allows the API to
|
The use of an opaque type (``Py_tss_t``) to key TLS values allows the API to
|
||||||
be compatible, at least in this regard, with CPython's internal TLS
|
be compatible, with all present (posix and Windows) and future (C11?)
|
||||||
implementation, as well as all present (NT and posix) and future (C11?)
|
|
||||||
native TLS implementations supported by CPython, as it allows the definition
|
native TLS implementations supported by CPython, as it allows the definition
|
||||||
of ``Py_tss_t`` to depend on the underlying implementation.
|
of ``Py_tss_t`` to depend on the underlying implementation.
|
||||||
|
|
||||||
|
@ -204,8 +220,8 @@ by the fact that not all native TLS implementations define a sentinel value
|
||||||
for uninitialized TLS keys. For example, on Windows a TLS key is
|
for uninitialized TLS keys. For example, on Windows a TLS key is
|
||||||
represented by a ``DWORD`` (``unsigned int``) and its value must be treated
|
represented by a ``DWORD`` (``unsigned int``) and its value must be treated
|
||||||
as opaque [3]_. So there is no unsigned integer value that can be safely
|
as opaque [3]_. So there is no unsigned integer value that can be safely
|
||||||
used to represent an uninititalized TLS key on Windows. Likewise, POSIX
|
used to represent an uninitialized TLS key on Windows. Likewise, POSIX
|
||||||
does not specify a sentintel for an uninitialized ``pthread_key_t``, instead
|
does not specify a sentinel for an uninitialized ``pthread_key_t``, instead
|
||||||
relying on the ``pthread_once`` interface to ensure that a given TLS key is
|
relying on the ``pthread_once`` interface to ensure that a given TLS key is
|
||||||
initialized only once per-process. Therefore, the ``Py_tss_t`` type
|
initialized only once per-process. Therefore, the ``Py_tss_t`` type
|
||||||
contains an explicit ``._is_initialized`` that can indicate the key's
|
contains an explicit ``._is_initialized`` that can indicate the key's
|
||||||
|
@ -241,13 +257,14 @@ Rejected Ideas
|
||||||
Python should not be hobbled on affected platforms despite them being
|
Python should not be hobbled on affected platforms despite them being
|
||||||
otherwise perfectly capable of running multi-threaded Python.
|
otherwise perfectly capable of running multi-threaded Python.
|
||||||
|
|
||||||
* Affected platforms should not define ``Py_HAVE_NATIVE_TLS``: This is a more
|
* Affected platforms should use CPython's own TLS implementation instead of
|
||||||
acceptable alternative to the previous idea, and in fact there is a patch to
|
native TLS implementation: This is a more acceptable alternative to the
|
||||||
do just that [4]_. However, CPython's internal TLS implementation being
|
previous idea, and in fact there had been a patch to do just that [4]_.
|
||||||
"slower and clunkier" in general than native implementations still needlessly
|
However, the own implementation being "slower and clunkier" in general
|
||||||
hobbles performance on affected platforms. At least one other module
|
than native implementations still needlessly hobbles performance on affected
|
||||||
(``tracemalloc``) is also broken if Python is built without
|
platforms. At least one other module (``tracemalloc``) is also broken if
|
||||||
``Py_HAVE_NATIVE_TLS``.
|
Python is built without native implementation. And this idea cannot be
|
||||||
|
adopted because the own implementation was removed.
|
||||||
|
|
||||||
* Keep the existing API, but work around the issue by providing a mapping from
|
* Keep the existing API, but work around the issue by providing a mapping from
|
||||||
``pthread_key_t`` values to ``int`` values. A couple attempts were made at
|
``pthread_key_t`` values to ``int`` values. A couple attempts were made at
|
||||||
|
@ -263,7 +280,13 @@ Implementation
|
||||||
==============
|
==============
|
||||||
|
|
||||||
An initial version of a patch [7]_ is available on the bug tracker for this
|
An initial version of a patch [7]_ is available on the bug tracker for this
|
||||||
issue.
|
issue. Since the migration to Github, it's being developed in the
|
||||||
|
``pep539-tss-api`` feature branch [10]_ in Masayuki Yamamoto's fork of the
|
||||||
|
CPython repository on Github. A work-in-progress PR is available at [11]_.
|
||||||
|
|
||||||
|
This reference implementation covers not only the enhancement request in API
|
||||||
|
features, but also the client codes fix needed to replace the existing TLS API
|
||||||
|
with the new TSS API.
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
|
@ -282,3 +305,7 @@ References and Footnotes
|
||||||
.. [5] http://bugs.python.org/file44269/issue25658-1.patch
|
.. [5] http://bugs.python.org/file44269/issue25658-1.patch
|
||||||
.. [6] http://bugs.python.org/file44303/key-constant-time.diff
|
.. [6] http://bugs.python.org/file44303/key-constant-time.diff
|
||||||
.. [7] http://bugs.python.org/file46379/pythread-tss-3.patch
|
.. [7] http://bugs.python.org/file46379/pythread-tss-3.patch
|
||||||
|
.. [8] http://bugs.python.org/issue25658#msg298342
|
||||||
|
.. [9] http://bugs.python.org/issue30832
|
||||||
|
.. [10] https://github.com/python/cpython/compare/master...ma8ma:pep539-tss-api
|
||||||
|
.. [11] https://github.com/python/cpython/pull/1362
|
||||||
|
|
Loading…
Reference in New Issue