Commit 8fab3aab authored by Stefan Behnel's avatar Stefan Behnel

Promote the new opaque PEP-539 type "Py_tss_t" to a known Cython type to avoid...

Promote the new opaque PEP-539 type "Py_tss_t" to a known Cython type to avoid static variable initialisation issues with the "Py_tss_NEEDS_INIT" struct initialiser value.
parent d9672974
...@@ -27,6 +27,10 @@ Features added ...@@ -27,6 +27,10 @@ Features added
* The new TSS C-API in CPython 3.7 is supported and has been backported. * The new TSS C-API in CPython 3.7 is supported and has been backported.
Patch by Naotoshi Seo. (Github issue #1932) Patch by Naotoshi Seo. (Github issue #1932)
* Cython knows the new ``Py_tss_t`` type defined in PEP-539 and automatically
initialises variables declared with that type to ``Py_tss_NEEDS_INIT``,
a value which cannot be used outside of static assignments.
* The set methods ``.remove()`` and ``.discard()`` are optimised. * The set methods ``.remove()`` and ``.discard()`` are optimised.
Patch by Antoine Pitrou. (Github issue #2042) Patch by Antoine Pitrou. (Github issue #2042)
......
...@@ -2710,6 +2710,7 @@ special_basic_c_types = cython.declare(dict, { ...@@ -2710,6 +2710,7 @@ special_basic_c_types = cython.declare(dict, {
"ssize_t" : (2, 0), "ssize_t" : (2, 0),
"size_t" : (0, 0), "size_t" : (0, 0),
"ptrdiff_t" : (2, 0), "ptrdiff_t" : (2, 0),
"Py_tss_t" : (1, 0),
}) })
sign_and_longness_words = cython.declare( sign_and_longness_words = cython.declare(
......
...@@ -192,7 +192,8 @@ class PyrexType(BaseType): ...@@ -192,7 +192,8 @@ class PyrexType(BaseType):
# is_pythran_expr boolean Is Pythran expr # is_pythran_expr boolean Is Pythran expr
# is_numpy_buffer boolean Is Numpy array buffer # is_numpy_buffer boolean Is Numpy array buffer
# has_attributes boolean Has C dot-selectable attributes # has_attributes boolean Has C dot-selectable attributes
# default_value string Initial value # default_value string Initial value that can be assigned before first user assignment.
# declaration_value string The value statically assigned on declaration (if any).
# entry Entry The Entry for this type # entry Entry The Entry for this type
# #
# declaration_code(entity_code, # declaration_code(entity_code,
...@@ -254,6 +255,7 @@ class PyrexType(BaseType): ...@@ -254,6 +255,7 @@ class PyrexType(BaseType):
is_numpy_buffer = 0 is_numpy_buffer = 0
has_attributes = 0 has_attributes = 0
default_value = "" default_value = ""
declaration_value = ""
def resolve(self): def resolve(self):
# If a typedef, returns the base type. # If a typedef, returns the base type.
...@@ -1083,6 +1085,7 @@ class PyObjectType(PyrexType): ...@@ -1083,6 +1085,7 @@ class PyObjectType(PyrexType):
name = "object" name = "object"
is_pyobject = 1 is_pyobject = 1
default_value = "0" default_value = "0"
declaration_value = "0"
buffer_defaults = None buffer_defaults = None
is_extern = False is_extern = False
is_subclassed = False is_subclassed = False
...@@ -2226,6 +2229,25 @@ complex_ops = { ...@@ -2226,6 +2229,25 @@ complex_ops = {
} }
class CPyTSSTType(CType):
#
# PEP-539 "Py_tss_t" type
#
declaration_value = "Py_tss_NEEDS_INIT"
def __repr__(self):
return "<Py_tss_t>"
def declaration_code(self, entity_code,
for_display=0, dll_linkage=None, pyrex=0):
if pyrex or for_display:
base_code = "Py_tss_t"
else:
base_code = public_decl("Py_tss_t", dll_linkage)
return self.base_declaration_code(base_code, entity_code)
class CPointerBaseType(CType): class CPointerBaseType(CType):
# common base type for pointer/array types # common base type for pointer/array types
# #
...@@ -4088,6 +4110,9 @@ c_gilstate_type = CEnumType("PyGILState_STATE", "PyGILState_STATE", True) ...@@ -4088,6 +4110,9 @@ c_gilstate_type = CEnumType("PyGILState_STATE", "PyGILState_STATE", True)
c_threadstate_type = CStructOrUnionType("PyThreadState", "struct", None, 1, "PyThreadState") c_threadstate_type = CStructOrUnionType("PyThreadState", "struct", None, 1, "PyThreadState")
c_threadstate_ptr_type = CPtrType(c_threadstate_type) c_threadstate_ptr_type = CPtrType(c_threadstate_type)
# PEP-539 "Py_tss_t" type
c_pytss_t_type = CPyTSSTType()
# the Py_buffer type is defined in Builtin.py # the Py_buffer type is defined in Builtin.py
c_py_buffer_type = CStructOrUnionType("Py_buffer", "struct", None, 1, "Py_buffer") c_py_buffer_type = CStructOrUnionType("Py_buffer", "struct", None, 1, "Py_buffer")
c_py_buffer_ptr_type = CPtrType(c_py_buffer_type) c_py_buffer_ptr_type = CPtrType(c_py_buffer_type)
...@@ -4153,6 +4178,7 @@ modifiers_and_name_to_type = { ...@@ -4153,6 +4178,7 @@ modifiers_and_name_to_type = {
# #
(1, 0, "void"): c_void_type, (1, 0, "void"): c_void_type,
(1, 0, "Py_tss_t"): c_pytss_t_type,
(1, 0, "bint"): c_bint_type, (1, 0, "bint"): c_bint_type,
(0, 0, "Py_UNICODE"): c_py_unicode_type, (0, 0, "Py_UNICODE"): c_py_unicode_type,
......
...@@ -1378,8 +1378,8 @@ class ModuleScope(Scope): ...@@ -1378,8 +1378,8 @@ class ModuleScope(Scope):
api=api, in_pxd=in_pxd, is_cdef=is_cdef) api=api, in_pxd=in_pxd, is_cdef=is_cdef)
if is_cdef: if is_cdef:
entry.is_cglobal = 1 entry.is_cglobal = 1
if entry.type.is_pyobject: if entry.type.declaration_value:
entry.init = "0" entry.init = entry.type.declaration_value
self.var_entries.append(entry) self.var_entries.append(entry)
else: else:
entry.is_pyglobal = 1 entry.is_pyglobal = 1
...@@ -1710,8 +1710,8 @@ class LocalScope(Scope): ...@@ -1710,8 +1710,8 @@ class LocalScope(Scope):
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname=cname, visibility=visibility, cname=cname, visibility=visibility,
api=api, in_pxd=in_pxd, is_cdef=is_cdef) api=api, in_pxd=in_pxd, is_cdef=is_cdef)
if type.is_pyobject: if entry.type.declaration_value:
entry.init = "0" entry.init = entry.type.declaration_value
entry.is_local = 1 entry.is_local = 1
entry.in_with_gil_block = self._in_with_gil_block entry.in_with_gil_block = self._in_with_gil_block
......
...@@ -39,10 +39,9 @@ cdef extern from "pythread.h": ...@@ -39,10 +39,9 @@ cdef extern from "pythread.h":
# Cleanup after a fork # Cleanup after a fork
void PyThread_ReInitTLS() void PyThread_ReInitTLS()
# Thread Specific Storage (TSS) API in CPython 3.7+ # Thread Specific Storage (TSS) API in CPython 3.7+ (also backported)
ctypedef struct Py_tss_t: #ctypedef struct Py_tss_t: pass # Cython built-in type
pass Py_tss_t Py_tss_NEEDS_INIT # Not normally useful: Cython auto-initialises declared "Py_tss_t" variables.
Py_tss_t Py_tss_NEEDS_INIT
Py_tss_t * PyThread_tss_alloc() Py_tss_t * PyThread_tss_alloc()
void PyThread_tss_free(Py_tss_t *key) void PyThread_tss_free(Py_tss_t *key)
int PyThread_tss_is_created(Py_tss_t *key) int PyThread_tss_is_created(Py_tss_t *key)
......
...@@ -385,7 +385,7 @@ py_complex = typedef(complex, "double complex") ...@@ -385,7 +385,7 @@ py_complex = typedef(complex, "double complex")
int_types = ['char', 'short', 'Py_UNICODE', 'int', 'Py_UCS4', 'long', 'longlong', 'Py_ssize_t', 'size_t'] int_types = ['char', 'short', 'Py_UNICODE', 'int', 'Py_UCS4', 'long', 'longlong', 'Py_ssize_t', 'size_t']
float_types = ['longdouble', 'double', 'float'] float_types = ['longdouble', 'double', 'float']
complex_types = ['longdoublecomplex', 'doublecomplex', 'floatcomplex', 'complex'] complex_types = ['longdoublecomplex', 'doublecomplex', 'floatcomplex', 'complex']
other_types = ['bint', 'void'] other_types = ['bint', 'void', 'Py_tss_t']
to_repr = { to_repr = {
'longlong': 'long long', 'longlong': 'long long',
...@@ -420,13 +420,13 @@ for name in complex_types: ...@@ -420,13 +420,13 @@ for name in complex_types:
gs[name] = typedef(py_complex, to_repr(name, name)) gs[name] = typedef(py_complex, to_repr(name, name))
bint = typedef(bool, "bint") bint = typedef(bool, "bint")
void = typedef(int, "void") void = typedef(None, "void")
Py_tss_t = typedef(None, "Py_tss_t")
for t in int_types + float_types + complex_types + other_types: for t in int_types + float_types + complex_types + other_types:
for i in range(1, 4): for i in range(1, 4):
gs["%s_%s" % ('p'*i, t)] = gs[t]._pointer(i) gs["%s_%s" % ('p'*i, t)] = gs[t]._pointer(i)
void = typedef(None, "void")
NULL = gs['p_void'](0) NULL = gs['p_void'](0)
# looks like 'gs' has some users out there by now... # looks like 'gs' has some users out there by now...
......
...@@ -3,16 +3,21 @@ ...@@ -3,16 +3,21 @@
from cpython.pythread cimport * from cpython.pythread cimport *
cdef Py_tss_t *pass_py_tss_t_ptr(Py_tss_t *value):
return value
def tss_create_delete(): def tss_create_delete():
""" """
>>> tss_create_delete() >>> tss_create_delete()
(True, False) (True, False)
""" """
cdef Py_tss_t tss_key = Py_tss_NEEDS_INIT cdef Py_tss_t tss_key
cdef bint after_create, after_delete cdef bint after_create, after_delete
if PyThread_tss_create(&tss_key) != 0: if PyThread_tss_create(&tss_key) != 0:
raise MemoryError() raise MemoryError()
after_create = PyThread_tss_is_created(&tss_key) != 0 after_create = PyThread_tss_is_created(&tss_key) != 0
assert after_create == PyThread_tss_is_created(pass_py_tss_t_ptr(&tss_key))
PyThread_tss_delete(&tss_key) PyThread_tss_delete(&tss_key)
after_delete = PyThread_tss_is_created(&tss_key) != 0 after_delete = PyThread_tss_is_created(&tss_key) != 0
return (after_create, after_delete) return (after_create, after_delete)
...@@ -58,7 +63,7 @@ def tss_set_get(): ...@@ -58,7 +63,7 @@ def tss_set_get():
>>> tss_set_get() >>> tss_set_get()
1 1
""" """
cdef Py_tss_t tss_key = Py_tss_NEEDS_INIT cdef Py_tss_t tss_key
cdef int the_value = 1 cdef int the_value = 1
cdef int ret_value cdef int ret_value
if PyThread_tss_create(&tss_key) != 0: if PyThread_tss_create(&tss_key) != 0:
......
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