@@ -596,7 +596,7 @@ buffered_getstate(buffered *self, PyObject *args)
596596
597597/* Forward decls */
598598static PyObject *
599- _bufferedwriter_flush_unlocked (buffered * , int );
599+ _bufferedwriter_flush_unlocked (buffered * );
600600static Py_ssize_t
601601_bufferedreader_fill_buffer (buffered * self );
602602static void
@@ -618,6 +618,18 @@ _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len);
618618 * Helpers
619619 */
620620
621+ /* Sets the current error to BlockingIOError */
622+ static void
623+ _set_BlockingIOError (char * msg , Py_ssize_t written )
624+ {
625+ PyObject * err ;
626+ err = PyObject_CallFunction (PyExc_BlockingIOError , "isn" ,
627+ errno , msg , written );
628+ if (err )
629+ PyErr_SetObject (PyExc_BlockingIOError , err );
630+ Py_XDECREF (err );
631+ }
632+
621633/* Returns the address of the `written` member if a BlockingIOError was
622634 raised, NULL otherwise. The error is always re-raised. */
623635static Py_ssize_t *
@@ -772,7 +784,7 @@ buffered_flush_and_rewind_unlocked(buffered *self)
772784{
773785 PyObject * res ;
774786
775- res = _bufferedwriter_flush_unlocked (self , 0 );
787+ res = _bufferedwriter_flush_unlocked (self );
776788 if (res == NULL )
777789 return NULL ;
778790 Py_DECREF (res );
@@ -1188,7 +1200,7 @@ buffered_seek(buffered *self, PyObject *args)
11881200
11891201 /* Fallback: invoke raw seek() method and clear buffer */
11901202 if (self -> writable ) {
1191- res = _bufferedwriter_flush_unlocked (self , 0 );
1203+ res = _bufferedwriter_flush_unlocked (self );
11921204 if (res == NULL )
11931205 goto end ;
11941206 Py_CLEAR (res );
@@ -1807,6 +1819,7 @@ _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
18071819 Py_buffer buf ;
18081820 PyObject * memobj , * res ;
18091821 Py_ssize_t n ;
1822+ int errnum ;
18101823 /* NOTE: the buffer needn't be released as its object is NULL. */
18111824 if (PyBuffer_FillInfo (& buf , NULL , start , len , 1 , PyBUF_CONTIG_RO ) == -1 )
18121825 return -1 ;
@@ -1819,11 +1832,21 @@ _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
18191832 raised (see issue #10956).
18201833 */
18211834 do {
1835+ errno = 0 ;
18221836 res = PyObject_CallMethodObjArgs (self -> raw , _PyIO_str_write , memobj , NULL );
1837+ errnum = errno ;
18231838 } while (res == NULL && _trap_eintr ());
18241839 Py_DECREF (memobj );
18251840 if (res == NULL )
18261841 return -1 ;
1842+ if (res == Py_None ) {
1843+ /* Non-blocking stream would have blocked. Special return code!
1844+ Being paranoid we reset errno in case it is changed by code
1845+ triggered by a decref. errno is used by _set_BlockingIOError(). */
1846+ Py_DECREF (res );
1847+ errno = errnum ;
1848+ return -2 ;
1849+ }
18271850 n = PyNumber_AsSsize_t (res , PyExc_ValueError );
18281851 Py_DECREF (res );
18291852 if (n < 0 || n > len ) {
@@ -1840,7 +1863,7 @@ _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
18401863/* `restore_pos` is 1 if we need to restore the raw stream position at
18411864 the end, 0 otherwise. */
18421865static PyObject *
1843- _bufferedwriter_flush_unlocked (buffered * self , int restore_pos )
1866+ _bufferedwriter_flush_unlocked (buffered * self )
18441867{
18451868 Py_ssize_t written = 0 ;
18461869 Py_off_t n , rewind ;
@@ -1862,14 +1885,11 @@ _bufferedwriter_flush_unlocked(buffered *self, int restore_pos)
18621885 Py_SAFE_DOWNCAST (self -> write_end - self -> write_pos ,
18631886 Py_off_t , Py_ssize_t ));
18641887 if (n == -1 ) {
1865- Py_ssize_t * w = _buffered_check_blocking_error ();
1866- if (w == NULL )
1867- goto error ;
1868- self -> write_pos += * w ;
1869- self -> raw_pos = self -> write_pos ;
1870- written += * w ;
1871- * w = written ;
1872- /* Already re-raised */
1888+ goto error ;
1889+ }
1890+ else if (n == -2 ) {
1891+ _set_BlockingIOError ("write could not complete without blocking" ,
1892+ 0 );
18731893 goto error ;
18741894 }
18751895 self -> write_pos += n ;
@@ -1882,16 +1902,6 @@ _bufferedwriter_flush_unlocked(buffered *self, int restore_pos)
18821902 goto error ;
18831903 }
18841904
1885- if (restore_pos ) {
1886- Py_off_t forward = rewind - written ;
1887- if (forward != 0 ) {
1888- n = _buffered_raw_seek (self , forward , 1 );
1889- if (n < 0 ) {
1890- goto error ;
1891- }
1892- self -> raw_pos += forward ;
1893- }
1894- }
18951905 _bufferedwriter_reset_buf (self );
18961906
18971907end :
@@ -1944,7 +1954,7 @@ bufferedwriter_write(buffered *self, PyObject *args)
19441954 }
19451955
19461956 /* First write the current buffer */
1947- res = _bufferedwriter_flush_unlocked (self , 0 );
1957+ res = _bufferedwriter_flush_unlocked (self );
19481958 if (res == NULL ) {
19491959 Py_ssize_t * w = _buffered_check_blocking_error ();
19501960 if (w == NULL )
@@ -1967,14 +1977,19 @@ bufferedwriter_write(buffered *self, PyObject *args)
19671977 PyErr_Clear ();
19681978 memcpy (self -> buffer + self -> write_end , buf .buf , buf .len );
19691979 self -> write_end += buf .len ;
1980+ self -> pos += buf .len ;
19701981 written = buf .len ;
19711982 goto end ;
19721983 }
19731984 /* Buffer as much as possible. */
19741985 memcpy (self -> buffer + self -> write_end , buf .buf , avail );
19751986 self -> write_end += avail ;
1976- /* Already re-raised */
1977- * w = avail ;
1987+ self -> pos += avail ;
1988+ /* XXX Modifying the existing exception e using the pointer w
1989+ will change e.characters_written but not e.args[2].
1990+ Therefore we just replace with a new error. */
1991+ _set_BlockingIOError ("write could not complete without blocking" ,
1992+ avail );
19781993 goto error ;
19791994 }
19801995 Py_CLEAR (res );
@@ -1999,20 +2014,19 @@ bufferedwriter_write(buffered *self, PyObject *args)
19992014 Py_ssize_t n = _bufferedwriter_raw_write (
20002015 self , (char * ) buf .buf + written , buf .len - written );
20012016 if (n == -1 ) {
2002- Py_ssize_t * w = _buffered_check_blocking_error ();
2003- if (w == NULL )
2004- goto error ;
2005- written += * w ;
2006- remaining -= * w ;
2017+ goto error ;
2018+ } else if (n == -2 ) {
2019+ /* Write failed because raw file is non-blocking */
20072020 if (remaining > self -> buffer_size ) {
20082021 /* Can't buffer everything, still buffer as much as possible */
20092022 memcpy (self -> buffer ,
20102023 (char * ) buf .buf + written , self -> buffer_size );
20112024 self -> raw_pos = 0 ;
20122025 ADJUST_POSITION (self , self -> buffer_size );
20132026 self -> write_end = self -> buffer_size ;
2014- * w = written + self -> buffer_size ;
2015- /* Already re-raised */
2027+ written += self -> buffer_size ;
2028+ _set_BlockingIOError ("write could not complete without "
2029+ "blocking" , written );
20162030 goto error ;
20172031 }
20182032 PyErr_Clear ();
0 commit comments