@@ -2514,6 +2514,7 @@ code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf)
25142514 return PyLong_FromInt32 (PyCode_Addr2Line (code , offset ));
25152515}
25162516
2517+
25172518typedef struct {
25182519 Py_ssize_t create_count ;
25192520 Py_ssize_t destroy_count ;
@@ -2526,34 +2527,93 @@ _reftrace_counter(PyObject *obj, PyRefTracerEvent event, void *counter_data)
25262527{
25272528 if (event == PyRefTracer_CREATE ) {
25282529 ((reftrace_counter_data * )counter_data )-> create_count ++ ;
2529- } else {
2530+ }
2531+ else { // PyRefTracer_DESTROY
25302532 ((reftrace_counter_data * )counter_data )-> destroy_count ++ ;
25312533 }
25322534 return 0 ;
25332535}
25342536
2535- // A very simple reftrace counter for very simple tests
2537+ void
2538+ reftrace_counter_capsule_destructor (PyObject * capsule )
2539+ {
2540+ reftrace_counter_data * counter_data = (reftrace_counter_data * )PyCapsule_GetPointer (capsule , "counter_data" );
2541+
2542+ if (counter_data ) {
2543+ if (counter_data -> prev_tracer != (void * )_reftrace_counter ) {
2544+ // juuust in case, to not segfault
2545+ PyRefTracer_SetTracer (counter_data -> prev_tracer , counter_data -> prev_data );
2546+ }
2547+
2548+ PyMem_Free (counter_data );
2549+ }
2550+ }
2551+
2552+ // A simple reftrace counter for very simple tests
25362553static PyObject *
2537- toggle_reftrace_counter (PyObject * ob , PyObject * Py_UNUSED ( args ) )
2554+ toggle_reftrace_counter (PyObject * ob , PyObject * args )
25382555{
2539- static reftrace_counter_data counter_data = {0 , 0 , NULL , (void * )toggle_reftrace_counter }; // sentinel
2556+ reftrace_counter_data * counter_data ;
2557+ PyObject * capsule ;
2558+
2559+ if (PyObject_GetOptionalAttrString (ob , "_reftrace_counter_data" , & capsule )) {
2560+ if (!PyCapsule_IsValid (capsule , "counter_data" )) {
2561+ PyErr_SetString (PyExc_ValueError , "something went wrong, _reftrace_counter_data is invalid" );
2562+ return NULL ;
2563+ }
2564+
2565+ counter_data = PyCapsule_GetPointer (capsule , "counter_data" );
2566+
2567+ if (counter_data == NULL ) {
2568+ PyErr_SetString (PyExc_ValueError , "something went wrong, _reftrace_counter_data is invalid" );
2569+ return NULL ;
2570+ }
2571+ }
2572+ else {
2573+ counter_data = (reftrace_counter_data * )PyMem_Malloc (sizeof (reftrace_counter_data ));
25402574
2541- if (counter_data .prev_tracer == (void * )toggle_reftrace_counter ) {
2575+ if (counter_data == NULL ) {
2576+ PyErr_NoMemory ();
2577+ return NULL ;
2578+ }
2579+
2580+ capsule = PyCapsule_New (counter_data , "counter_data" , reftrace_counter_capsule_destructor );
2581+
2582+ if (capsule == NULL ) {
2583+ PyMem_Free (counter_data );
2584+ return NULL ;
2585+ }
2586+
2587+ counter_data -> prev_tracer = (void * )_reftrace_counter ; // sentinel
2588+
2589+ if (PyModule_Add (ob , "_reftrace_counter_data" , capsule )) {
2590+ return NULL ;
2591+ }
2592+
2593+ Py_INCREF (capsule );
2594+ }
2595+
2596+ if (counter_data -> prev_tracer == (void * )_reftrace_counter ) {
25422597 // toggle counter on
2543- counter_data . create_count = counter_data . destroy_count = 0 ;
2544- counter_data . prev_tracer = PyRefTracer_GetTracer (& counter_data . prev_data );
2598+ counter_data -> create_count = counter_data -> destroy_count = 0 ;
2599+ counter_data -> prev_tracer = PyRefTracer_GetTracer (& counter_data -> prev_data );
25452600
2546- PyRefTracer_SetTracer (_reftrace_counter , & counter_data );
2601+ PyRefTracer_SetTracer (_reftrace_counter , counter_data );
25472602
2603+ Py_DECREF (capsule );
25482604 Py_RETURN_NONE ;
25492605 }
25502606
25512607 // toggle counter off
2552- PyRefTracer_SetTracer (counter_data .prev_tracer , counter_data .prev_data );
2608+ PyRefTracer_SetTracer (counter_data -> prev_tracer , counter_data -> prev_data );
2609+
2610+ Py_ssize_t create_count = counter_data -> create_count - 1 ; // because of PyObject_GetOptionalAttrString
2611+ Py_ssize_t destroy_count = counter_data -> destroy_count ;
2612+ counter_data -> prev_tracer = (void * )_reftrace_counter ;
25532613
2554- counter_data . prev_tracer = ( void * ) toggle_reftrace_counter ;
2614+ Py_DECREF ( capsule ) ;
25552615
2556- return Py_BuildValue ("(nn)" , counter_data . create_count , counter_data . destroy_count );
2616+ return Py_BuildValue ("(nn)" , create_count , destroy_count );
25572617}
25582618
25592619
@@ -2650,7 +2710,7 @@ static PyMethodDef TestMethods[] = {
26502710 {"finalize_thread_hang" , finalize_thread_hang , METH_O , NULL },
26512711 {"test_atexit" , test_atexit , METH_NOARGS },
26522712 {"code_offset_to_line" , _PyCFunction_CAST (code_offset_to_line ), METH_FASTCALL },
2653- {"toggle_reftrace_counter" , toggle_reftrace_counter , METH_NOARGS },
2713+ {"toggle_reftrace_counter" , toggle_reftrace_counter , METH_VARARGS },
26542714 {NULL , NULL } /* sentinel */
26552715};
26562716
0 commit comments