cython: freethreading_compatible (#654)

```
$ v3/bin/python -VV
Python 3.14.0 free-threading build (main, Oct  7 2025, 15:35:12) [Clang 20.1.4 ]

$ v3/bin/python -c 'import sys,msgpack; print(sys._is_gil_enabled())'
False
```
This commit is contained in:
Inada Naoki 2025-10-09 15:53:08 +09:00 committed by GitHub
parent c2546eabc4
commit af45640970
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 20 additions and 6 deletions

View file

@ -10,7 +10,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: ["ubuntu-latest", "windows-latest", "windows-11-arm", "macos-latest"] os: ["ubuntu-latest", "windows-latest", "windows-11-arm", "macos-latest"]
py: ["3.14-dev", "3.13", "3.12", "3.11", "3.10", "3.9"] py: ["3.14", "3.14t", "3.13", "3.12", "3.11", "3.10", "3.9"]
exclude: exclude:
- os: windows-11-arm - os: windows-11-arm
py: "3.9" py: "3.9"

View file

@ -1,5 +1,6 @@
# coding: utf-8
#cython: embedsignature=True, c_string_encoding=ascii, language_level=3 #cython: embedsignature=True, c_string_encoding=ascii, language_level=3
#cython: freethreading_compatible = True
import cython
from cpython.datetime cimport import_datetime, datetime_new from cpython.datetime cimport import_datetime, datetime_new
import_datetime() import_datetime()

View file

@ -1,5 +1,3 @@
# coding: utf-8
from cpython cimport * from cpython cimport *
from cpython.bytearray cimport PyByteArray_Check, PyByteArray_CheckExact from cpython.bytearray cimport PyByteArray_Check, PyByteArray_CheckExact
from cpython.datetime cimport ( from cpython.datetime cimport (
@ -129,6 +127,7 @@ cdef class Packer:
if self.exports > 0: if self.exports > 0:
raise BufferError("Existing exports of data: Packer cannot be changed") raise BufferError("Existing exports of data: Packer cannot be changed")
@cython.critical_section
def __init__(self, *, default=None, def __init__(self, *, default=None,
bint use_single_float=False, bint autoreset=True, bint use_bin_type=True, bint use_single_float=False, bint autoreset=True, bint use_bin_type=True,
bint strict_types=False, bint datetime=False, unicode_errors=None, bint strict_types=False, bint datetime=False, unicode_errors=None,
@ -269,6 +268,7 @@ cdef class Packer:
return ret return ret
return self._pack_inner(o, 0, nest_limit) return self._pack_inner(o, 0, nest_limit)
@cython.critical_section
def pack(self, object obj): def pack(self, object obj):
cdef int ret cdef int ret
self._check_exports() self._check_exports()
@ -284,6 +284,7 @@ cdef class Packer:
self.pk.length = 0 self.pk.length = 0
return buf return buf
@cython.critical_section
def pack_ext_type(self, typecode, data): def pack_ext_type(self, typecode, data):
self._check_exports() self._check_exports()
if len(data) > ITEM_LIMIT: if len(data) > ITEM_LIMIT:
@ -291,6 +292,7 @@ cdef class Packer:
msgpack_pack_ext(&self.pk, typecode, len(data)) msgpack_pack_ext(&self.pk, typecode, len(data))
msgpack_pack_raw_body(&self.pk, data, len(data)) msgpack_pack_raw_body(&self.pk, data, len(data))
@cython.critical_section
def pack_array_header(self, long long size): def pack_array_header(self, long long size):
self._check_exports() self._check_exports()
if size > ITEM_LIMIT: if size > ITEM_LIMIT:
@ -301,6 +303,7 @@ cdef class Packer:
self.pk.length = 0 self.pk.length = 0
return buf return buf
@cython.critical_section
def pack_map_header(self, long long size): def pack_map_header(self, long long size):
self._check_exports() self._check_exports()
if size > ITEM_LIMIT: if size > ITEM_LIMIT:
@ -311,6 +314,7 @@ cdef class Packer:
self.pk.length = 0 self.pk.length = 0
return buf return buf
@cython.critical_section
def pack_map_pairs(self, object pairs): def pack_map_pairs(self, object pairs):
""" """
Pack *pairs* as msgpack map type. Pack *pairs* as msgpack map type.
@ -331,6 +335,7 @@ cdef class Packer:
self.pk.length = 0 self.pk.length = 0
return buf return buf
@cython.critical_section
def reset(self): def reset(self):
"""Reset internal buffer. """Reset internal buffer.
@ -339,6 +344,7 @@ cdef class Packer:
self._check_exports() self._check_exports()
self.pk.length = 0 self.pk.length = 0
@cython.critical_section
def bytes(self): def bytes(self):
"""Return internal buffer contents as bytes object""" """Return internal buffer contents as bytes object"""
return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length) return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)

View file

@ -1,5 +1,3 @@
# coding: utf-8
from cpython cimport * from cpython cimport *
cdef extern from "Python.h": cdef extern from "Python.h":
ctypedef struct PyObject ctypedef struct PyObject
@ -324,6 +322,7 @@ cdef class Unpacker:
PyMem_Free(self.buf) PyMem_Free(self.buf)
self.buf = NULL self.buf = NULL
@cython.critical_section
def __init__(self, file_like=None, *, Py_ssize_t read_size=0, def __init__(self, file_like=None, *, Py_ssize_t read_size=0,
bint use_list=True, bint raw=False, int timestamp=0, bint strict_map_key=True, bint use_list=True, bint raw=False, int timestamp=0, bint strict_map_key=True,
object object_hook=None, object object_pairs_hook=None, object list_hook=None, object object_hook=None, object object_pairs_hook=None, object list_hook=None,
@ -384,6 +383,7 @@ cdef class Unpacker:
max_str_len, max_bin_len, max_array_len, max_str_len, max_bin_len, max_array_len,
max_map_len, max_ext_len) max_map_len, max_ext_len)
@cython.critical_section
def feed(self, object next_bytes): def feed(self, object next_bytes):
"""Append `next_bytes` to internal buffer.""" """Append `next_bytes` to internal buffer."""
cdef Py_buffer pybuff cdef Py_buffer pybuff
@ -484,6 +484,7 @@ cdef class Unpacker:
else: else:
raise ValueError("Unpack failed: error = %d" % (ret,)) raise ValueError("Unpack failed: error = %d" % (ret,))
@cython.critical_section
def read_bytes(self, Py_ssize_t nbytes): def read_bytes(self, Py_ssize_t nbytes):
"""Read a specified number of raw bytes from the stream""" """Read a specified number of raw bytes from the stream"""
cdef Py_ssize_t nread cdef Py_ssize_t nread
@ -496,6 +497,7 @@ cdef class Unpacker:
self.stream_offset += nread self.stream_offset += nread
return ret return ret
@cython.critical_section
def unpack(self): def unpack(self):
"""Unpack one object """Unpack one object
@ -503,6 +505,7 @@ cdef class Unpacker:
""" """
return self._unpack(unpack_construct) return self._unpack(unpack_construct)
@cython.critical_section
def skip(self): def skip(self):
"""Read and ignore one object, returning None """Read and ignore one object, returning None
@ -510,6 +513,7 @@ cdef class Unpacker:
""" """
return self._unpack(unpack_skip) return self._unpack(unpack_skip)
@cython.critical_section
def read_array_header(self): def read_array_header(self):
"""assuming the next object is an array, return its size n, such that """assuming the next object is an array, return its size n, such that
the next n unpack() calls will iterate over its contents. the next n unpack() calls will iterate over its contents.
@ -518,6 +522,7 @@ cdef class Unpacker:
""" """
return self._unpack(read_array_header) return self._unpack(read_array_header)
@cython.critical_section
def read_map_header(self): def read_map_header(self):
"""assuming the next object is a map, return its size n, such that the """assuming the next object is a map, return its size n, such that the
next n * 2 unpack() calls will iterate over its key-value pairs. next n * 2 unpack() calls will iterate over its key-value pairs.
@ -526,6 +531,7 @@ cdef class Unpacker:
""" """
return self._unpack(read_map_header) return self._unpack(read_map_header)
@cython.critical_section
def tell(self): def tell(self):
"""Returns the current position of the Unpacker in bytes, i.e., the """Returns the current position of the Unpacker in bytes, i.e., the
number of bytes that were read from the input, also the starting number of bytes that were read from the input, also the starting
@ -536,6 +542,7 @@ cdef class Unpacker:
def __iter__(self): def __iter__(self):
return self return self
@cython.critical_section
def __next__(self): def __next__(self):
return self._unpack(unpack_construct, 1) return self._unpack(unpack_construct, 1)