mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-128679: Redesign tracemalloc locking (#128888)
* Use TABLES_LOCK() to protect 'tracemalloc_config.tracing'. * Hold TABLES_LOCK() longer while accessing tables. * tracemalloc_realloc() and tracemalloc_free() no longer remove the trace on reentrant call. * _PyTraceMalloc_Stop() unregisters _PyTraceMalloc_TraceRef(). * _PyTraceMalloc_GetTraces() sets the reentrant flag. * tracemalloc_clear_traces_unlocked() sets the reentrant flag.
This commit is contained in:
parent
080f444a58
commit
36c5e3bcc2
5 changed files with 302 additions and 364 deletions
|
@ -299,12 +299,6 @@ Py_ssize_t _Py_ExplicitMergeRefcount(PyObject *op, Py_ssize_t extra);
|
||||||
extern int _PyType_CheckConsistency(PyTypeObject *type);
|
extern int _PyType_CheckConsistency(PyTypeObject *type);
|
||||||
extern int _PyDict_CheckConsistency(PyObject *mp, int check_content);
|
extern int _PyDict_CheckConsistency(PyObject *mp, int check_content);
|
||||||
|
|
||||||
/* Update the Python traceback of an object. This function must be called
|
|
||||||
when a memory block is reused from a free list.
|
|
||||||
|
|
||||||
Internal function called by _Py_NewReference(). */
|
|
||||||
extern int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, void*);
|
|
||||||
|
|
||||||
// Fast inlined version of PyType_HasFeature()
|
// Fast inlined version of PyType_HasFeature()
|
||||||
static inline int
|
static inline int
|
||||||
_PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
|
_PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ struct _PyTraceMalloc_Config {
|
||||||
} initialized;
|
} initialized;
|
||||||
|
|
||||||
/* Is tracemalloc tracing memory allocations?
|
/* Is tracemalloc tracing memory allocations?
|
||||||
Variable protected by the GIL */
|
Variable protected by the TABLES_LOCK(). */
|
||||||
int tracing;
|
int tracing;
|
||||||
|
|
||||||
/* limit of the number of frames in a traceback, 1 by default.
|
/* limit of the number of frames in a traceback, 1 by default.
|
||||||
|
@ -85,14 +85,14 @@ struct _tracemalloc_runtime_state {
|
||||||
size_t peak_traced_memory;
|
size_t peak_traced_memory;
|
||||||
/* Hash table used as a set to intern filenames:
|
/* Hash table used as a set to intern filenames:
|
||||||
PyObject* => PyObject*.
|
PyObject* => PyObject*.
|
||||||
Protected by the GIL */
|
Protected by the TABLES_LOCK(). */
|
||||||
_Py_hashtable_t *filenames;
|
_Py_hashtable_t *filenames;
|
||||||
/* Buffer to store a new traceback in traceback_new().
|
/* Buffer to store a new traceback in traceback_new().
|
||||||
Protected by the GIL. */
|
Protected by the TABLES_LOCK(). */
|
||||||
struct tracemalloc_traceback *traceback;
|
struct tracemalloc_traceback *traceback;
|
||||||
/* Hash table used as a set to intern tracebacks:
|
/* Hash table used as a set to intern tracebacks:
|
||||||
traceback_t* => traceback_t*
|
traceback_t* => traceback_t*
|
||||||
Protected by the GIL */
|
Protected by the TABLES_LOCK(). */
|
||||||
_Py_hashtable_t *tracebacks;
|
_Py_hashtable_t *tracebacks;
|
||||||
/* pointer (void*) => trace (trace_t*).
|
/* pointer (void*) => trace (trace_t*).
|
||||||
Protected by TABLES_LOCK(). */
|
Protected by TABLES_LOCK(). */
|
||||||
|
@ -144,7 +144,7 @@ extern PyObject* _PyTraceMalloc_GetTraces(void);
|
||||||
extern PyObject* _PyTraceMalloc_GetObjectTraceback(PyObject *obj);
|
extern PyObject* _PyTraceMalloc_GetObjectTraceback(PyObject *obj);
|
||||||
|
|
||||||
/* Initialize tracemalloc */
|
/* Initialize tracemalloc */
|
||||||
extern int _PyTraceMalloc_Init(void);
|
extern PyStatus _PyTraceMalloc_Init(void);
|
||||||
|
|
||||||
/* Start tracemalloc */
|
/* Start tracemalloc */
|
||||||
extern int _PyTraceMalloc_Start(int max_nframe);
|
extern int _PyTraceMalloc_Start(int max_nframe);
|
||||||
|
|
|
@ -215,18 +215,14 @@ static struct PyModuleDef module_def = {
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
PyInit__tracemalloc(void)
|
PyInit__tracemalloc(void)
|
||||||
{
|
{
|
||||||
PyObject *m;
|
PyObject *mod = PyModule_Create(&module_def);
|
||||||
m = PyModule_Create(&module_def);
|
if (mod == NULL) {
|
||||||
if (m == NULL)
|
|
||||||
return NULL;
|
|
||||||
#ifdef Py_GIL_DISABLED
|
|
||||||
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (_PyTraceMalloc_Init() < 0) {
|
|
||||||
Py_DECREF(m);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m;
|
#ifdef Py_GIL_DISABLED
|
||||||
|
PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
|
@ -707,7 +707,12 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
|
||||||
// the settings are loaded (so that feature_flags are set) but before
|
// the settings are loaded (so that feature_flags are set) but before
|
||||||
// any calls are made to obmalloc functions.
|
// any calls are made to obmalloc functions.
|
||||||
if (_PyMem_init_obmalloc(interp) < 0) {
|
if (_PyMem_init_obmalloc(interp) < 0) {
|
||||||
return _PyStatus_NO_MEMORY();
|
return _PyStatus_NO_MEMORY();
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _PyTraceMalloc_Init();
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThreadState *tstate = _PyThreadState_New(interp,
|
PyThreadState *tstate = _PyThreadState_New(interp,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue