@@ -121,12 +121,6 @@ def fork():
121121 # Parent and child process.
122122 return pid , master_fd
123123
124- def _writen (fd , data ):
125- """Write all the data to a descriptor."""
126- while data :
127- n = os .write (fd , data )
128- data = data [n :]
129-
130124def _read (fd ):
131125 """Default read function."""
132126 return os .read (fd , 1024 )
@@ -136,9 +130,42 @@ def _copy(master_fd, master_read=_read, stdin_read=_read):
136130 Copies
137131 pty master -> standard output (master_read)
138132 standard input -> pty master (stdin_read)"""
139- fds = [master_fd , STDIN_FILENO ]
140- while fds :
141- rfds , _wfds , _xfds = select (fds , [], [])
133+ if os .get_blocking (master_fd ):
134+ # If we write more than tty/ndisc is willing to buffer, we may block
135+ # indefinitely. So we set master_fd to non-blocking temporarily during
136+ # the copy operation.
137+ os .set_blocking (master_fd , False )
138+ try :
139+ _copy (master_fd , master_read = master_read , stdin_read = stdin_read )
140+ finally :
141+ # restore blocking mode for backwards compatibility
142+ os .set_blocking (master_fd , True )
143+ return
144+ high_waterlevel = 4096
145+ stdin_avail = master_fd != STDIN_FILENO
146+ stdout_avail = master_fd != STDOUT_FILENO
147+ i_buf = b''
148+ o_buf = b''
149+ while 1 :
150+ rfds = []
151+ wfds = []
152+ if stdin_avail and len (i_buf ) < high_waterlevel :
153+ rfds .append (STDIN_FILENO )
154+ if stdout_avail and len (o_buf ) < high_waterlevel :
155+ rfds .append (master_fd )
156+ if stdout_avail and len (o_buf ) > 0 :
157+ wfds .append (STDOUT_FILENO )
158+ if len (i_buf ) > 0 :
159+ wfds .append (master_fd )
160+
161+ rfds , wfds , _xfds = select (rfds , wfds , [])
162+
163+ if STDOUT_FILENO in wfds :
164+ try :
165+ n = os .write (STDOUT_FILENO , o_buf )
166+ o_buf = o_buf [n :]
167+ except OSError :
168+ stdout_avail = False
142169
143170 if master_fd in rfds :
144171 # Some OSes signal EOF by returning an empty byte string,
@@ -150,15 +177,18 @@ def _copy(master_fd, master_read=_read, stdin_read=_read):
150177 if not data : # Reached EOF.
151178 return # Assume the child process has exited and is
152179 # unreachable, so we clean up.
153- else :
154- os .write (STDOUT_FILENO , data )
180+ o_buf += data
181+
182+ if master_fd in wfds :
183+ n = os .write (master_fd , i_buf )
184+ i_buf = i_buf [n :]
155185
156- if STDIN_FILENO in rfds :
186+ if stdin_avail and STDIN_FILENO in rfds :
157187 data = stdin_read (STDIN_FILENO )
158188 if not data :
159- fds . remove ( STDIN_FILENO )
189+ stdin_avail = False
160190 else :
161- _writen ( master_fd , data )
191+ i_buf += data
162192
163193def spawn (argv , master_read = _read , stdin_read = _read ):
164194 """Create a spawned process."""
0 commit comments