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
2 changes: 1 addition & 1 deletion line_profiler/_line_profiler.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ ctypedef PyCodeObject *PyCodeObjectPtr
#ctypedef unordered_map[int64, LastTime] LastTimeMap
#ctypedef unordered_map[int64, LineTime] LineTimeMap

cdef extern from "c_trace_callbacks.c": # Legacy tracing
cdef extern from "c_trace_callbacks.h": # Legacy tracing
ctypedef unsigned long long Py_uintptr_t

ctypedef struct TraceCallback:
Expand Down
67 changes: 67 additions & 0 deletions line_profiler/c_trace_callbacks.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,72 @@
#include "c_trace_callbacks.h"

/*
* XXX: would make better sense to declare `PyInterpreterState` in
* "Python_wrapper.h", but the file declaring it causes all sorts of
* trouble across various platforms and Python versions... so we handle it here.
*
* Note that we don't actually use `PyInterpreterState` directly -- we just
* need its memory layout so that we can refer to its `.last_restart_version` member.
*/

// _is -> PyInterpreterState
#if PY_VERSION_HEX >= 0x030c00b1 // 3.12.0b6
# ifndef Py_BUILD_CORE
# define Py_BUILD_CORE 1
# endif
# if PY_VERSION_HEX < 0x030d0000 // 3.13
/*
* - Undefine the `_PyGC_FINALIZED()` macro which is removed in 3.13+
* and causes problems in 3.12 (see CPython #105268, #105350, #107348)
* - Undefine the `HAVE_STD_ATOMIC` macro, which causes problems on
* Linux in 3.12 (see CPython #108216)
* - Set `Py_ATOMIC_H` to true to circumvent the #include of
* `include/pycore_atomic.h` (in `include/pycore_interp.h`, so that
* problematic function definitions therein are replaced with dummy
* ones (see #390); note that we still need to vendor in parts
* therefrom which are used by `pycore_interp.h`, and its dependencies
* `pycore_ceval_state.h` and `pycore_gil.h` (or at least mock them)
*/
# undef _PyGC_FINALIZED
# ifdef __linux__
# undef HAVE_STD_ATOMIC
# endif
# if (defined(_M_ARM) || defined(_M_ARM64)) && (! defined(Py_ATOMIC_H))
# define Py_ATOMIC_H
// Used in `pycore_interp.h`
typedef struct _Py_atomic_address {
volatile uintptr_t _value;
} _Py_atomic_address;
// Used in `pycore_gil.h` and `pycore_ceval_state.h`
typedef struct _Py_atomic_int {
volatile int _value;
} _Py_atomic_int;
/* Stub out macros in `pycore_atomic.h` used in macros in
* `pycore_interp.h` (which aren't related to the
* `struct _is` we need).
* If any stub is referenced, fail the build with an
* unresolved external.
* This ensures we never ship wheels that "use" these
* placeholders. */
# ifdef _MSC_VER
__declspec(dllimport) void lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(void);
__declspec(dllimport) void lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(void);
# else
extern void lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(void);
extern void lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(void);
# endif
# define _LP_ATOMIC_PANIC_LOAD_EXPR() (lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(), 0)
# define _LP_ATOMIC_PANIC_STORE_STMT() do { lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(); } while (0)
// Panic-on-use shims (expression/statement forms)
# undef _Py_atomic_load_relaxed
# undef _Py_atomic_store_relaxed
# define _Py_atomic_load_relaxed(obj) ((void)(obj), _LP_ATOMIC_PANIC_LOAD_EXPR())
# define _Py_atomic_store_relaxed(obj, val) do { (void)(obj); (void)(val); _LP_ATOMIC_PANIC_STORE_STMT(); } while (0)
# endif
# endif
# include "internal/pycore_interp.h"
#endif

#define CYTHON_MODULE "line_profiler._line_profiler"
#define DISABLE_CALLBACK "disable_line_events"
#define RAISE_IN_CALL(func_name, xc, const_msg) \
Expand Down
71 changes: 6 additions & 65 deletions line_profiler/c_trace_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,8 @@
#include "Python_wrapper.h"
#include "frameobject.h"

/*
* XXX: would make better sense to declare `PyInterpreterState` in
* "Python_wrapper.h", but the file declaring it causes all sorts of
* trouble across various platforms and Python versions... so
* - Only include the file if we are actually using it here, i.e. in
* 3.12+, and
* - Undefine the `_PyGC_FINALIZED()` macro which is removed in 3.13+
* and causes problems in 3.12 (see CPython #105268, #105350, #107348)
* - Undefine the `HAVE_STD_ATOMIC` macro, which causes problems on
* Linux in 3.12 (see CPython #108216)
* - Set `Py_ATOMIC_H` to true to circumvent the #include of
* `include/pycore_atomic.h` (in `include/pycore_interp.h`, so that
* problematic function definitions therein are replaced with dummy
* ones (see #390); note that we still need to vendor in parts
* therefrom which are used by `pycore_interp.h`, and its dependencies
* `pycore_ceval_state.h` and `pycore_gil.h` (or at least mock them)
* Note in any case that we don't actually use `PyInterpreterState`
* directly -- we just need its memory layout so that we can refer to
* its `.last_restart_version` member
*/

// _is -> PyInterpreterState
#if PY_VERSION_HEX >= 0x030c00b1 // 3.12.0b6
# ifndef Py_BUILD_CORE
# define Py_BUILD_CORE 1
# endif
# if PY_VERSION_HEX < 0x030d0000 // 3.13
# undef _PyGC_FINALIZED
# ifdef __linux__
# undef HAVE_STD_ATOMIC
# endif
# if (defined(_M_ARM) || defined(_M_ARM64)) && (! defined(Py_ATOMIC_H))
# define Py_ATOMIC_H
// Used in `pycore_interp.h`
typedef struct _Py_atomic_address {
volatile uintptr_t _value;
} _Py_atomic_address;
// Used in `pycore_gil.h` and `pycore_ceval_state.h`
typedef struct _Py_atomic_int {
volatile int _value;
} _Py_atomic_int;
/* Stub out macros in `pycore_atomic.h` used in macros in
* `pycore_interp.h` (which aren't related to the
* `struct _is` we need).
* If any stub is referenced, fail the build with an
* unresolved external.
* This ensures we never ship wheels that "use" these
* placeholders. */
# ifdef _MSC_VER
__declspec(dllimport) void lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(void);
__declspec(dllimport) void lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(void);
# else
extern void lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(void);
extern void lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(void);
# endif
# define _LP_ATOMIC_PANIC_LOAD_EXPR() (lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(), 0)
# define _LP_ATOMIC_PANIC_STORE_STMT() do { lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(); } while (0)
// Panic-on-use shims (expression/statement forms)
# undef _Py_atomic_load_relaxed
# undef _Py_atomic_store_relaxed
# define _Py_atomic_load_relaxed(obj) ((void)(obj), _LP_ATOMIC_PANIC_LOAD_EXPR())
# define _Py_atomic_store_relaxed(obj, val) do { (void)(obj); (void)(val); _LP_ATOMIC_PANIC_STORE_STMT(); } while (0)
# endif
# endif
# include "internal/pycore_interp.h"
#ifdef __cplusplus
extern "C" {
#endif

typedef struct TraceCallback
Expand Down Expand Up @@ -103,4 +40,8 @@ int call_callback(
void set_local_trace(PyObject *manager, PyFrameObject *py_frame);
Py_uintptr_t monitoring_restart_version();

#ifdef __cplusplus
}
#endif

#endif // LINE_PROFILER_C_TRACE_CALLBACKS_H
Loading