@@ -115,12 +115,6 @@ def fork():
115
115
# Parent and child process.
116
116
return pid , master_fd
117
117
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
-
124
118
def _read (fd ):
125
119
"""Default read function."""
126
120
return os .read (fd , 1024 )
@@ -130,9 +124,42 @@ def _copy(master_fd, master_read=_read, stdin_read=_read):
130
124
Copies
131
125
pty master -> standard output (master_read)
132
126
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
136
163
137
164
if master_fd in rfds :
138
165
# Some OSes signal EOF by returning an empty byte string,
@@ -144,15 +171,18 @@ def _copy(master_fd, master_read=_read, stdin_read=_read):
144
171
if not data : # Reached EOF.
145
172
return # Assume the child process has exited and is
146
173
# 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 :]
149
179
150
- if STDIN_FILENO in rfds :
180
+ if stdin_avail and STDIN_FILENO in rfds :
151
181
data = stdin_read (STDIN_FILENO )
152
182
if not data :
153
- fds . remove ( STDIN_FILENO )
183
+ stdin_avail = False
154
184
else :
155
- _writen ( master_fd , data )
185
+ i_buf += data
156
186
157
187
def spawn (argv , master_read = _read , stdin_read = _read ):
158
188
"""Create a spawned process."""
0 commit comments