6161import codecs
6262import _fileio
6363import warnings
64+ import threading
6465
6566# open() uses st_blksize whenever we can
6667DEFAULT_BUFFER_SIZE = 8 * 1024 # bytes
@@ -895,6 +896,7 @@ def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
895896 _BufferedIOMixin .__init__ (self , raw )
896897 self .buffer_size = buffer_size
897898 self ._reset_read_buf ()
899+ self ._read_lock = threading .Lock ()
898900
899901 def _reset_read_buf (self ):
900902 self ._read_buf = b""
@@ -908,6 +910,10 @@ def read(self, n=None):
908910 mode. If n is negative, read until EOF or until read() would
909911 block.
910912 """
913+ with self ._read_lock :
914+ return self ._read_unlocked (n )
915+
916+ def _read_unlocked (self , n = None ):
911917 nodata_val = b""
912918 empty_values = (b"" , None )
913919 buf = self ._read_buf
@@ -960,6 +966,10 @@ def peek(self, n=0):
960966 do at most one raw read to satisfy it. We never return more
961967 than self.buffer_size.
962968 """
969+ with self ._read_lock :
970+ return self ._peek_unlocked (n )
971+
972+ def _peek_unlocked (self , n = 0 ):
963973 want = min (n , self .buffer_size )
964974 have = len (self ._read_buf ) - self ._read_pos
965975 if have < want :
@@ -976,18 +986,21 @@ def read1(self, n):
976986 # only return buffered bytes. Otherwise, we do one raw read.
977987 if n <= 0 :
978988 return b""
979- self .peek (1 )
980- return self .read (min (n , len (self ._read_buf ) - self ._read_pos ))
989+ with self ._read_lock :
990+ self ._peek_unlocked (1 )
991+ return self ._read_unlocked (
992+ min (n , len (self ._read_buf ) - self ._read_pos ))
981993
982994 def tell (self ):
983995 return self .raw .tell () - len (self ._read_buf ) + self ._read_pos
984996
985997 def seek (self , pos , whence = 0 ):
986- if whence == 1 :
987- pos -= len (self ._read_buf ) - self ._read_pos
988- pos = self .raw .seek (pos , whence )
989- self ._reset_read_buf ()
990- return pos
998+ with self ._read_lock :
999+ if whence == 1 :
1000+ pos -= len (self ._read_buf ) - self ._read_pos
1001+ pos = self .raw .seek (pos , whence )
1002+ self ._reset_read_buf ()
1003+ return pos
9911004
9921005
9931006class BufferedWriter (_BufferedIOMixin ):
@@ -1009,43 +1022,51 @@ def __init__(self, raw,
10091022 if max_buffer_size is None
10101023 else max_buffer_size )
10111024 self ._write_buf = bytearray ()
1025+ self ._write_lock = threading .Lock ()
10121026
10131027 def write (self , b ):
10141028 if self .closed :
10151029 raise ValueError ("write to closed file" )
10161030 if isinstance (b , str ):
10171031 raise TypeError ("can't write str to binary stream" )
1018- # XXX we can implement some more tricks to try and avoid partial writes
1019- if len (self ._write_buf ) > self .buffer_size :
1020- # We're full, so let's pre-flush the buffer
1021- try :
1022- self .flush ()
1023- except BlockingIOError as e :
1024- # We can't accept anything else.
1025- # XXX Why not just let the exception pass through?
1026- raise BlockingIOError (e .errno , e .strerror , 0 )
1027- before = len (self ._write_buf )
1028- self ._write_buf .extend (b )
1029- written = len (self ._write_buf ) - before
1030- if len (self ._write_buf ) > self .buffer_size :
1031- try :
1032- self .flush ()
1033- except BlockingIOError as e :
1034- if (len (self ._write_buf ) > self .max_buffer_size ):
1035- # We've hit max_buffer_size. We have to accept a partial
1036- # write and cut back our buffer.
1037- overage = len (self ._write_buf ) - self .max_buffer_size
1038- self ._write_buf = self ._write_buf [:self .max_buffer_size ]
1039- raise BlockingIOError (e .errno , e .strerror , overage )
1040- return written
1032+ with self ._write_lock :
1033+ # XXX we can implement some more tricks to try and avoid
1034+ # partial writes
1035+ if len (self ._write_buf ) > self .buffer_size :
1036+ # We're full, so let's pre-flush the buffer
1037+ try :
1038+ self ._flush_unlocked ()
1039+ except BlockingIOError as e :
1040+ # We can't accept anything else.
1041+ # XXX Why not just let the exception pass through?
1042+ raise BlockingIOError (e .errno , e .strerror , 0 )
1043+ before = len (self ._write_buf )
1044+ self ._write_buf .extend (b )
1045+ written = len (self ._write_buf ) - before
1046+ if len (self ._write_buf ) > self .buffer_size :
1047+ try :
1048+ self ._flush_unlocked ()
1049+ except BlockingIOError as e :
1050+ if len (self ._write_buf ) > self .max_buffer_size :
1051+ # We've hit max_buffer_size. We have to accept a
1052+ # partial write and cut back our buffer.
1053+ overage = len (self ._write_buf ) - self .max_buffer_size
1054+ self ._write_buf = self ._write_buf [:self .max_buffer_size ]
1055+ raise BlockingIOError (e .errno , e .strerror , overage )
1056+ return written
10411057
10421058 def truncate (self , pos = None ):
1043- self .flush ()
1044- if pos is None :
1045- pos = self .raw .tell ()
1046- return self .raw .truncate (pos )
1059+ with self ._write_lock :
1060+ self ._flush_unlocked ()
1061+ if pos is None :
1062+ pos = self .raw .tell ()
1063+ return self .raw .truncate (pos )
10471064
10481065 def flush (self ):
1066+ with self ._write_lock :
1067+ self ._flush_unlocked ()
1068+
1069+ def _flush_unlocked (self ):
10491070 if self .closed :
10501071 raise ValueError ("flush of closed file" )
10511072 written = 0
@@ -1064,8 +1085,9 @@ def tell(self):
10641085 return self .raw .tell () + len (self ._write_buf )
10651086
10661087 def seek (self , pos , whence = 0 ):
1067- self .flush ()
1068- return self .raw .seek (pos , whence )
1088+ with self ._write_lock :
1089+ self ._flush_unlocked ()
1090+ return self .raw .seek (pos , whence )
10691091
10701092
10711093class BufferedRWPair (BufferedIOBase ):
@@ -1155,7 +1177,8 @@ def seek(self, pos, whence=0):
11551177 # First do the raw seek, then empty the read buffer, so that
11561178 # if the raw seek fails, we don't lose buffered data forever.
11571179 pos = self .raw .seek (pos , whence )
1158- self ._reset_read_buf ()
1180+ with self ._read_lock :
1181+ self ._reset_read_buf ()
11591182 return pos
11601183
11611184 def tell (self ):
@@ -1192,8 +1215,9 @@ def read1(self, n):
11921215 def write (self , b ):
11931216 if self ._read_buf :
11941217 # Undo readahead
1195- self .raw .seek (self ._read_pos - len (self ._read_buf ), 1 )
1196- self ._reset_read_buf ()
1218+ with self ._read_lock :
1219+ self .raw .seek (self ._read_pos - len (self ._read_buf ), 1 )
1220+ self ._reset_read_buf ()
11971221 return BufferedWriter .write (self , b )
11981222
11991223
0 commit comments