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