diff -r cd282dd0cfe8 Lib/_pyio.py --- a/Lib/_pyio.py Thu Dec 04 01:26:35 2014 -0500 +++ b/Lib/_pyio.py Thu Dec 04 15:00:35 2014 +0100 @@ -1168,6 +1168,7 @@ self.buffer_size = buffer_size self._write_buf = bytearray() self._write_lock = Lock() + _register_writer(self) def write(self, b): if self.closed: @@ -2182,3 +2183,18 @@ def detach(self): # This doesn't make sense on StringIO. self._unsupported("detach") + + +# ____________________________________________________________ + +import atexit, weakref + +_all_writers = weakref.WeakKeyDictionary() + +def _register_writer(w): + _all_writers[w] = True + +def _flush_all_writers(): + for w in _all_writers: + w.flush() +atexit.register(_flush_all_writers) diff -r cd282dd0cfe8 Modules/_io/_iomodule.c --- a/Modules/_io/_iomodule.c Thu Dec 04 01:26:35 2014 -0500 +++ b/Modules/_io/_iomodule.c Thu Dec 04 15:00:35 2014 +0100 @@ -758,6 +758,8 @@ !(_PyIO_zero = PyLong_FromLong(0L))) goto fail; + _Py_PyAtExit(_PyIO_atexit_flush); + state->initialized = 1; return m; diff -r cd282dd0cfe8 Modules/_io/_iomodule.h --- a/Modules/_io/_iomodule.h Thu Dec 04 01:26:35 2014 -0500 +++ b/Modules/_io/_iomodule.h Thu Dec 04 15:00:35 2014 +0100 @@ -170,3 +170,5 @@ extern PyObject *_PyIO_zero; extern PyTypeObject _PyBytesIOBuffer_Type; + +extern void _PyIO_atexit_flush(void); diff -r cd282dd0cfe8 Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c Thu Dec 04 01:26:35 2014 -0500 +++ b/Modules/_io/bufferedio.c Thu Dec 04 15:00:35 2014 +0100 @@ -242,6 +242,10 @@ }; +struct doubly_linked_s { + struct doubly_linked_s *prev, *next; +}; + typedef struct { PyObject_HEAD @@ -286,8 +290,15 @@ PyObject *dict; PyObject *weakreflist; + + /* a doubly-linked chained list of "buffered" objects that need to + be flushed when the process exits */ + struct doubly_linked_s buffered_writers_list; } buffered; +static struct doubly_linked_s doubly_linked_end = { + &doubly_linked_end, &doubly_linked_end }; + /* Implementation notes: @@ -412,6 +423,15 @@ static void +remove_from_linked_list(buffered *self) +{ + self->buffered_writers_list.next->prev = self->buffered_writers_list.prev; + self->buffered_writers_list.prev->next = self->buffered_writers_list.next; + self->buffered_writers_list.prev = NULL; + self->buffered_writers_list.next = NULL; +} + +static void buffered_dealloc(buffered *self) { self->finalizing = 1; @@ -419,6 +439,8 @@ return; _PyObject_GC_UNTRACK(self); self->ok = 0; + if (self->buffered_writers_list.next != NULL) + remove_from_linked_list(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)self); Py_CLEAR(self->raw); @@ -1911,10 +1933,28 @@ self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedWriter_Type && Py_TYPE(raw) == &PyFileIO_Type); + if (self->buffered_writers_list.next == NULL) { + self->buffered_writers_list.prev = &doubly_linked_end; + self->buffered_writers_list.next = doubly_linked_end.next; + doubly_linked_end.next->prev = &self->buffered_writers_list; + doubly_linked_end.next = &self->buffered_writers_list; + } + self->ok = 1; return 0; } +void _PyIO_atexit_flush(void) +{ + while (doubly_linked_end.next != &doubly_linked_end) { + buffered *buf = (buffered *)(((char *)doubly_linked_end.next) - + offsetof(buffered, buffered_writers_list)); + remove_from_linked_list(buf); + buffered_flush(buf, NULL); + PyErr_Clear(); + } +} + static Py_ssize_t _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len) {