| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent d2c7b25 commit 58af229
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -271,8 +271,8 @@ extern void _PyDebug_PrintTotalRefs(void); | |||
| 271 | 271 | ||
| 272 | 272 | #ifdef Py_TRACE_REFS | |
| 273 | 273 | extern void _Py_AddToAllObjects(PyObject *op, int force); | |
| 274 | - extern void _Py_PrintReferences(FILE *); | ||
| 275 | - extern void _Py_PrintReferenceAddresses(FILE *); | ||
| 274 | + extern void _Py_PrintReferences(PyInterpreterState *, FILE *); | ||
| 275 | + extern void _Py_PrintReferenceAddresses(PyInterpreterState *, FILE *); | ||
| 276 | 276 | #endif | |
| 277 | 277 | ||
| 278 | 278 | ||
| 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 | |
|---|---|---|---|
@@ -101,6 +101,7 @@ extern PyTypeObject _PyExc_MemoryError; | |||
| 101 | 101 | { .threshold = 10, }, \ | |
| 102 | 102 | }, \ | |
| 103 | 103 | }, \ | |
| 104 | + .object_state = _py_object_state_INIT(INTERP), \ | ||
| 104 | 105 | .dtoa = _dtoa_state_INIT(&(INTERP)), \ | |
| 105 | 106 | .dict_state = _dict_state_INIT, \ | |
| 106 | 107 | .func_state = { \ | |
@@ -130,6 +131,16 @@ extern PyTypeObject _PyExc_MemoryError; | |||
| 130 | 131 | .context_ver = 1, \ | |
| 131 | 132 | } | |
| 132 | 133 | ||
| 134 | + #ifdef Py_TRACE_REFS | ||
| 135 | + # define _py_object_state_INIT(INTERP) \ | ||
| 136 | + { \ | ||
| 137 | + .refchain = {&INTERP.object_state.refchain, &INTERP.object_state.refchain}, \ | ||
| 138 | + } | ||
| 139 | + #else | ||
| 140 | + # define _py_object_state_INIT(INTERP) \ | ||
| 141 | + { 0 } | ||
| 142 | + #endif | ||
| 143 | + | ||
| 133 | 144 | ||
| 134 | 145 | // global objects | |
| 135 | 146 | ||
| 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 | |
|---|---|---|---|
@@ -158,11 +158,8 @@ _PyDebug_PrintTotalRefs(void) { | |||
| 158 | 158 | Do not call them otherwise, they do not initialize the object! */ | |
| 159 | 159 | ||
| 160 | 160 | #ifdef Py_TRACE_REFS | |
| 161 | - /* Head of circular doubly-linked list of all objects. These are linked | ||
| 162 | - * together via the _ob_prev and _ob_next members of a PyObject, which | ||
| 163 | - * exist only in a Py_TRACE_REFS build. | ||
| 164 | - */ | ||
| 165 | - static PyObject refchain = {&refchain, &refchain}; | ||
| 161 | + | ||
| 162 | + #define REFCHAIN(interp) &interp->object_state.refchain | ||
| 166 | 163 | ||
| 167 | 164 | /* Insert op at the front of the list of all objects. If force is true, | |
| 168 | 165 | * op is added even if _ob_prev and _ob_next are non-NULL already. If | |
@@ -187,10 +184,11 @@ _Py_AddToAllObjects(PyObject *op, int force) | |||
| 187 | 184 | } | |
| 188 | 185 | #endif | |
| 189 | 186 | if (force || op->_ob_prev == NULL) { | |
| 190 | - op->_ob_next = refchain._ob_next; | ||
| 191 | - op->_ob_prev = &refchain; | ||
| 192 | - refchain._ob_next->_ob_prev = op; | ||
| 193 | - refchain._ob_next = op; | ||
| 187 | + PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); | ||
| 188 | + op->_ob_next = refchain->_ob_next; | ||
| 189 | + op->_ob_prev = refchain; | ||
| 190 | + refchain->_ob_next->_ob_prev = op; | ||
| 191 | + refchain->_ob_next = op; | ||
| 194 | 192 | } | |
| 195 | 193 | } | |
| 196 | 194 | #endif /* Py_TRACE_REFS */ | |
@@ -2206,20 +2204,21 @@ _Py_ForgetReference(PyObject *op) | |||
| 2206 | 2204 | _PyObject_ASSERT_FAILED_MSG(op, "negative refcnt"); | |
| 2207 | 2205 | } | |
| 2208 | 2206 | ||
| 2209 | - if (op == &refchain || | ||
| 2207 | + PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); | ||
| 2208 | + if (op == refchain || | ||
| 2210 | 2209 | op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) | |
| 2211 | 2210 | { | |
| 2212 | 2211 | _PyObject_ASSERT_FAILED_MSG(op, "invalid object chain"); | |
| 2213 | 2212 | } | |
| 2214 | 2213 | ||
| 2215 | 2214 | #ifdef SLOW_UNREF_CHECK | |
| 2216 | 2215 | PyObject *p; | |
| 2217 | - for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { | ||
| 2216 | + for (p = refchain->_ob_next; p != refchain; p = p->_ob_next) { | ||
| 2218 | 2217 | if (p == op) { | |
| 2219 | 2218 | break; | |
| 2220 | 2219 | } | |
| 2221 | 2220 | } | |
| 2222 | - if (p == &refchain) { | ||
| 2221 | + if (p == refchain) { | ||
| 2223 | 2222 | /* Not found */ | |
| 2224 | 2223 | _PyObject_ASSERT_FAILED_MSG(op, | |
| 2225 | 2224 | "object not found in the objects list"); | |
@@ -2235,11 +2234,15 @@ _Py_ForgetReference(PyObject *op) | |||
| 2235 | 2234 | * interpreter must be in a healthy state. | |
| 2236 | 2235 | */ | |
| 2237 | 2236 | void | |
| 2238 | - _Py_PrintReferences(FILE *fp) | ||
| 2237 | + _Py_PrintReferences(PyInterpreterState *interp, FILE *fp) | ||
| 2239 | 2238 | { | |
| 2240 | 2239 | PyObject *op; | |
| 2240 | + if (interp == NULL) { | ||
| 2241 | + interp = _PyInterpreterState_Main(); | ||
| 2242 | + } | ||
| 2241 | 2243 | fprintf(fp, "Remaining objects:\n"); | |
| 2242 | - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { | ||
| 2244 | + PyObject *refchain = REFCHAIN(interp); | ||
| 2245 | + for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) { | ||
| 2243 | 2246 | fprintf(fp, "%p [%zd] ", (void *)op, Py_REFCNT(op)); | |
| 2244 | 2247 | if (PyObject_Print(op, fp, 0) != 0) { | |
| 2245 | 2248 | PyErr_Clear(); | |
@@ -2251,34 +2254,42 @@ _Py_PrintReferences(FILE *fp) | |||
| 2251 | 2254 | /* Print the addresses of all live objects. Unlike _Py_PrintReferences, this | |
| 2252 | 2255 | * doesn't make any calls to the Python C API, so is always safe to call. | |
| 2253 | 2256 | */ | |
| 2257 | + // XXX This function is not safe to use if the interpreter has been | ||
| 2258 | + // freed or is in an unhealthy state (e.g. late in finalization). | ||
| 2259 | + // The call in Py_FinalizeEx() is okay since the main interpreter | ||
| 2260 | + // is statically allocated. | ||
| 2254 | 2261 | void | |
| 2255 | - _Py_PrintReferenceAddresses(FILE *fp) | ||
| 2262 | + _Py_PrintReferenceAddresses(PyInterpreterState *interp, FILE *fp) | ||
| 2256 | 2263 | { | |
| 2257 | 2264 | PyObject *op; | |
| 2265 | + PyObject *refchain = REFCHAIN(interp); | ||
| 2258 | 2266 | fprintf(fp, "Remaining object addresses:\n"); | |
| 2259 | - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) | ||
| 2267 | + for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) | ||
| 2260 | 2268 | fprintf(fp, "%p [%zd] %s\n", (void *)op, | |
| 2261 | 2269 | Py_REFCNT(op), Py_TYPE(op)->tp_name); | |
| 2262 | 2270 | } | |
| 2263 | 2271 | ||
| 2272 | + /* The implementation of sys.getobjects(). */ | ||
| 2264 | 2273 | PyObject * | |
| 2265 | 2274 | _Py_GetObjects(PyObject *self, PyObject *args) | |
| 2266 | 2275 | { | |
| 2267 | 2276 | int i, n; | |
| 2268 | 2277 | PyObject *t = NULL; | |
| 2269 | 2278 | PyObject *res, *op; | |
| 2279 | + PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| 2270 | 2280 | ||
| 2271 | 2281 | if (!PyArg_ParseTuple(args, "i|O", &n, &t)) | |
| 2272 | 2282 | return NULL; | |
| 2273 | - op = refchain._ob_next; | ||
| 2283 | + PyObject *refchain = REFCHAIN(interp); | ||
| 2284 | + op = refchain->_ob_next; | ||
| 2274 | 2285 | res = PyList_New(0); | |
| 2275 | 2286 | if (res == NULL) | |
| 2276 | 2287 | return NULL; | |
| 2277 | - for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { | ||
| 2288 | + for (i = 0; (n == 0 || i < n) && op != refchain; i++) { | ||
| 2278 | 2289 | while (op == self || op == args || op == res || op == t || | |
| 2279 | 2290 | (t != NULL && !Py_IS_TYPE(op, (PyTypeObject *) t))) { | |
| 2280 | 2291 | op = op->_ob_next; | |
| 2281 | - if (op == &refchain) | ||
| 2292 | + if (op == refchain) | ||
| 2282 | 2293 | return res; | |
| 2283 | 2294 | } | |
| 2284 | 2295 | if (PyList_Append(res, op) < 0) { | |
@@ -2290,6 +2301,8 @@ _Py_GetObjects(PyObject *self, PyObject *args) | |||
| 2290 | 2301 | return res; | |
| 2291 | 2302 | } | |
| 2292 | 2303 | ||
| 2304 | + #undef REFCHAIN | ||
| 2305 | + | ||
| 2293 | 2306 | #endif | |
| 2294 | 2307 | ||
| 2295 | 2308 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1920,11 +1920,11 @@ Py_FinalizeEx(void) | |||
| 1920 | 1920 | } | |
| 1921 | 1921 | ||
| 1922 | 1922 | if (dump_refs) { | |
| 1923 | - _Py_PrintReferences(stderr); | ||
| 1923 | + _Py_PrintReferences(tstate->interp, stderr); | ||
| 1924 | 1924 | } | |
| 1925 | 1925 | ||
| 1926 | 1926 | if (dump_refs_fp != NULL) { | |
| 1927 | - _Py_PrintReferences(dump_refs_fp); | ||
| 1927 | + _Py_PrintReferences(tstate->interp, dump_refs_fp); | ||
| 1928 | 1928 | } | |
| 1929 | 1929 | #endif /* Py_TRACE_REFS */ | |
| 1930 | 1930 | ||
@@ -1960,11 +1960,11 @@ Py_FinalizeEx(void) | |||
| 1960 | 1960 | */ | |
| 1961 | 1961 | ||
| 1962 | 1962 | if (dump_refs) { | |
| 1963 | - _Py_PrintReferenceAddresses(stderr); | ||
| 1963 | + _Py_PrintReferenceAddresses(tstate->interp, stderr); | ||
| 1964 | 1964 | } | |
| 1965 | 1965 | ||
| 1966 | 1966 | if (dump_refs_fp != NULL) { | |
| 1967 | - _Py_PrintReferenceAddresses(dump_refs_fp); | ||
| 1967 | + _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp); | ||
| 1968 | 1968 | fclose(dump_refs_fp); | |
| 1969 | 1969 | } | |
| 1970 | 1970 | #endif /* Py_TRACE_REFS */ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments