summaryrefslogtreecommitdiffstats
path: root/Objects/exceptions.c
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-06-23 20:55:46 (GMT)
committerGitHub <noreply@github.com>2020-06-23 20:55:46 (GMT)
commit281cce1106568ef9fec17e3c72d289416fac02a5 (patch)
tree529d24e0db048c8914cc8a12ebf7b8328a62665d /Objects/exceptions.c
parent2c6e4e91c5a4d3f25908108f4ed32aba936df70c (diff)
downloadcpython-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.c75
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