diff options
Diffstat (limited to 'Modules/_io/bufferedio.c')
| -rw-r--r-- | Modules/_io/bufferedio.c | 148 |
1 files changed, 116 insertions, 32 deletions
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index ea0302b..365bb85 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -52,7 +52,6 @@ bufferediobase_readinto(PyObject *self, PyObject *args) Py_buffer buf; Py_ssize_t len; PyObject *data; - _Py_IDENTIFIER(read); if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) { return NULL; @@ -92,7 +91,9 @@ bufferediobase_readinto(PyObject *self, PyObject *args) static PyObject * bufferediobase_unsupported(const char *message) { - PyErr_SetString(IO_STATE->unsupported_operation, message); + _PyIO_State *state = IO_STATE(); + if (state != NULL) + PyErr_SetString(state->unsupported_operation, message); return NULL; } @@ -190,7 +191,8 @@ PyTypeObject PyBufferedIOBase_Type = { 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferediobase_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -209,6 +211,16 @@ PyTypeObject PyBufferedIOBase_Type = { 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -220,7 +232,7 @@ typedef struct { int detached; int readable; int writable; - int deallocating; + char finalizing; /* True if this is a vanilla Buffered object (rather than a user derived class) *and* the raw stream is a vanilla FileIO object. */ @@ -288,14 +300,35 @@ typedef struct { static int _enter_buffered_busy(buffered *self) { + int relax_locking; + PyLockStatus st; if (self->owner == PyThread_get_thread_ident()) { PyErr_Format(PyExc_RuntimeError, "reentrant call inside %R", self); return 0; } + relax_locking = (_Py_Finalizing != NULL); Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); + if (!relax_locking) + st = PyThread_acquire_lock(self->lock, 1); + else { + /* When finalizing, we don't want a deadlock to happen with daemon + * threads abruptly shut down while they owned the lock. + * Therefore, only wait for a grace period (1 s.). + * Note that non-daemon threads have already exited here, so this + * shouldn't affect carefully written threaded I/O code. + */ + st = PyThread_acquire_lock_timed(self->lock, 1e6, 0); + } Py_END_ALLOW_THREADS + if (relax_locking && st != PY_LOCK_ACQUIRED) { + PyObject *msgobj = PyUnicode_FromFormat( + "could not acquire lock for %A at interpreter " + "shutdown, possibly due to daemon threads", + (PyObject *) self); + char *msg = PyUnicode_AsUTF8(msgobj); + Py_FatalError(msg); + } return 1; } @@ -384,8 +417,8 @@ _enter_buffered_busy(buffered *self) static void buffered_dealloc(buffered *self) { - self->deallocating = 1; - if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) + self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) return; _PyObject_GC_UNTRACK(self); self->ok = 0; @@ -428,8 +461,6 @@ buffered_traverse(buffered *self, visitproc visit, void *arg) static int buffered_clear(buffered *self) { - if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) - return -1; self->ok = 0; Py_CLEAR(self->raw); Py_CLEAR(self->dict); @@ -508,7 +539,7 @@ buffered_close(buffered *self, PyObject *args) goto end; } - if (self->deallocating) { + if (self->finalizing) { PyObject *r = buffered_dealloc_warn(self, (PyObject *) self); if (r) Py_DECREF(r); @@ -527,20 +558,14 @@ buffered_close(buffered *self, PyObject *args) res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL); + if (self->buffer) { + PyMem_Free(self->buffer); + self->buffer = NULL; + } + if (exc != NULL) { - if (res != NULL) { - Py_CLEAR(res); - PyErr_Restore(exc, val, tb); - } - else { - PyObject *val2; - Py_DECREF(exc); - Py_XDECREF(tb); - PyErr_Fetch(&exc, &val2, &tb); - PyErr_NormalizeException(&exc, &val2, &tb); - PyException_SetContext(val2, val); - PyErr_Restore(exc, val2, tb); - } + _PyErr_ChainExceptions(exc, val, tb); + Py_CLEAR(res); } end: @@ -658,6 +683,11 @@ static void _set_BlockingIOError(char *msg, Py_ssize_t written) { PyObject *err; +#ifdef Py_DEBUG + /* in debug mode, PyEval_EvalFrameEx() fails with an assertion error + if an exception is set when it is called */ + PyErr_Clear(); +#endif err = PyObject_CallFunction(PyExc_BlockingIOError, "isn", errno, msg, written); if (err) @@ -859,6 +889,8 @@ buffered_peek(buffered *self, PyObject *args) PyObject *res = NULL; CHECK_INITIALIZED(self) + CHECK_CLOSED(self, "peek of closed file") + if (!PyArg_ParseTuple(args, "|n:peek", &n)) { return NULL; } @@ -933,6 +965,9 @@ buffered_read1(buffered *self, PyObject *args) "read length must be positive"); return NULL; } + + CHECK_CLOSED(self, "read of closed file") + if (n == 0) return PyBytes_FromStringAndSize(NULL, 0); @@ -1350,7 +1385,7 @@ buffered_repr(buffered *self) nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name); if (nameobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) + if (PyErr_ExceptionMatches(PyExc_Exception)) PyErr_Clear(); else return NULL; @@ -1739,6 +1774,7 @@ static PyMethodDef bufferedreader_methods[] = { static PyMemberDef bufferedreader_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -1771,7 +1807,7 @@ PyTypeObject PyBufferedReader_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedreader_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -1790,6 +1826,16 @@ PyTypeObject PyBufferedReader_Type = { (initproc)bufferedreader_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2120,6 +2166,7 @@ static PyMethodDef bufferedwriter_methods[] = { static PyMemberDef bufferedwriter_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -2152,7 +2199,7 @@ PyTypeObject PyBufferedWriter_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedwriter_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -2171,6 +2218,16 @@ PyTypeObject PyBufferedWriter_Type = { (initproc)bufferedwriter_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2334,12 +2391,18 @@ bufferedrwpair_writable(rwpair *self, PyObject *args) static PyObject * bufferedrwpair_close(rwpair *self, PyObject *args) { + PyObject *exc = NULL, *val, *tb; PyObject *ret = _forward_call(self->writer, &PyId_close, args); if (ret == NULL) - return NULL; - Py_DECREF(ret); - - return _forward_call(self->reader, &PyId_close, args); + PyErr_Fetch(&exc, &val, &tb); + else + Py_DECREF(ret); + ret = _forward_call(self->reader, &PyId_close, args); + if (exc != NULL) { + _PyErr_ChainExceptions(exc, val, tb); + Py_CLEAR(ret); + } + return ret; } static PyObject * @@ -2413,7 +2476,7 @@ PyTypeObject PyBufferedRWPair_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ bufferedrwpair_doc, /* tp_doc */ (traverseproc)bufferedrwpair_traverse, /* tp_traverse */ (inquiry)bufferedrwpair_clear, /* tp_clear */ @@ -2432,6 +2495,16 @@ PyTypeObject PyBufferedRWPair_Type = { (initproc)bufferedrwpair_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2519,6 +2592,7 @@ static PyMethodDef bufferedrandom_methods[] = { static PyMemberDef bufferedrandom_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -2551,7 +2625,7 @@ PyTypeObject PyBufferedRandom_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedrandom_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -2570,4 +2644,14 @@ PyTypeObject PyBufferedRandom_Type = { (initproc)bufferedrandom_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; |
