@@ -81,6 +81,7 @@ static int maybe_call_line_trace(Py_tracefunc, PyObject *,
8181static void maybe_dtrace_line (PyFrameObject * , PyTraceInfo * , int );
8282static void dtrace_function_entry (PyFrameObject * );
8383static void dtrace_function_return (PyFrameObject * );
84+ static int notify_thread_state_change (PyThreadState * tstate , int event , long arg );
8485
8586static PyObject * import_name (PyThreadState * , PyFrameObject * ,
8687 PyObject * , PyObject * , PyObject * );
@@ -415,18 +416,31 @@ _PyEval_Fini(void)
415416void
416417PyEval_AcquireLock (void )
417418{
419+ struct timespec start , end ;
420+ clock_gettime (CLOCK_MONOTONIC , & start );
421+
418422 _PyRuntimeState * runtime = & _PyRuntime ;
419423 PyThreadState * tstate = _PyRuntimeState_GetThreadState (runtime );
420424 _Py_EnsureTstateNotNULL (tstate );
421425
422426 take_gil (tstate );
427+
428+ clock_gettime (CLOCK_MONOTONIC , & end );
429+ long timediff = ((long )end .tv_sec - (long )start .tv_sec ) * (long )1000000
430+ + ((long )end .tv_nsec - (long )start .tv_nsec ) / 1000 ;
431+ notify_thread_state_change (tstate , PyTrace_LOCK_ACQUIRE , timediff );
423432}
424433
425434void
426435PyEval_ReleaseLock (void )
427436{
428437 _PyRuntimeState * runtime = & _PyRuntime ;
429438 PyThreadState * tstate = _PyRuntimeState_GetThreadState (runtime );
439+
440+ if (tstate != NULL ) {
441+ notify_thread_state_change (tstate , PyTrace_LOCK_RELEASE , -1 );
442+ }
443+
430444 /* This function must succeed when the current thread state is NULL.
431445 We therefore avoid PyThreadState_Get() which dumps a fatal error
432446 in debug mode. */
@@ -438,6 +452,8 @@ PyEval_ReleaseLock(void)
438452void
439453_PyEval_ReleaseLock (PyThreadState * tstate )
440454{
455+ notify_thread_state_change (tstate , PyTrace_LOCK_RELEASE , -1 );
456+
441457 struct _ceval_runtime_state * ceval = & tstate -> interp -> runtime -> ceval ;
442458 struct _ceval_state * ceval2 = & tstate -> interp -> ceval ;
443459 drop_gil (ceval , ceval2 , tstate );
@@ -448,6 +464,9 @@ PyEval_AcquireThread(PyThreadState *tstate)
448464{
449465 _Py_EnsureTstateNotNULL (tstate );
450466
467+ struct timespec start , end ;
468+ clock_gettime (CLOCK_MONOTONIC , & start );
469+
451470 take_gil (tstate );
452471
453472 struct _gilstate_runtime_state * gilstate = & tstate -> interp -> runtime -> gilstate ;
@@ -458,13 +477,20 @@ PyEval_AcquireThread(PyThreadState *tstate)
458477 Py_FatalError ("non-NULL old thread state" );
459478 }
460479#endif
480+
481+ clock_gettime (CLOCK_MONOTONIC , & end );
482+ long timediff = ((long )end .tv_sec - (long )start .tv_sec ) * (long )1000000
483+ + ((long )end .tv_nsec - (long )start .tv_nsec ) / 1000 ;
484+ notify_thread_state_change (tstate , PyTrace_THREAD_ACQUIRE , timediff );
461485}
462486
463487void
464488PyEval_ReleaseThread (PyThreadState * tstate )
465489{
466490 assert (is_tstate_valid (tstate ));
467491
492+ notify_thread_state_change (tstate , PyTrace_THREAD_RELEASE , -1 );
493+
468494 _PyRuntimeState * runtime = tstate -> interp -> runtime ;
469495 PyThreadState * new_tstate = _PyThreadState_Swap (& runtime -> gilstate , NULL );
470496 if (new_tstate != tstate ) {
@@ -519,12 +545,16 @@ _PyEval_SignalAsyncExc(PyInterpreterState *interp)
519545PyThreadState *
520546PyEval_SaveThread (void )
521547{
548+ PyThreadState * tstate = PyGILState_GetThisThreadState ();
549+ if (tstate != NULL ) {
550+ notify_thread_state_change (tstate , PyTrace_THREAD_SAVE , -1 );
551+ }
522552 _PyRuntimeState * runtime = & _PyRuntime ;
523553#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
524554 PyThreadState * old_tstate = _PyThreadState_GET ();
525- PyThreadState * tstate = _PyThreadState_Swap (& runtime -> gilstate , old_tstate );
555+ tstate = _PyThreadState_Swap (& runtime -> gilstate , old_tstate );
526556#else
527- PyThreadState * tstate = _PyThreadState_Swap (& runtime -> gilstate , NULL );
557+ tstate = _PyThreadState_Swap (& runtime -> gilstate , NULL );
528558#endif
529559 _Py_EnsureTstateNotNULL (tstate );
530560
@@ -544,10 +574,18 @@ PyEval_RestoreThread(PyThreadState *tstate)
544574{
545575 _Py_EnsureTstateNotNULL (tstate );
546576
577+ struct timespec start , end ;
578+ clock_gettime (CLOCK_MONOTONIC , & start );
579+
547580 take_gil (tstate );
548581
549582 struct _gilstate_runtime_state * gilstate = & tstate -> interp -> runtime -> gilstate ;
550583 _PyThreadState_Swap (gilstate , tstate );
584+
585+ clock_gettime (CLOCK_MONOTONIC , & end );
586+ long timediff = ((long )end .tv_sec - (long )start .tv_sec ) * (long )1000000
587+ + ((long )end .tv_nsec - (long )start .tv_nsec ) / 1000 ;
588+ notify_thread_state_change (tstate , PyTrace_THREAD_RESTORE , timediff );
551589}
552590
553591
@@ -1177,7 +1215,9 @@ eval_frame_handle_pending(PyThreadState *tstate)
11771215 }
11781216
11791217 /* GIL drop request */
1180- if (_Py_atomic_load_relaxed (& ceval2 -> gil_drop_request )) {
1218+ if (_Py_atomic_load_relaxed (& ceval2 -> gil_drop_request ) && !tstate -> tracing ) {
1219+
1220+ notify_thread_state_change (tstate , PyTrace_THREAD_PREEMPT , -1 );
11811221 /* Give another thread a chance */
11821222 if (_PyThreadState_Swap (& runtime -> gilstate , NULL ) != tstate ) {
11831223 Py_FatalError ("tstate mix-up" );
@@ -1186,6 +1226,9 @@ eval_frame_handle_pending(PyThreadState *tstate)
11861226
11871227 /* Other threads may run now */
11881228
1229+ struct timespec start , end ;
1230+ clock_gettime (CLOCK_MONOTONIC , & start );
1231+
11891232 take_gil (tstate );
11901233
11911234#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
@@ -1195,6 +1238,11 @@ eval_frame_handle_pending(PyThreadState *tstate)
11951238 Py_FatalError ("orphan tstate" );
11961239 }
11971240#endif
1241+
1242+ clock_gettime (CLOCK_MONOTONIC , & end );
1243+ long timediff = ((long )end .tv_sec - (long )start .tv_sec ) * (long )1000000
1244+ + ((long )end .tv_nsec - (long )start .tv_nsec ) / 1000 ;
1245+ notify_thread_state_change (tstate , PyTrace_THREAD_RESUME , timediff );
11981246 }
11991247
12001248 /* Check for asynchronous exception. */
@@ -5572,6 +5620,27 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
55725620 }
55735621}
55745622
5623+ void
5624+ PyEval_SetProfileAllThreads (Py_tracefunc func , PyObject * arg )
5625+ {
5626+ PyThreadState * this_tstate = _PyThreadState_GET ();
5627+ PyInterpreterState * interp = this_tstate -> interp ;
5628+
5629+ /* unused var _PyRuntimeState *runtime = &_PyRuntime; */
5630+ /* missing call to HEAD_LOCK(runtime); */
5631+ PyThreadState * ts = PyInterpreterState_ThreadHead (interp );
5632+ /* missing call to HEAD_UNLOCK(runtime); */
5633+
5634+ while (ts ) {
5635+ if (_PyEval_SetProfile (ts , func , arg ) < 0 ) {
5636+ _PyErr_WriteUnraisableMsg ("Exception ignored in PyEval_SetProfileAllThreads" , NULL );
5637+ }
5638+ /* missing call to HEAD_LOCK(runtime); */
5639+ ts = PyThreadState_Next (ts );
5640+ /* missing call to HEAD_UNLOCK(runtime); */
5641+ }
5642+ }
5643+
55755644int
55765645_PyEval_SetTrace (PyThreadState * tstate , Py_tracefunc func , PyObject * arg )
55775646{
@@ -6512,6 +6581,31 @@ maybe_dtrace_line(PyFrameObject *frame,
65126581 }
65136582}
65146583
6584+ static int
6585+ notify_thread_state_change (PyThreadState * tstate , int event , long arg )
6586+ {
6587+ if (tstate -> c_profilefunc == NULL )
6588+ return 0 ;
6589+ PyObject * arg_obj = Py_None ;
6590+ if (arg >= 0 ) {
6591+ arg_obj = PyLong_FromLong (arg );
6592+ }
6593+ if (arg_obj == NULL ) {
6594+ return -1 ;
6595+ }
6596+ PyTraceInfo trace_info ;
6597+ /* Mark trace_info as uninitialized */
6598+ trace_info .code = NULL ;
6599+ int res = call_trace_protected (tstate -> c_profilefunc ,
6600+ tstate -> c_profileobj ,
6601+ tstate , tstate -> frame ,
6602+ & trace_info ,
6603+ event , arg_obj );
6604+ if (arg_obj != Py_None ) {
6605+ Py_DECREF (arg_obj );
6606+ }
6607+ return res ;
6608+ }
65156609
65166610/* Implement Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() as functions
65176611 for the limited API. */
0 commit comments