Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions Include/cpython/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -495,3 +495,82 @@ PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(PyObject *);
PyAPI_FUNC(int) PyUnstable_Object_IsUniquelyReferenced(PyObject *);

PyAPI_FUNC(int) PyUnstable_SetImmortal(PyObject *op);

#if defined(Py_GIL_DISABLED)
PyAPI_FUNC(uintptr_t) _Py_GetThreadLocal_Addr(void);

static inline uintptr_t
_Py_ThreadId(void)
{
uintptr_t tid;
#if defined(_MSC_VER) && defined(_M_X64)
tid = __readgsqword(48);
#elif defined(_MSC_VER) && defined(_M_IX86)
tid = __readfsdword(24);
#elif defined(_MSC_VER) && defined(_M_ARM64)
tid = __getReg(18);
#elif defined(__MINGW32__) && defined(_M_X64)
tid = __readgsqword(48);
#elif defined(__MINGW32__) && defined(_M_IX86)
tid = __readfsdword(24);
#elif defined(__MINGW32__) && defined(_M_ARM64)
tid = __getReg(18);
#elif defined(__i386__)
__asm__("{movl %%gs:0, %0|mov %0, dword ptr gs:[0]}" : "=r" (tid)); // 32-bit always uses GS
#elif defined(__MACH__) && defined(__x86_64__)
__asm__("{movq %%gs:0, %0|mov %0, qword ptr gs:[0]}" : "=r" (tid)); // x86_64 macOSX uses GS
#elif defined(__x86_64__)
__asm__("{movq %%fs:0, %0|mov %0, qword ptr fs:[0]}" : "=r" (tid)); // x86_64 Linux, BSD uses FS
#elif defined(__arm__) && __ARM_ARCH >= 7
__asm__ ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tid));
#elif defined(__aarch64__) && defined(__APPLE__)
__asm__ ("mrs %0, tpidrro_el0" : "=r" (tid));
#elif defined(__aarch64__)
__asm__ ("mrs %0, tpidr_el0" : "=r" (tid));
#elif defined(__powerpc64__)
#if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer)
tid = (uintptr_t)__builtin_thread_pointer();
#else
// r13 is reserved for use as system thread ID by the Power 64-bit ABI.
register uintptr_t tp __asm__ ("r13");
__asm__("" : "=r" (tp));
tid = tp;
#endif
#elif defined(__powerpc__)
#if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer)
tid = (uintptr_t)__builtin_thread_pointer();
#else
// r2 is reserved for use as system thread ID by the Power 32-bit ABI.
register uintptr_t tp __asm__ ("r2");
__asm__ ("" : "=r" (tp));
tid = tp;
#endif
#elif defined(__s390__) && defined(__GNUC__)
// Both GCC and Clang have supported __builtin_thread_pointer
// for s390 from long time ago.
tid = (uintptr_t)__builtin_thread_pointer();
#elif defined(__riscv)
#if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer)
tid = (uintptr_t)__builtin_thread_pointer();
#else
// tp is Thread Pointer provided by the RISC-V ABI.
__asm__ ("mv %0, tp" : "=r" (tid));
#endif
#else
// Fallback to a portable implementation if we do not have a faster
// platform-specific implementation.
tid = _Py_GetThreadLocal_Addr();
#endif
return tid;
}

static inline Py_ALWAYS_INLINE int
_Py_IsOwnedByCurrentThread(PyObject *ob)
{
#ifdef _Py_THREAD_SANITIZER
return _Py_atomic_load_uintptr_relaxed(&ob->ob_tid) == _Py_ThreadId();
#else
return ob->ob_tid == _Py_ThreadId();
#endif
}
#endif
4 changes: 3 additions & 1 deletion Include/moduleobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,10 @@ struct PyModuleDef_Slot {
# define Py_MOD_GIL_NOT_USED ((void *)1)
#endif

#if !defined(Py_LIMITED_API) && defined(Py_GIL_DISABLED)
#if !defined(Py_LIMITED_API)
# if defined(Py_GIL_DISABLED)
PyAPI_FUNC(int) PyUnstable_Module_SetGIL(PyObject *module, void *gil);
# endif
#endif

#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)
Expand Down
85 changes: 4 additions & 81 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,85 +186,6 @@ typedef struct PyVarObject PyVarObject;
PyAPI_FUNC(int) Py_Is(PyObject *x, PyObject *y);
#define Py_Is(x, y) ((x) == (y))

#if defined(Py_GIL_DISABLED) && !defined(Py_LIMITED_API)
PyAPI_FUNC(uintptr_t) _Py_GetThreadLocal_Addr(void);

static inline uintptr_t
_Py_ThreadId(void)
{
uintptr_t tid;
#if defined(_MSC_VER) && defined(_M_X64)
tid = __readgsqword(48);
#elif defined(_MSC_VER) && defined(_M_IX86)
tid = __readfsdword(24);
#elif defined(_MSC_VER) && defined(_M_ARM64)
tid = __getReg(18);
#elif defined(__MINGW32__) && defined(_M_X64)
tid = __readgsqword(48);
#elif defined(__MINGW32__) && defined(_M_IX86)
tid = __readfsdword(24);
#elif defined(__MINGW32__) && defined(_M_ARM64)
tid = __getReg(18);
#elif defined(__i386__)
__asm__("{movl %%gs:0, %0|mov %0, dword ptr gs:[0]}" : "=r" (tid)); // 32-bit always uses GS
#elif defined(__MACH__) && defined(__x86_64__)
__asm__("{movq %%gs:0, %0|mov %0, qword ptr gs:[0]}" : "=r" (tid)); // x86_64 macOSX uses GS
#elif defined(__x86_64__)
__asm__("{movq %%fs:0, %0|mov %0, qword ptr fs:[0]}" : "=r" (tid)); // x86_64 Linux, BSD uses FS
#elif defined(__arm__) && __ARM_ARCH >= 7
__asm__ ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tid));
#elif defined(__aarch64__) && defined(__APPLE__)
__asm__ ("mrs %0, tpidrro_el0" : "=r" (tid));
#elif defined(__aarch64__)
__asm__ ("mrs %0, tpidr_el0" : "=r" (tid));
#elif defined(__powerpc64__)
#if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer)
tid = (uintptr_t)__builtin_thread_pointer();
#else
// r13 is reserved for use as system thread ID by the Power 64-bit ABI.
register uintptr_t tp __asm__ ("r13");
__asm__("" : "=r" (tp));
tid = tp;
#endif
#elif defined(__powerpc__)
#if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer)
tid = (uintptr_t)__builtin_thread_pointer();
#else
// r2 is reserved for use as system thread ID by the Power 32-bit ABI.
register uintptr_t tp __asm__ ("r2");
__asm__ ("" : "=r" (tp));
tid = tp;
#endif
#elif defined(__s390__) && defined(__GNUC__)
// Both GCC and Clang have supported __builtin_thread_pointer
// for s390 from long time ago.
tid = (uintptr_t)__builtin_thread_pointer();
#elif defined(__riscv)
#if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer)
tid = (uintptr_t)__builtin_thread_pointer();
#else
// tp is Thread Pointer provided by the RISC-V ABI.
__asm__ ("mv %0, tp" : "=r" (tid));
#endif
#else
// Fallback to a portable implementation if we do not have a faster
// platform-specific implementation.
tid = _Py_GetThreadLocal_Addr();
#endif
return tid;
}

static inline Py_ALWAYS_INLINE int
_Py_IsOwnedByCurrentThread(PyObject *ob)
{
#ifdef _Py_THREAD_SANITIZER
return _Py_atomic_load_uintptr_relaxed(&ob->ob_tid) == _Py_ThreadId();
#else
return ob->ob_tid == _Py_ThreadId();
#endif
}
#endif

PyAPI_DATA(PyTypeObject) PyLong_Type;
PyAPI_DATA(PyTypeObject) PyBool_Type;

Expand Down Expand Up @@ -652,8 +573,10 @@ given type object has a specified feature.
#define _Py_IMMORTAL_FLAGS (1 << 0)
#define _Py_LEGACY_ABI_CHECK_FLAG (1 << 1) /* see PyModuleDef_Init() */
#define _Py_STATICALLY_ALLOCATED_FLAG (1 << 2)
#if defined(Py_GIL_DISABLED) && defined(Py_DEBUG)
#define _Py_TYPE_REVEALED_FLAG (1 << 3)
#if !defined(Py_LIMITED_API)
# if defined(Py_GIL_DISABLED) && defined(Py_DEBUG)
# define _Py_TYPE_REVEALED_FLAG (1 << 3)
# endif
#endif

#define Py_CONSTANT_NONE 0
Expand Down
19 changes: 19 additions & 0 deletions Include/pyport.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,25 @@
# define Py_BUILD_CORE
#endif

#if defined(Py_TARGET_ABI3T)
# if !defined(Py_GIL_DISABLED)
// Define Py_GIL_DISABLED for users' needs. This macro is used to enable
// locking needed in for free-threaded interpreters builds.
# define Py_GIL_DISABLED
# endif
# if defined(_Py_IS_TESTCEXT)
// When compiling for abi3t, contents of Python.h should not depend
// on Py_GIL_DISABLED.
// We ask GCC to error if it sees the macro from this point on.
// Since users are free to the macro, and there's no way to undo the poisoning
// at the end of Python.h, we only do this in a test module.
# ifdef __GNUC__
# undef Py_GIL_DISABLED
# pragma GCC poison Py_GIL_DISABLED
# endif
# endif
#endif


/**************************************************************************
Symbols and macros to supply platform-independent interfaces to basic
Expand Down
35 changes: 21 additions & 14 deletions Include/refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extern "C" {
#endif


#if !defined(_Py_OPAQUE_PYOBJECT)
/*
Immortalization:

Expand Down Expand Up @@ -90,14 +91,16 @@ check by comparing the reference count field to the minimum immortality refcount
# define _Py_REF_SHARED(refcnt, flags) \
(((refcnt) << _Py_REF_SHARED_SHIFT) + (flags))
#endif // Py_GIL_DISABLED

#endif // _Py_OPAQUE_PYOBJECT

// Py_REFCNT() implementation for the stable ABI
PyAPI_FUNC(Py_ssize_t) Py_REFCNT(PyObject *ob);

#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030e0000
// Stable ABI implements Py_REFCNT() as a function call
// on limited C API version 3.14 and newer.
// on limited C API version 3.14 and newer, and on abi3t.
#elif defined(_Py_OPAQUE_PYOBJECT)
// Py_REFCNT() is also a function call in abi3t.
#else
static inline Py_ssize_t _Py_REFCNT(PyObject *ob) {
#if !defined(Py_GIL_DISABLED)
Expand Down Expand Up @@ -150,9 +153,10 @@ PyAPI_FUNC(void) _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt);

static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
assert(refcnt >= 0);
#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030d0000
#if (defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030d0000) \
|| defined(_Py_OPAQUE_PYOBJECT)
// Stable ABI implements Py_SET_REFCNT() as a function call
// on limited C API version 3.13 and newer.
// on limited C API version 3.13 and newer, and abi3t.
_Py_SetRefcnt(ob, refcnt);
#else
// This immortal check is for code that is unaware of immortal objects.
Expand Down Expand Up @@ -191,7 +195,7 @@ static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
ob->ob_ref_shared = _Py_REF_SHARED(refcnt, _Py_REF_MERGED);
}
#endif // Py_GIL_DISABLED
#endif // Py_LIMITED_API+0 < 0x030d0000
#endif // Py_LIMITED_API
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_SET_REFCNT(ob, refcnt) Py_SET_REFCNT(_PyObject_CAST(ob), (refcnt))
Expand Down Expand Up @@ -250,10 +254,11 @@ PyAPI_FUNC(void) _Py_DecRef(PyObject *);

static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
{
#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG))
#if (defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG))) \
|| defined(_Py_OPAQUE_PYOBJECT)
// Stable ABI implements Py_INCREF() as a function call on limited C API
// version 3.12 and newer, and on Python built in debug mode. _Py_IncRef()
// was added to Python 3.10.0a7, use Py_IncRef() on older Python versions.
// version 3.12 and newer, abi3t, and on Python built in debug mode.
// _Py_IncRef() was added to Python 3.10.0a7, use Py_IncRef() on older versions.
// Py_IncRef() accepts NULL whereas _Py_IncRef() doesn't.
# if Py_LIMITED_API+0 >= 0x030a00A7
_Py_IncRef(op);
Expand Down Expand Up @@ -305,8 +310,8 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
# define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op))
#endif


#if !defined(Py_LIMITED_API) && defined(Py_GIL_DISABLED)
#if !defined(Py_LIMITED_API)
#if defined(Py_GIL_DISABLED)
// Implements Py_DECREF on objects not owned by the current thread.
PyAPI_FUNC(void) _Py_DecRefShared(PyObject *);
PyAPI_FUNC(void) _Py_DecRefSharedDebug(PyObject *, const char *, int);
Expand All @@ -316,12 +321,14 @@ PyAPI_FUNC(void) _Py_DecRefSharedDebug(PyObject *, const char *, int);
// zero. Otherwise, the thread gives up ownership and merges the reference
// count fields.
PyAPI_FUNC(void) _Py_MergeZeroLocalRefcount(PyObject *);
#endif
#endif // Py_GIL_DISABLED
#endif // Py_LIMITED_API

#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG))
#if (defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG))) \
|| defined(_Py_OPAQUE_PYOBJECT)
// Stable ABI implements Py_DECREF() as a function call on limited C API
// version 3.12 and newer, and on Python built in debug mode. _Py_DecRef() was
// added to Python 3.10.0a7, use Py_DecRef() on older Python versions.
// version 3.12 and newer, abi3t, and on Python built in debug mode.
// _Py_DecRef() was added to Python 3.10.0a7, use Py_DecRef() on older versions.
// Py_DecRef() accepts NULL whereas _Py_DecRef() doesn't.
static inline void Py_DECREF(PyObject *op) {
# if Py_LIMITED_API+0 >= 0x030a00A7
Expand Down
5 changes: 5 additions & 0 deletions Lib/test/test_cext/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
# The purpose of test_cext extension is to check that building a C
# extension using the Python C API does not emit C compiler warnings.
'-Werror',
# Enable extra checks for header files, which:
# - need to be enabled somewhere inside Python headers (rather than
# before including Python.h)
# - should not be checked for user code
'-D_Py_IS_TESTCEXT',
]

# C compiler flags for GCC and clang
Expand Down
Loading