@@ -115,12 +115,6 @@ def fork():
115115 # Parent and child process.
116116 return pid , master_fd
117117
118- def _writen (fd , data ):
119- """Write all the data to a descriptor."""
120- while data :
121- n = os .write (fd , data )
122- data = data [n :]
123-
124118def _read (fd ):
125119 """Default read function."""
126120 return os .read (fd , 1024 )
@@ -130,9 +124,42 @@ def _copy(master_fd, master_read=_read, stdin_read=_read):
130124 Copies
131125 pty master -> standard output (master_read)
132126 standard input -> pty master (stdin_read)"""
133- fds = [master_fd , STDIN_FILENO ]
134- while fds :
135- rfds , _wfds , _xfds = select (fds , [], [])
127+ if os .get_blocking (master_fd ):
128+ # If we write more than tty/ndisc is willing to buffer, we may block
129+ # indefinitely. So we set master_fd to non-blocking temporarily during
130+ # the copy operation.
131+ os .set_blocking (master_fd , False )
132+ try :
133+ _copy (master_fd , master_read = master_read , stdin_read = stdin_read )
134+ finally :
135+ # restore blocking mode for backwards compatibility
136+ os .set_blocking (master_fd , True )
137+ return
138+ high_waterlevel = 4096
139+ stdin_avail = master_fd != STDIN_FILENO
140+ stdout_avail = master_fd != STDOUT_FILENO
141+ i_buf = b''
142+ o_buf = b''
143+ while 1 :
144+ rfds = []
145+ wfds = []
146+ if stdin_avail and len (i_buf ) < high_waterlevel :
147+ rfds .append (STDIN_FILENO )
148+ if stdout_avail and len (o_buf ) < high_waterlevel :
149+ rfds .append (master_fd )
150+ if stdout_avail and len (o_buf ) > 0 :
151+ wfds .append (STDOUT_FILENO )
152+ if len (i_buf ) > 0 :
153+ wfds .append (master_fd )
154+
155+ rfds , wfds , _xfds = select (rfds , wfds , [])
156+
157+ if STDOUT_FILENO in wfds :
158+ try :
159+ n = os .write (STDOUT_FILENO , o_buf )
160+ o_buf = o_buf [n :]
161+ except OSError :
162+ stdout_avail = False
136163
137164 if master_fd in rfds :
138165 # Some OSes signal EOF by returning an empty byte string,
@@ -144,15 +171,18 @@ def _copy(master_fd, master_read=_read, stdin_read=_read):
144171 if not data : # Reached EOF.
145172 return # Assume the child process has exited and is
146173 # unreachable, so we clean up.
147- else :
148- os .write (STDOUT_FILENO , data )
174+ o_buf += data
175+
176+ if master_fd in wfds :
177+ n = os .write (master_fd , i_buf )
178+ i_buf = i_buf [n :]
149179
150- if STDIN_FILENO in rfds :
180+ if stdin_avail and STDIN_FILENO in rfds :
151181 data = stdin_read (STDIN_FILENO )
152182 if not data :
153- fds . remove ( STDIN_FILENO )
183+ stdin_avail = False
154184 else :
155- _writen ( master_fd , data )
185+ i_buf += data
156186
157187def spawn (argv , master_read = _read , stdin_read = _read ):
158188 """Create a spawned process."""
0 commit comments