| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 14fbd4e commit 58ef741
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -292,8 +292,8 @@ extern void _PyDebug_PrintTotalRefs(void); | |||
| 292 | 292 | ||
| 293 | 293 | #ifdef Py_TRACE_REFS | |
| 294 | 294 | extern void _Py_AddToAllObjects(PyObject *op, int force); | |
| 295 | - extern void _Py_PrintReferences(FILE *); | ||
| 296 | - extern void _Py_PrintReferenceAddresses(FILE *); | ||
| 295 | + extern void _Py_PrintReferences(PyInterpreterState *, FILE *); | ||
| 296 | + extern void _Py_PrintReferenceAddresses(PyInterpreterState *, FILE *); | ||
| 297 | 297 | #endif | |
| 298 | 298 | ||
| 299 | 299 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,17 +11,22 @@ extern "C" { | |||
| 11 | 11 | struct _py_object_runtime_state { | |
| 12 | 12 | #ifdef Py_REF_DEBUG | |
| 13 | 13 | Py_ssize_t interpreter_leaks; | |
| 14 | - #else | ||
| 15 | - int _not_used; | ||
| 16 | 14 | #endif | |
| 15 | + int _not_used; | ||
| 17 | 16 | }; | |
| 18 | 17 | ||
| 19 | 18 | struct _py_object_state { | |
| 20 | 19 | #ifdef Py_REF_DEBUG | |
| 21 | 20 | Py_ssize_t reftotal; | |
| 22 | - #else | ||
| 23 | - int _not_used; | ||
| 24 | 21 | #endif | |
| 22 | + #ifdef Py_TRACE_REFS | ||
| 23 | + /* Head of circular doubly-linked list of all objects. These are linked | ||
| 24 | + * together via the _ob_prev and _ob_next members of a PyObject, which | ||
| 25 | + * exist only in a Py_TRACE_REFS build. | ||
| 26 | + */ | ||
| 27 | + PyObject refchain; | ||
| 28 | + #endif | ||
| 29 | + int _not_used; | ||
| 25 | 30 | }; | |
| 26 | 31 | ||
| 27 | 32 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -157,6 +157,7 @@ extern PyTypeObject _PyExc_MemoryError; | |||
| 157 | 157 | { .threshold = 10, }, \ | |
| 158 | 158 | }, \ | |
| 159 | 159 | }, \ | |
| 160 | + .object_state = _py_object_state_INIT(INTERP), \ | ||
| 160 | 161 | .dtoa = _dtoa_state_INIT(&(INTERP)), \ | |
| 161 | 162 | .dict_state = _dict_state_INIT, \ | |
| 162 | 163 | .func_state = { \ | |
@@ -186,6 +187,16 @@ extern PyTypeObject _PyExc_MemoryError; | |||
| 186 | 187 | .context_ver = 1, \ | |
| 187 | 188 | } | |
| 188 | 189 | ||
| 190 | + #ifdef Py_TRACE_REFS | ||
| 191 | + # define _py_object_state_INIT(INTERP) \ | ||
| 192 | + { \ | ||
| 193 | + .refchain = {&INTERP.object_state.refchain, &INTERP.object_state.refchain}, \ | ||
| 194 | + } | ||
| 195 | + #else | ||
| 196 | + # define _py_object_state_INIT(INTERP) \ | ||
| 197 | + { 0 } | ||
| 198 | + #endif | ||
| 199 | + | ||
| 189 | 200 | ||
| 190 | 201 | // global objects | |
| 191 | 202 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,4 @@ | |||
| 1 | + Trace refs builds (``--with-trace-refs``) were crashing when used with | ||
| 2 | + isolated subinterpreters. The problematic global state has been isolated to | ||
| 3 | + each interpreter. Other fixing the crashes, this change does not affect | ||
| 4 | + users. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -159,11 +159,8 @@ _PyDebug_PrintTotalRefs(void) { | |||
| 159 | 159 | Do not call them otherwise, they do not initialize the object! */ | |
| 160 | 160 | ||
| 161 | 161 | #ifdef Py_TRACE_REFS | |
| 162 | - /* Head of circular doubly-linked list of all objects. These are linked | ||
| 163 | - * together via the _ob_prev and _ob_next members of a PyObject, which | ||
| 164 | - * exist only in a Py_TRACE_REFS build. | ||
| 165 | - */ | ||
| 166 | - static PyObject refchain = {&refchain, &refchain}; | ||
| 162 | + | ||
| 163 | + #define REFCHAIN(interp) &interp->object_state.refchain | ||
| 167 | 164 | ||
| 168 | 165 | /* Insert op at the front of the list of all objects. If force is true, | |
| 169 | 166 | * op is added even if _ob_prev and _ob_next are non-NULL already. If | |
@@ -188,10 +185,11 @@ _Py_AddToAllObjects(PyObject *op, int force) | |||
| 188 | 185 | } | |
| 189 | 186 | #endif | |
| 190 | 187 | if (force || op->_ob_prev == NULL) { | |
| 191 | - op->_ob_next = refchain._ob_next; | ||
| 192 | - op->_ob_prev = &refchain; | ||
| 193 | - refchain._ob_next->_ob_prev = op; | ||
| 194 | - refchain._ob_next = op; | ||
| 188 | + PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); | ||
| 189 | + op->_ob_next = refchain->_ob_next; | ||
| 190 | + op->_ob_prev = refchain; | ||
| 191 | + refchain->_ob_next->_ob_prev = op; | ||
| 192 | + refchain->_ob_next = op; | ||
| 195 | 193 | } | |
| 196 | 194 | } | |
| 197 | 195 | #endif /* Py_TRACE_REFS */ | |
@@ -2229,20 +2227,21 @@ _Py_ForgetReference(PyObject *op) | |||
| 2229 | 2227 | _PyObject_ASSERT_FAILED_MSG(op, "negative refcnt"); | |
| 2230 | 2228 | } | |
| 2231 | 2229 | ||
| 2232 | - if (op == &refchain || | ||
| 2230 | + PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); | ||
| 2231 | + if (op == refchain || | ||
| 2233 | 2232 | op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) | |
| 2234 | 2233 | { | |
| 2235 | 2234 | _PyObject_ASSERT_FAILED_MSG(op, "invalid object chain"); | |
| 2236 | 2235 | } | |
| 2237 | 2236 | ||
| 2238 | 2237 | #ifdef SLOW_UNREF_CHECK | |
| 2239 | 2238 | PyObject *p; | |
| 2240 | - for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { | ||
| 2239 | + for (p = refchain->_ob_next; p != refchain; p = p->_ob_next) { | ||
| 2241 | 2240 | if (p == op) { | |
| 2242 | 2241 | break; | |
| 2243 | 2242 | } | |
| 2244 | 2243 | } | |
| 2245 | - if (p == &refchain) { | ||
| 2244 | + if (p == refchain) { | ||
| 2246 | 2245 | /* Not found */ | |
| 2247 | 2246 | _PyObject_ASSERT_FAILED_MSG(op, | |
| 2248 | 2247 | "object not found in the objects list"); | |
@@ -2258,11 +2257,15 @@ _Py_ForgetReference(PyObject *op) | |||
| 2258 | 2257 | * interpreter must be in a healthy state. | |
| 2259 | 2258 | */ | |
| 2260 | 2259 | void | |
| 2261 | - _Py_PrintReferences(FILE *fp) | ||
| 2260 | + _Py_PrintReferences(PyInterpreterState *interp, FILE *fp) | ||
| 2262 | 2261 | { | |
| 2263 | 2262 | PyObject *op; | |
| 2263 | + if (interp == NULL) { | ||
| 2264 | + interp = _PyInterpreterState_Main(); | ||
| 2265 | + } | ||
| 2264 | 2266 | fprintf(fp, "Remaining objects:\n"); | |
| 2265 | - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { | ||
| 2267 | + PyObject *refchain = REFCHAIN(interp); | ||
| 2268 | + for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) { | ||
| 2266 | 2269 | fprintf(fp, "%p [%zd] ", (void *)op, Py_REFCNT(op)); | |
| 2267 | 2270 | if (PyObject_Print(op, fp, 0) != 0) { | |
| 2268 | 2271 | PyErr_Clear(); | |
@@ -2274,34 +2277,42 @@ _Py_PrintReferences(FILE *fp) | |||
| 2274 | 2277 | /* Print the addresses of all live objects. Unlike _Py_PrintReferences, this | |
| 2275 | 2278 | * doesn't make any calls to the Python C API, so is always safe to call. | |
| 2276 | 2279 | */ | |
| 2280 | + // XXX This function is not safe to use if the interpreter has been | ||
| 2281 | + // freed or is in an unhealthy state (e.g. late in finalization). | ||
| 2282 | + // The call in Py_FinalizeEx() is okay since the main interpreter | ||
| 2283 | + // is statically allocated. | ||
| 2277 | 2284 | void | |
| 2278 | - _Py_PrintReferenceAddresses(FILE *fp) | ||
| 2285 | + _Py_PrintReferenceAddresses(PyInterpreterState *interp, FILE *fp) | ||
| 2279 | 2286 | { | |
| 2280 | 2287 | PyObject *op; | |
| 2288 | + PyObject *refchain = REFCHAIN(interp); | ||
| 2281 | 2289 | fprintf(fp, "Remaining object addresses:\n"); | |
| 2282 | - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) | ||
| 2290 | + for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) | ||
| 2283 | 2291 | fprintf(fp, "%p [%zd] %s\n", (void *)op, | |
| 2284 | 2292 | Py_REFCNT(op), Py_TYPE(op)->tp_name); | |
| 2285 | 2293 | } | |
| 2286 | 2294 | ||
| 2295 | + /* The implementation of sys.getobjects(). */ | ||
| 2287 | 2296 | PyObject * | |
| 2288 | 2297 | _Py_GetObjects(PyObject *self, PyObject *args) | |
| 2289 | 2298 | { | |
| 2290 | 2299 | int i, n; | |
| 2291 | 2300 | PyObject *t = NULL; | |
| 2292 | 2301 | PyObject *res, *op; | |
| 2302 | + PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| 2293 | 2303 | ||
| 2294 | 2304 | if (!PyArg_ParseTuple(args, "i|O", &n, &t)) | |
| 2295 | 2305 | return NULL; | |
| 2296 | - op = refchain._ob_next; | ||
| 2306 | + PyObject *refchain = REFCHAIN(interp); | ||
| 2307 | + op = refchain->_ob_next; | ||
| 2297 | 2308 | res = PyList_New(0); | |
| 2298 | 2309 | if (res == NULL) | |
| 2299 | 2310 | return NULL; | |
| 2300 | - for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { | ||
| 2311 | + for (i = 0; (n == 0 || i < n) && op != refchain; i++) { | ||
| 2301 | 2312 | while (op == self || op == args || op == res || op == t || | |
| 2302 | 2313 | (t != NULL && !Py_IS_TYPE(op, (PyTypeObject *) t))) { | |
| 2303 | 2314 | op = op->_ob_next; | |
| 2304 | - if (op == &refchain) | ||
| 2315 | + if (op == refchain) | ||
| 2305 | 2316 | return res; | |
| 2306 | 2317 | } | |
| 2307 | 2318 | if (PyList_Append(res, op) < 0) { | |
@@ -2313,6 +2324,8 @@ _Py_GetObjects(PyObject *self, PyObject *args) | |||
| 2313 | 2324 | return res; | |
| 2314 | 2325 | } | |
| 2315 | 2326 | ||
| 2327 | + #undef REFCHAIN | ||
| 2328 | + | ||
| 2316 | 2329 | #endif | |
| 2317 | 2330 | ||
| 2318 | 2331 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1921,11 +1921,11 @@ Py_FinalizeEx(void) | |||
| 1921 | 1921 | } | |
| 1922 | 1922 | ||
| 1923 | 1923 | if (dump_refs) { | |
| 1924 | - _Py_PrintReferences(stderr); | ||
| 1924 | + _Py_PrintReferences(tstate->interp, stderr); | ||
| 1925 | 1925 | } | |
| 1926 | 1926 | ||
| 1927 | 1927 | if (dump_refs_fp != NULL) { | |
| 1928 | - _Py_PrintReferences(dump_refs_fp); | ||
| 1928 | + _Py_PrintReferences(tstate->interp, dump_refs_fp); | ||
| 1929 | 1929 | } | |
| 1930 | 1930 | #endif /* Py_TRACE_REFS */ | |
| 1931 | 1931 | ||
@@ -1961,11 +1961,11 @@ Py_FinalizeEx(void) | |||
| 1961 | 1961 | */ | |
| 1962 | 1962 | ||
| 1963 | 1963 | if (dump_refs) { | |
| 1964 | - _Py_PrintReferenceAddresses(stderr); | ||
| 1964 | + _Py_PrintReferenceAddresses(tstate->interp, stderr); | ||
| 1965 | 1965 | } | |
| 1966 | 1966 | ||
| 1967 | 1967 | if (dump_refs_fp != NULL) { | |
| 1968 | - _Py_PrintReferenceAddresses(dump_refs_fp); | ||
| 1968 | + _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp); | ||
| 1969 | 1969 | fclose(dump_refs_fp); | |
| 1970 | 1970 | } | |
| 1971 | 1971 | #endif /* Py_TRACE_REFS */ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments