diff options
author | Victor Stinner <vstinner@python.org> | 2020-06-23 20:55:46 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-23 20:55:46 (GMT) |
commit | 281cce1106568ef9fec17e3c72d289416fac02a5 (patch) | |
tree | 529d24e0db048c8914cc8a12ebf7b8328a62665d /Objects/exceptions.c | |
parent | 2c6e4e91c5a4d3f25908108f4ed32aba936df70c (diff) | |
download | cpython-281cce1106568ef9fec17e3c72d289416fac02a5.zip cpython-281cce1106568ef9fec17e3c72d289416fac02a5.tar.gz cpython-281cce1106568ef9fec17e3c72d289416fac02a5.tar.bz2 |
bpo-40521: Make MemoryError free list per interpreter (GH-21086)
Each interpreter now has its own MemoryError free list: it is not
longer shared by all interpreters.
Add _Py_exc_state structure and PyInterpreterState.exc_state member.
Move also errnomap into _Py_exc_state.
Diffstat (limited to 'Objects/exceptions.c')
-rw-r--r-- | Objects/exceptions.c | 75 |
1 files changed, 45 insertions, 30 deletions
diff --git a/Objects/exceptions.c b/Objects/exceptions.c index db5e3da..1195ba1 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -19,8 +19,13 @@ PyObject *PyExc_IOError = NULL; PyObject *PyExc_WindowsError = NULL; #endif -/* The dict map from errno codes to OSError subclasses */ -static PyObject *errnomap = NULL; + +static struct _Py_exc_state* +get_exc_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->exc_state; +} /* NOTE: If the exception class hierarchy changes, don't forget to update @@ -985,10 +990,11 @@ OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) )) goto error; + struct _Py_exc_state *state = get_exc_state(); if (myerrno && PyLong_Check(myerrno) && - errnomap && (PyObject *) type == PyExc_OSError) { + state->errnomap && (PyObject *) type == PyExc_OSError) { PyObject *newtype; - newtype = PyDict_GetItemWithError(errnomap, myerrno); + newtype = PyDict_GetItemWithError(state->errnomap, myerrno); if (newtype) { assert(PyType_Check(newtype)); type = (PyTypeObject *) newtype; @@ -2274,8 +2280,6 @@ SimpleExtendsException(PyExc_Exception, ReferenceError, */ #define MEMERRORS_SAVE 16 -static PyBaseExceptionObject *memerrors_freelist = NULL; -static int memerrors_numfree = 0; static PyObject * MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -2284,16 +2288,22 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (type != (PyTypeObject *) PyExc_MemoryError) return BaseException_new(type, args, kwds); - if (memerrors_freelist == NULL) + + struct _Py_exc_state *state = get_exc_state(); + if (state->memerrors_freelist == NULL) { return BaseException_new(type, args, kwds); + } + /* Fetch object from freelist and revive it */ - self = memerrors_freelist; + self = state->memerrors_freelist; self->args = PyTuple_New(0); /* This shouldn't happen since the empty tuple is persistent */ - if (self->args == NULL) + if (self->args == NULL) { return NULL; - memerrors_freelist = (PyBaseExceptionObject *) self->dict; - memerrors_numfree--; + } + + state->memerrors_freelist = (PyBaseExceptionObject *) self->dict; + state->memerrors_numfree--; self->dict = NULL; _Py_NewReference((PyObject *)self); _PyObject_GC_TRACK(self); @@ -2305,12 +2315,15 @@ MemoryError_dealloc(PyBaseExceptionObject *self) { _PyObject_GC_UNTRACK(self); BaseException_clear(self); - if (memerrors_numfree >= MEMERRORS_SAVE) + + struct _Py_exc_state *state = get_exc_state(); + if (state->memerrors_numfree >= MEMERRORS_SAVE) { Py_TYPE(self)->tp_free((PyObject *)self); + } else { - self->dict = (PyObject *) memerrors_freelist; - memerrors_freelist = self; - memerrors_numfree++; + self->dict = (PyObject *) state->memerrors_freelist; + state->memerrors_freelist = self; + state->memerrors_numfree++; } } @@ -2335,11 +2348,11 @@ preallocate_memerrors(void) } static void -free_preallocated_memerrors(void) +free_preallocated_memerrors(struct _Py_exc_state *state) { - while (memerrors_freelist != NULL) { - PyObject *self = (PyObject *) memerrors_freelist; - memerrors_freelist = (PyBaseExceptionObject *) memerrors_freelist->dict; + while (state->memerrors_freelist != NULL) { + PyObject *self = (PyObject *) state->memerrors_freelist; + state->memerrors_freelist = (PyBaseExceptionObject *)state->memerrors_freelist->dict; Py_TYPE(self)->tp_free((PyObject *)self); } } @@ -2507,8 +2520,10 @@ SimpleExtendsException(PyExc_Warning, ResourceWarning, #endif /* MS_WINDOWS */ PyStatus -_PyExc_Init(void) +_PyExc_Init(PyThreadState *tstate) { + struct _Py_exc_state *state = &tstate->interp->exc_state; + #define PRE_INIT(TYPE) \ if (!(_PyExc_ ## TYPE.tp_flags & Py_TPFLAGS_READY)) { \ if (PyType_Ready(&_PyExc_ ## TYPE) < 0) { \ @@ -2521,7 +2536,7 @@ _PyExc_Init(void) do { \ PyObject *_code = PyLong_FromLong(CODE); \ assert(_PyObject_RealIsSubclass(PyExc_ ## TYPE, PyExc_OSError)); \ - if (!_code || PyDict_SetItem(errnomap, _code, PyExc_ ## TYPE)) \ + if (!_code || PyDict_SetItem(state->errnomap, _code, PyExc_ ## TYPE)) \ return _PyStatus_ERR("errmap insertion problem."); \ Py_DECREF(_code); \ } while (0) @@ -2595,15 +2610,14 @@ _PyExc_Init(void) PRE_INIT(TimeoutError); if (preallocate_memerrors() < 0) { - return _PyStatus_ERR("Could not preallocate MemoryError object"); + return _PyStatus_NO_MEMORY(); } /* Add exceptions to errnomap */ - if (!errnomap) { - errnomap = PyDict_New(); - if (!errnomap) { - return _PyStatus_ERR("Cannot allocate map from errnos to OSError subclasses"); - } + assert(state->errnomap == NULL); + state->errnomap = PyDict_New(); + if (!state->errnomap) { + return _PyStatus_NO_MEMORY(); } ADD_ERRNO(BlockingIOError, EAGAIN); @@ -2741,10 +2755,11 @@ _PyBuiltins_AddExceptions(PyObject *bltinmod) } void -_PyExc_Fini(void) +_PyExc_Fini(PyThreadState *tstate) { - free_preallocated_memerrors(); - Py_CLEAR(errnomap); + struct _Py_exc_state *state = &tstate->interp->exc_state; + free_preallocated_memerrors(state); + Py_CLEAR(state->errnomap); } /* Helper to do the equivalent of "raise X from Y" in C, but always using |