diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2017-09-06 01:26:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-06 01:26:16 (GMT) |
commit | 76d5abc8684bac4f2fc7cccfe2cd940923357351 (patch) | |
tree | 4ae6a3bd88bef1266a8d9723c589f925d90bf848 /Modules | |
parent | 501b324d3a940d26e0021a38aae8d896a30fbcff (diff) | |
download | cpython-76d5abc8684bac4f2fc7cccfe2cd940923357351.zip cpython-76d5abc8684bac4f2fc7cccfe2cd940923357351.tar.gz cpython-76d5abc8684bac4f2fc7cccfe2cd940923357351.tar.bz2 |
bpo-30860: Consolidate stateful runtime globals. (#2594)
* group the (stateful) runtime globals into various topical structs
* consolidate the topical structs under a single top-level _PyRuntimeState struct
* add a check-c-globals.py script that helps identify runtime globals
Other globals are excluded (see globals.txt and check-c-globals.py).
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_io/bufferedio.c | 2 | ||||
-rw-r--r-- | Modules/_threadmodule.c | 11 | ||||
-rw-r--r-- | Modules/_winapi.c | 2 | ||||
-rw-r--r-- | Modules/gcmodule.c | 309 | ||||
-rw-r--r-- | Modules/main.c | 8 |
5 files changed, 105 insertions, 227 deletions
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 189b1cd..3f57041 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -279,7 +279,7 @@ _enter_buffered_busy(buffered *self) "reentrant call inside %R", self); return 0; } - relax_locking = (_Py_Finalizing != NULL); + relax_locking = _Py_IS_FINALIZING(); Py_BEGIN_ALLOW_THREADS if (!relax_locking) st = PyThread_acquire_lock(self->lock, 1); diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index da750c0..89be96c 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -14,7 +14,6 @@ #include "pythread.h" static PyObject *ThreadError; -static long nb_threads = 0; static PyObject *str_dict; _Py_IDENTIFIER(stderr); @@ -993,7 +992,7 @@ t_bootstrap(void *boot_raw) tstate->thread_id = PyThread_get_thread_ident(); _PyThreadState_Init(tstate); PyEval_AcquireThread(tstate); - nb_threads++; + tstate->interp->num_threads++; res = PyObject_Call(boot->func, boot->args, boot->keyw); if (res == NULL) { if (PyErr_ExceptionMatches(PyExc_SystemExit)) @@ -1020,7 +1019,7 @@ t_bootstrap(void *boot_raw) Py_DECREF(boot->args); Py_XDECREF(boot->keyw); PyMem_DEL(boot_raw); - nb_threads--; + tstate->interp->num_threads--; PyThreadState_Clear(tstate); PyThreadState_DeleteCurrent(); PyThread_exit_thread(); @@ -1159,7 +1158,8 @@ A thread's identity may be reused for another thread after it exits."); static PyObject * thread__count(PyObject *self) { - return PyLong_FromLong(nb_threads); + PyThreadState *tstate = PyThreadState_Get(); + return PyLong_FromLong(tstate->interp->num_threads); } PyDoc_STRVAR(_count_doc, @@ -1352,6 +1352,7 @@ PyInit__thread(void) PyObject *m, *d, *v; double time_max; double timeout_max; + PyThreadState *tstate = PyThreadState_Get(); /* Initialize types: */ if (PyType_Ready(&localdummytype) < 0) @@ -1396,7 +1397,7 @@ PyInit__thread(void) if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) return NULL; - nb_threads = 0; + tstate->interp->num_threads = 0; str_dict = PyUnicode_InternFromString("__dict__"); if (str_dict == NULL) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 682d0a3..6556d99 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -114,7 +114,7 @@ overlapped_dealloc(OverlappedObject *self) { /* The operation is no longer pending -- nothing to do. */ } - else if (_Py_Finalizing == NULL) + else if _Py_IS_FINALIZING() { /* The operation is still pending -- give a warning. This will probably only happen on Windows XP. */ diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 4e5acf3..fa67f7f 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -39,133 +39,9 @@ module gc /* Get the object given the GC head */ #define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1)) -/*** Global GC state ***/ - -struct gc_generation { - PyGC_Head head; - int threshold; /* collection threshold */ - int count; /* count of allocations or collections of younger - generations */ -}; - -/* If we change this, we need to change the default value in the signature of - gc.collect. */ -#define NUM_GENERATIONS 3 -#define GEN_HEAD(n) (&generations[n].head) - -/* linked lists of container objects */ -static struct gc_generation generations[NUM_GENERATIONS] = { - /* PyGC_Head, threshold, count */ - {{{GEN_HEAD(0), GEN_HEAD(0), 0}}, 700, 0}, - {{{GEN_HEAD(1), GEN_HEAD(1), 0}}, 10, 0}, - {{{GEN_HEAD(2), GEN_HEAD(2), 0}}, 10, 0}, -}; - -PyGC_Head *_PyGC_generation0 = GEN_HEAD(0); - -static int enabled = 1; /* automatic collection enabled? */ - -/* true if we are currently running the collector */ -static int collecting = 0; - -/* list of uncollectable objects */ -static PyObject *garbage = NULL; - /* Python string to use if unhandled exception occurs */ static PyObject *gc_str = NULL; -/* a list of callbacks to be invoked when collection is performed */ -static PyObject *callbacks = NULL; - -/* This is the number of objects that survived the last full collection. It - approximates the number of long lived objects tracked by the GC. - - (by "full collection", we mean a collection of the oldest generation). -*/ -static Py_ssize_t long_lived_total = 0; - -/* This is the number of objects that survived all "non-full" collections, - and are awaiting to undergo a full collection for the first time. - -*/ -static Py_ssize_t long_lived_pending = 0; - -/* - NOTE: about the counting of long-lived objects. - - To limit the cost of garbage collection, there are two strategies; - - make each collection faster, e.g. by scanning fewer objects - - do less collections - This heuristic is about the latter strategy. - - In addition to the various configurable thresholds, we only trigger a - full collection if the ratio - long_lived_pending / long_lived_total - is above a given value (hardwired to 25%). - - The reason is that, while "non-full" collections (i.e., collections of - the young and middle generations) will always examine roughly the same - number of objects -- determined by the aforementioned thresholds --, - the cost of a full collection is proportional to the total number of - long-lived objects, which is virtually unbounded. - - Indeed, it has been remarked that doing a full collection every - <constant number> of object creations entails a dramatic performance - degradation in workloads which consist in creating and storing lots of - long-lived objects (e.g. building a large list of GC-tracked objects would - show quadratic performance, instead of linear as expected: see issue #4074). - - Using the above ratio, instead, yields amortized linear performance in - the total number of objects (the effect of which can be summarized - thusly: "each full garbage collection is more and more costly as the - number of objects grows, but we do fewer and fewer of them"). - - This heuristic was suggested by Martin von Löwis on python-dev in - June 2008. His original analysis and proposal can be found at: - http://mail.python.org/pipermail/python-dev/2008-June/080579.html -*/ - -/* - NOTE: about untracking of mutable objects. - - Certain types of container cannot participate in a reference cycle, and - so do not need to be tracked by the garbage collector. Untracking these - objects reduces the cost of garbage collections. However, determining - which objects may be untracked is not free, and the costs must be - weighed against the benefits for garbage collection. - - There are two possible strategies for when to untrack a container: - - i) When the container is created. - ii) When the container is examined by the garbage collector. - - Tuples containing only immutable objects (integers, strings etc, and - recursively, tuples of immutable objects) do not need to be tracked. - The interpreter creates a large number of tuples, many of which will - not survive until garbage collection. It is therefore not worthwhile - to untrack eligible tuples at creation time. - - Instead, all tuples except the empty tuple are tracked when created. - During garbage collection it is determined whether any surviving tuples - can be untracked. A tuple can be untracked if all of its contents are - already not tracked. Tuples are examined for untracking in all garbage - collection cycles. It may take more than one cycle to untrack a tuple. - - Dictionaries containing only immutable objects also do not need to be - tracked. Dictionaries are untracked when created. If a tracked item is - inserted into a dictionary (either as a key or value), the dictionary - becomes tracked. During a full garbage collection (all generations), - the collector will untrack any dictionaries whose contents are not - tracked. - - The module provides the python function is_tracked(obj), which returns - the CURRENT tracking status of the object. Subsequent garbage - collections may change the tracking status of the object. - - Untracking of certain containers was introduced in issue #4688, and - the algorithm was refined in response to issue #14775. -*/ - /* set for debugging information */ #define DEBUG_STATS (1<<0) /* print collection statistics */ #define DEBUG_COLLECTABLE (1<<1) /* print collectable objects */ @@ -174,19 +50,26 @@ static Py_ssize_t long_lived_pending = 0; #define DEBUG_LEAK DEBUG_COLLECTABLE | \ DEBUG_UNCOLLECTABLE | \ DEBUG_SAVEALL -static int debug; - -/* Running stats per generation */ -struct gc_generation_stats { - /* total number of collections */ - Py_ssize_t collections; - /* total number of collected objects */ - Py_ssize_t collected; - /* total number of uncollectable objects (put into gc.garbage) */ - Py_ssize_t uncollectable; -}; -static struct gc_generation_stats generation_stats[NUM_GENERATIONS]; +#define GEN_HEAD(n) (&_PyRuntime.gc.generations[n].head) + +void +_PyGC_Initialize(struct _gc_runtime_state *state) +{ + state->enabled = 1; /* automatic collection enabled? */ + +#define _GEN_HEAD(n) (&state->generations[n].head) + struct gc_generation generations[NUM_GENERATIONS] = { + /* PyGC_Head, threshold, count */ + {{{_GEN_HEAD(0), _GEN_HEAD(0), 0}}, 700, 0}, + {{{_GEN_HEAD(1), _GEN_HEAD(1), 0}}, 10, 0}, + {{{_GEN_HEAD(2), _GEN_HEAD(2), 0}}, 10, 0}, + }; + for (int i = 0; i < NUM_GENERATIONS; i++) { + state->generations[i] = generations[i]; + }; + state->generation0 = GEN_HEAD(0); +} /*-------------------------------------------------------------------------- gc_refs values. @@ -766,16 +649,16 @@ handle_legacy_finalizers(PyGC_Head *finalizers, PyGC_Head *old) { PyGC_Head *gc = finalizers->gc.gc_next; - if (garbage == NULL) { - garbage = PyList_New(0); - if (garbage == NULL) + if (_PyRuntime.gc.garbage == NULL) { + _PyRuntime.gc.garbage = PyList_New(0); + if (_PyRuntime.gc.garbage == NULL) Py_FatalError("gc couldn't create gc.garbage list"); } for (; gc != finalizers; gc = gc->gc.gc_next) { PyObject *op = FROM_GC(gc); - if ((debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) { - if (PyList_Append(garbage, op) < 0) + if ((_PyRuntime.gc.debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) { + if (PyList_Append(_PyRuntime.gc.garbage, op) < 0) return -1; } } @@ -865,8 +748,8 @@ delete_garbage(PyGC_Head *collectable, PyGC_Head *old) PyGC_Head *gc = collectable->gc.gc_next; PyObject *op = FROM_GC(gc); - if (debug & DEBUG_SAVEALL) { - PyList_Append(garbage, op); + if (_PyRuntime.gc.debug & DEBUG_SAVEALL) { + PyList_Append(_PyRuntime.gc.garbage, op); } else { if ((clear = Py_TYPE(op)->tp_clear) != NULL) { @@ -919,9 +802,9 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, PyGC_Head *gc; _PyTime_t t1 = 0; /* initialize to prevent a compiler warning */ - struct gc_generation_stats *stats = &generation_stats[generation]; + struct gc_generation_stats *stats = &_PyRuntime.gc.generation_stats[generation]; - if (debug & DEBUG_STATS) { + if (_PyRuntime.gc.debug & DEBUG_STATS) { PySys_WriteStderr("gc: collecting generation %d...\n", generation); PySys_WriteStderr("gc: objects in each generation:"); @@ -938,9 +821,9 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, /* update collection and allocation counters */ if (generation+1 < NUM_GENERATIONS) - generations[generation+1].count += 1; + _PyRuntime.gc.generations[generation+1].count += 1; for (i = 0; i <= generation; i++) - generations[i].count = 0; + _PyRuntime.gc.generations[i].count = 0; /* merge younger generations with one we are currently collecting */ for (i = 0; i < generation; i++) { @@ -974,7 +857,7 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, /* Move reachable objects to next generation. */ if (young != old) { if (generation == NUM_GENERATIONS - 2) { - long_lived_pending += gc_list_size(young); + _PyRuntime.gc.long_lived_pending += gc_list_size(young); } gc_list_merge(young, old); } @@ -982,8 +865,8 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, /* We only untrack dicts in full collections, to avoid quadratic dict build-up. See issue #14775. */ untrack_dicts(young); - long_lived_pending = 0; - long_lived_total = gc_list_size(young); + _PyRuntime.gc.long_lived_pending = 0; + _PyRuntime.gc.long_lived_total = gc_list_size(young); } /* All objects in unreachable are trash, but objects reachable from @@ -1003,7 +886,7 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, for (gc = unreachable.gc.gc_next; gc != &unreachable; gc = gc->gc.gc_next) { m++; - if (debug & DEBUG_COLLECTABLE) { + if (_PyRuntime.gc.debug & DEBUG_COLLECTABLE) { debug_cycle("collectable", FROM_GC(gc)); } } @@ -1032,10 +915,10 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, gc != &finalizers; gc = gc->gc.gc_next) { n++; - if (debug & DEBUG_UNCOLLECTABLE) + if (_PyRuntime.gc.debug & DEBUG_UNCOLLECTABLE) debug_cycle("uncollectable", FROM_GC(gc)); } - if (debug & DEBUG_STATS) { + if (_PyRuntime.gc.debug & DEBUG_STATS) { _PyTime_t t2 = _PyTime_GetMonotonicClock(); if (m == 0 && n == 0) @@ -1098,11 +981,11 @@ invoke_gc_callback(const char *phase, int generation, PyObject *info = NULL; /* we may get called very early */ - if (callbacks == NULL) + if (_PyRuntime.gc.callbacks == NULL) return; /* The local variable cannot be rebound, check it for sanity */ - assert(callbacks != NULL && PyList_CheckExact(callbacks)); - if (PyList_GET_SIZE(callbacks) != 0) { + assert(_PyRuntime.gc.callbacks != NULL && PyList_CheckExact(_PyRuntime.gc.callbacks)); + if (PyList_GET_SIZE(_PyRuntime.gc.callbacks) != 0) { info = Py_BuildValue("{sisnsn}", "generation", generation, "collected", collected, @@ -1112,8 +995,8 @@ invoke_gc_callback(const char *phase, int generation, return; } } - for (i=0; i<PyList_GET_SIZE(callbacks); i++) { - PyObject *r, *cb = PyList_GET_ITEM(callbacks, i); + for (i=0; i<PyList_GET_SIZE(_PyRuntime.gc.callbacks); i++) { + PyObject *r, *cb = PyList_GET_ITEM(_PyRuntime.gc.callbacks, i); Py_INCREF(cb); /* make sure cb doesn't go away */ r = PyObject_CallFunction(cb, "sO", phase, info); Py_XDECREF(r); @@ -1147,13 +1030,13 @@ collect_generations(void) * exceeds the threshold. Objects in the that generation and * generations younger than it will be collected. */ for (i = NUM_GENERATIONS-1; i >= 0; i--) { - if (generations[i].count > generations[i].threshold) { + if (_PyRuntime.gc.generations[i].count > _PyRuntime.gc.generations[i].threshold) { /* Avoid quadratic performance degradation in number of tracked objects. See comments at the beginning of this file, and issue #4074. */ if (i == NUM_GENERATIONS - 1 - && long_lived_pending < long_lived_total / 4) + && _PyRuntime.gc.long_lived_pending < _PyRuntime.gc.long_lived_total / 4) continue; n = collect_with_callback(i); break; @@ -1174,7 +1057,7 @@ static PyObject * gc_enable_impl(PyObject *module) /*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/ { - enabled = 1; + _PyRuntime.gc.enabled = 1; Py_RETURN_NONE; } @@ -1188,7 +1071,7 @@ static PyObject * gc_disable_impl(PyObject *module) /*[clinic end generated code: output=97d1030f7aa9d279 input=8c2e5a14e800d83b]*/ { - enabled = 0; + _PyRuntime.gc.enabled = 0; Py_RETURN_NONE; } @@ -1202,7 +1085,7 @@ static int gc_isenabled_impl(PyObject *module) /*[clinic end generated code: output=1874298331c49130 input=30005e0422373b31]*/ { - return enabled; + return _PyRuntime.gc.enabled; } /*[clinic input] @@ -1230,12 +1113,12 @@ gc_collect_impl(PyObject *module, int generation) return -1; } - if (collecting) + if (_PyRuntime.gc.collecting) n = 0; /* already collecting, don't do anything */ else { - collecting = 1; + _PyRuntime.gc.collecting = 1; n = collect_with_callback(generation); - collecting = 0; + _PyRuntime.gc.collecting = 0; } return n; @@ -1263,7 +1146,7 @@ static PyObject * gc_set_debug_impl(PyObject *module, int flags) /*[clinic end generated code: output=7c8366575486b228 input=5e5ce15e84fbed15]*/ { - debug = flags; + _PyRuntime.gc.debug = flags; Py_RETURN_NONE; } @@ -1278,7 +1161,7 @@ static int gc_get_debug_impl(PyObject *module) /*[clinic end generated code: output=91242f3506cd1e50 input=91a101e1c3b98366]*/ { - return debug; + return _PyRuntime.gc.debug; } PyDoc_STRVAR(gc_set_thresh__doc__, @@ -1292,13 +1175,13 @@ gc_set_thresh(PyObject *self, PyObject *args) { int i; if (!PyArg_ParseTuple(args, "i|ii:set_threshold", - &generations[0].threshold, - &generations[1].threshold, - &generations[2].threshold)) + &_PyRuntime.gc.generations[0].threshold, + &_PyRuntime.gc.generations[1].threshold, + &_PyRuntime.gc.generations[2].threshold)) return NULL; for (i = 2; i < NUM_GENERATIONS; i++) { /* generations higher than 2 get the same threshold */ - generations[i].threshold = generations[2].threshold; + _PyRuntime.gc.generations[i].threshold = _PyRuntime.gc.generations[2].threshold; } Py_RETURN_NONE; @@ -1315,9 +1198,9 @@ gc_get_threshold_impl(PyObject *module) /*[clinic end generated code: output=7902bc9f41ecbbd8 input=286d79918034d6e6]*/ { return Py_BuildValue("(iii)", - generations[0].threshold, - generations[1].threshold, - generations[2].threshold); + _PyRuntime.gc.generations[0].threshold, + _PyRuntime.gc.generations[1].threshold, + _PyRuntime.gc.generations[2].threshold); } /*[clinic input] @@ -1331,9 +1214,9 @@ gc_get_count_impl(PyObject *module) /*[clinic end generated code: output=354012e67b16398f input=a392794a08251751]*/ { return Py_BuildValue("(iii)", - generations[0].count, - generations[1].count, - generations[2].count); + _PyRuntime.gc.generations[0].count, + _PyRuntime.gc.generations[1].count, + _PyRuntime.gc.generations[2].count); } static int @@ -1464,7 +1347,7 @@ gc_get_stats_impl(PyObject *module) /* To get consistent values despite allocations while constructing the result list, we use a snapshot of the running stats. */ for (i = 0; i < NUM_GENERATIONS; i++) { - stats[i] = generation_stats[i]; + stats[i] = _PyRuntime.gc.generation_stats[i]; } result = PyList_New(0); @@ -1581,22 +1464,22 @@ PyInit_gc(void) if (m == NULL) return NULL; - if (garbage == NULL) { - garbage = PyList_New(0); - if (garbage == NULL) + if (_PyRuntime.gc.garbage == NULL) { + _PyRuntime.gc.garbage = PyList_New(0); + if (_PyRuntime.gc.garbage == NULL) return NULL; } - Py_INCREF(garbage); - if (PyModule_AddObject(m, "garbage", garbage) < 0) + Py_INCREF(_PyRuntime.gc.garbage); + if (PyModule_AddObject(m, "garbage", _PyRuntime.gc.garbage) < 0) return NULL; - if (callbacks == NULL) { - callbacks = PyList_New(0); - if (callbacks == NULL) + if (_PyRuntime.gc.callbacks == NULL) { + _PyRuntime.gc.callbacks = PyList_New(0); + if (_PyRuntime.gc.callbacks == NULL) return NULL; } - Py_INCREF(callbacks); - if (PyModule_AddObject(m, "callbacks", callbacks) < 0) + Py_INCREF(_PyRuntime.gc.callbacks); + if (PyModule_AddObject(m, "callbacks", _PyRuntime.gc.callbacks) < 0) return NULL; #define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return NULL @@ -1615,12 +1498,12 @@ PyGC_Collect(void) { Py_ssize_t n; - if (collecting) + if (_PyRuntime.gc.collecting) n = 0; /* already collecting, don't do anything */ else { - collecting = 1; + _PyRuntime.gc.collecting = 1; n = collect_with_callback(NUM_GENERATIONS - 1); - collecting = 0; + _PyRuntime.gc.collecting = 0; } return n; @@ -1629,7 +1512,7 @@ PyGC_Collect(void) Py_ssize_t _PyGC_CollectIfEnabled(void) { - if (!enabled) + if (!_PyRuntime.gc.enabled) return 0; return PyGC_Collect(); @@ -1646,12 +1529,12 @@ _PyGC_CollectNoFail(void) during interpreter shutdown (and then never finish it). See http://bugs.python.org/issue8713#msg195178 for an example. */ - if (collecting) + if (_PyRuntime.gc.collecting) n = 0; else { - collecting = 1; + _PyRuntime.gc.collecting = 1; n = collect(NUM_GENERATIONS - 1, NULL, NULL, 1); - collecting = 0; + _PyRuntime.gc.collecting = 0; } return n; } @@ -1659,10 +1542,10 @@ _PyGC_CollectNoFail(void) void _PyGC_DumpShutdownStats(void) { - if (!(debug & DEBUG_SAVEALL) - && garbage != NULL && PyList_GET_SIZE(garbage) > 0) { + if (!(_PyRuntime.gc.debug & DEBUG_SAVEALL) + && _PyRuntime.gc.garbage != NULL && PyList_GET_SIZE(_PyRuntime.gc.garbage) > 0) { char *message; - if (debug & DEBUG_UNCOLLECTABLE) + if (_PyRuntime.gc.debug & DEBUG_UNCOLLECTABLE) message = "gc: %zd uncollectable objects at " \ "shutdown"; else @@ -1673,13 +1556,13 @@ _PyGC_DumpShutdownStats(void) already. */ if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, "gc", NULL, message, - PyList_GET_SIZE(garbage))) + PyList_GET_SIZE(_PyRuntime.gc.garbage))) PyErr_WriteUnraisable(NULL); - if (debug & DEBUG_UNCOLLECTABLE) { + if (_PyRuntime.gc.debug & DEBUG_UNCOLLECTABLE) { PyObject *repr = NULL, *bytes = NULL; - repr = PyObject_Repr(garbage); + repr = PyObject_Repr(_PyRuntime.gc.garbage); if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr))) - PyErr_WriteUnraisable(garbage); + PyErr_WriteUnraisable(_PyRuntime.gc.garbage); else { PySys_WriteStderr( " %s\n", @@ -1695,7 +1578,7 @@ _PyGC_DumpShutdownStats(void) void _PyGC_Fini(void) { - Py_CLEAR(callbacks); + Py_CLEAR(_PyRuntime.gc.callbacks); } /* for debugging */ @@ -1746,15 +1629,15 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize) return PyErr_NoMemory(); g->gc.gc_refs = 0; _PyGCHead_SET_REFS(g, GC_UNTRACKED); - generations[0].count++; /* number of allocated GC objects */ - if (generations[0].count > generations[0].threshold && - enabled && - generations[0].threshold && - !collecting && + _PyRuntime.gc.generations[0].count++; /* number of allocated GC objects */ + if (_PyRuntime.gc.generations[0].count > _PyRuntime.gc.generations[0].threshold && + _PyRuntime.gc.enabled && + _PyRuntime.gc.generations[0].threshold && + !_PyRuntime.gc.collecting && !PyErr_Occurred()) { - collecting = 1; + _PyRuntime.gc.collecting = 1; collect_generations(); - collecting = 0; + _PyRuntime.gc.collecting = 0; } op = FROM_GC(g); return op; @@ -1819,8 +1702,8 @@ PyObject_GC_Del(void *op) PyGC_Head *g = AS_GC(op); if (IS_TRACKED(op)) gc_list_remove(g); - if (generations[0].count > 0) { - generations[0].count--; + if (_PyRuntime.gc.generations[0].count > 0) { + _PyRuntime.gc.generations[0].count--; } PyObject_FREE(g); } diff --git a/Modules/main.c b/Modules/main.c index 08b2276..3e347dc 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -598,16 +598,10 @@ Py_Main(int argc, wchar_t **argv) } } - char *pymalloc = Py_GETENV("PYTHONMALLOC"); - if (_PyMem_SetupAllocators(pymalloc) < 0) { - fprintf(stderr, - "Error in PYTHONMALLOC: unknown allocator \"%s\"!\n", pymalloc); - exit(1); - } - /* Initialize the core language runtime */ Py_IgnoreEnvironmentFlag = core_config.ignore_environment; core_config._disable_importlib = 0; + core_config.allocator = Py_GETENV("PYTHONMALLOC"); _Py_InitializeCore(&core_config); /* Reprocess the command line with the language runtime available */ |