@@ -35,25 +35,53 @@ def __init__(self, loop, protocol, args, shell,
3535 self ._pipes [2 ] = None
3636
3737 # Create the child process: set the _proc attribute
38+ self ._loop .create_task (self ._create_child (
39+ waiter , args = args , shell = shell , stdin = stdin , stdout = stdout ,
40+ stderr = stderr , bufsize = bufsize , start_kwargs = kwargs ))
41+
42+ @coroutine
43+ def _create_child (self , waiter , args , shell , stdin , stdout , stderr ,
44+ bufsize , start_kwargs ):
3845 try :
39- self ._start (args = args , shell = shell , stdin = stdin , stdout = stdout ,
40- stderr = stderr , bufsize = bufsize , ** kwargs )
41- except :
42- self .close ()
43- raise
46+ try :
47+ start = self ._start (args = args , shell = shell , stdin = stdin ,
48+ stdout = stdout , stderr = stderr ,
49+ bufsize = bufsize , ** start_kwargs )
50+
51+ if start is not None :
52+ # _start is not required to be a coroutine
53+ yield from start
54+ except :
55+ self .close ()
56+ raise
4457
45- self ._pid = self ._proc .pid
46- self ._extra ['subprocess' ] = self ._proc
58+ self ._pid = self ._proc .pid
59+ self ._extra ['subprocess' ] = self ._proc
4760
48- if self ._loop .get_debug ():
49- if isinstance (args , (bytes , str )):
50- program = args
61+ if self ._loop .get_debug ():
62+ if isinstance (args , (bytes , str )):
63+ program = args
64+ else :
65+ program = args [0 ]
66+ logger .debug ('process %r created: pid %s' , program , self ._pid )
67+
68+ if self ._closed :
69+ # transport.close() may have been called concurrently, for
70+ # instance if _make_subprocess_transport() has been cancelled.
71+ if self ._proc .stdin :
72+ self ._proc .stdin .close ()
73+ if self ._proc .stdout :
74+ self ._proc .stdout .close ()
75+ if self ._proc .stderr :
76+ self ._proc .stderr .close ()
5177 else :
52- program = args [0 ]
53- logger .debug ('process %r created: pid %s' ,
54- program , self ._pid )
55-
56- self ._loop .create_task (self ._connect_pipes (waiter ))
78+ yield from self ._connect_pipes (waiter )
79+ except Exception as exc :
80+ if waiter is not None and not waiter .cancelled ():
81+ waiter .set_exception (exc )
82+ else :
83+ if waiter is not None and not waiter .cancelled ():
84+ waiter .set_result (None )
5785
5886 def __repr__ (self ):
5987 info = [self .__class__ .__name__ ]
@@ -161,40 +189,33 @@ def kill(self):
161189
162190 @coroutine
163191 def _connect_pipes (self , waiter ):
164- try :
165- proc = self ._proc
166- loop = self ._loop
167-
168- if proc .stdin is not None :
169- _ , pipe = yield from loop .connect_write_pipe (
170- lambda : WriteSubprocessPipeProto (self , 0 ),
171- proc .stdin )
172- self ._pipes [0 ] = pipe
173-
174- if proc .stdout is not None :
175- _ , pipe = yield from loop .connect_read_pipe (
176- lambda : ReadSubprocessPipeProto (self , 1 ),
177- proc .stdout )
178- self ._pipes [1 ] = pipe
179-
180- if proc .stderr is not None :
181- _ , pipe = yield from loop .connect_read_pipe (
182- lambda : ReadSubprocessPipeProto (self , 2 ),
183- proc .stderr )
184- self ._pipes [2 ] = pipe
185-
186- assert self ._pending_calls is not None
187-
188- loop .call_soon (self ._protocol .connection_made , self )
189- for callback , data in self ._pending_calls :
190- loop .call_soon (callback , * data )
191- self ._pending_calls = None
192- except Exception as exc :
193- if waiter is not None and not waiter .cancelled ():
194- waiter .set_exception (exc )
195- else :
196- if waiter is not None and not waiter .cancelled ():
197- waiter .set_result (None )
192+ proc = self ._proc
193+ loop = self ._loop
194+
195+ if proc .stdin is not None :
196+ _ , pipe = yield from loop .connect_write_pipe (
197+ lambda : WriteSubprocessPipeProto (self , 0 ),
198+ proc .stdin )
199+ self ._pipes [0 ] = pipe
200+
201+ if proc .stdout is not None :
202+ _ , pipe = yield from loop .connect_read_pipe (
203+ lambda : ReadSubprocessPipeProto (self , 1 ),
204+ proc .stdout )
205+ self ._pipes [1 ] = pipe
206+
207+ if proc .stderr is not None :
208+ _ , pipe = yield from loop .connect_read_pipe (
209+ lambda : ReadSubprocessPipeProto (self , 2 ),
210+ proc .stderr )
211+ self ._pipes [2 ] = pipe
212+
213+ assert self ._pending_calls is not None
214+
215+ loop .call_soon (self ._protocol .connection_made , self )
216+ for callback , data in self ._pending_calls :
217+ loop .call_soon (callback , * data )
218+ self ._pending_calls = None
198219
199220 def _call (self , cb , * data ):
200221 if self ._pending_calls is not None :
0 commit comments