@@ -99,107 +99,6 @@ cdef extern from "Python.h":
9999
100100 cdef int PyFrame_GetLineNumber(PyFrameObject * frame)
101101
102- cdef extern from " Python.h" :
103- """
104- // Check for 3.12.0b1
105- #if PY_VERSION_HEX >= 0x030c00b1
106- // This is codified in PEP 669
107- #define PY_MONITORING_PROFILER_ID 2
108- #ifndef PyImport_ImportModuleAttrString
109- // Apparently they'll add this in 3.14
110- static PyObject* PyImport_ImportModuleAttrString(
111- const char* mod_name, const char* attr_name)
112- {
113- PyObject* module = PyImport_ImportModule(mod_name);
114- if (!module) return NULL;
115- PyObject* attr = PyObject_GetAttrString(module, attr_name);
116- Py_DECREF(module);
117- return attr;
118- }
119- #endif
120- static int _is_main_thread()
121- {
122- PyObject* swap;
123- // Get the callables returning the thread objects
124- PyObject* tcurr = PyImport_ImportModuleAttrString(
125- "threading", "current_thread");
126- if (!tcurr) return 0;
127- PyObject* tmain = PyImport_ImportModuleAttrString(
128- "threading", "main_thread");
129- if (!tmain) {
130- Py_DECREF(tcurr);
131- return 0;
132- }
133- // Get the actual thread objects
134- // - Current thread
135- swap = PyObject_CallNoArgs(tcurr);
136- Py_DECREF(tcurr);
137- if (!swap) {
138- Py_DECREF(tmain);
139- return 0;
140- }
141- tcurr = swap;
142- // - Main thread
143- swap = PyObject_CallNoArgs(tmain);
144- Py_DECREF(tmain);
145- if (!swap) {
146- Py_DECREF(tcurr);
147- return 0;
148- }
149- tmain = swap;
150- // Compare
151- int result = PyObject_RichCompareBool(tcurr, tmain, Py_EQ);
152- Py_DECREF(tcurr);
153- Py_DECREF(tmain);
154- return result;
155- }
156- static void _sys_monitoring_register()
157- { // Largely copied from `_lsprof.c`
158- if (_is_main_thread() != 1) return;
159- PyObject* monitoring = PyImport_ImportModuleAttrString("sys",
160- "monitoring");
161- if (!monitoring) return;
162- PyObject* check = PyObject_CallMethod(monitoring,
163- "use_tool_id",
164- "is",
165- PY_MONITORING_PROFILER_ID,
166- "line_profiler");
167- if (!check) {
168- PyErr_Format(PyExc_ValueError,
169- "Another profiling tool is already active");
170- } else {
171- Py_DECREF(check);
172- }
173- Py_DECREF(monitoring);
174- return;
175- }
176- static void _sys_monitoring_deregister()
177- { // Largely copied from `_lsprof.c`
178- if (_is_main_thread() != 1) return;
179- PyObject* monitoring = PyImport_ImportModuleAttrString("sys",
180- "monitoring");
181- if (!monitoring) return;
182- PyObject* result = PyObject_CallMethod(monitoring,
183- "free_tool_id",
184- "i",
185- PY_MONITORING_PROFILER_ID);
186- if (!result) {
187- PyErr_Format(PyExc_RuntimeError,
188- "Error freeing the profiling tool ID");
189- } else {
190- Py_DECREF(result);
191- }
192- Py_DECREF(monitoring);
193- return;
194- }
195- #else
196- static void _sys_monitoring_register() { return; }
197- static void _sys_monitoring_deregister() { return; }
198- #endif
199- """
200- cdef void _sys_monitoring_register() except *
201- cdef void _sys_monitoring_deregister() except *
202-
203102cdef extern from " timers.c" :
204103 PY_LONG_LONG hpTimer()
205104 double hpTimerUnit()
@@ -228,6 +127,26 @@ cdef inline int64 compute_line_hash(uint64 block_hash, uint64 linenum):
228127 # so it doesn't matter
229128 return block_hash ^ linenum
230129
130+
131+ if PY_VERSION_HEX < 0x030c00b1 : # 3.12.0b1
132+ def _sys_monitoring_register () -> None: ...
133+ def _sys_monitoring_deregister() -> None: ...
134+ else:
135+ def _is_main_thread() -> bool:
136+ return threading.current_thread() == threading.main_thread()
137+
138+ def _sys_monitoring_register() -> None:
139+ if not _is_main_thread():
140+ return
141+ mon = sys.monitoring
142+ mon.use_tool_id(mon.PROFILER_ID, ' line_profiler' )
143+
144+ def _sys_monitoring_deregister () -> None:
145+ if not _is_main_thread():
146+ return
147+ mon = sys.monitoring
148+ mon.free_tool_id(mon.PROFILER_ID)
149+
231150def label (code ):
232151 """
233152 Return a (filename, first_lineno, func_name) tuple for a given code object.
0 commit comments