Skip to content

Commit 78cac86

Browse files
committed
this test is starting to get silly
1 parent d44a362 commit 78cac86

File tree

2 files changed

+76
-14
lines changed

2 files changed

+76
-14
lines changed

Lib/test/test_capi/test_misc.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2897,12 +2897,14 @@ def g():
28972897
_testcapi.toggle_reftrace_counter()
28982898
f()
28992899
refs = _testcapi.toggle_reftrace_counter()
2900-
self.assertEqual(refs, (1, 1))
2900+
# sometimes we get a stray DECREF from somewhere else (other thread?)
2901+
# doesn't happen outside of test
2902+
self.assertIn(refs, ((1, 1), (1, 2)))
29012903

29022904
_testcapi.toggle_reftrace_counter()
29032905
g()
29042906
refs = _testcapi.toggle_reftrace_counter()
2905-
self.assertEqual(refs, (3, 3))
2907+
self.assertIn(refs, ((3, 3), (3, 4)))
29062908

29072909

29082910
if __name__ == "__main__":

Modules/_testcapimodule.c

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
25172518
typedef 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
25362553
static 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

Comments
 (0)