18
18
from pynvim .msgpack_rpc .event_loop .base import BaseEventLoop , TTransportType
19
19
20
20
logger = logging .getLogger (__name__ )
21
- debug , info , warn = (logger .debug , logger .info , logger .warning , )
21
+ debug , info , warn = (logger .debug , logger .info , logger .warning )
22
22
23
23
loop_cls = asyncio .SelectorEventLoop
24
24
@@ -47,13 +47,14 @@ def __init__(self, on_data, on_error):
47
47
@override
48
48
def connection_made (self , transport ):
49
49
"""Used to signal `asyncio.Protocol` of a successful connection."""
50
- del transport # no-op
50
+ self . _transport = transport
51
51
52
52
@override
53
53
def connection_lost (self , exc : Optional [Exception ]) -> None :
54
54
"""Used to signal `asyncio.Protocol` of a lost connection."""
55
- debug (f"connection_lost: exc = { exc } " )
56
- self ._on_error (exc if exc else EOFError ())
55
+ warn (f"connection_lost: exc = { exc } " )
56
+
57
+ self ._on_error (exc if exc else EOFError ("connection_lost" ))
57
58
58
59
@override
59
60
def data_received (self , data : bytes ) -> None :
@@ -63,11 +64,19 @@ def data_received(self, data: bytes) -> None:
63
64
@override
64
65
def pipe_connection_lost (self , fd : int , exc : Optional [Exception ]) -> None :
65
66
"""Used to signal `asyncio.SubprocessProtocol` of a lost connection."""
66
- debug ("pipe_connection_lost: fd = %s, exc = %s" , fd , exc )
67
+
68
+ assert isinstance (self ._transport , asyncio .SubprocessTransport )
69
+ debug_info = {'fd' : fd , 'exc' : exc , 'pid' : self ._transport .get_pid ()}
70
+ warn (f"pipe_connection_lost { debug_info } " )
71
+
67
72
if os .name == 'nt' and fd == 2 : # stderr
68
73
# On windows, ignore piped stderr being closed immediately (#505)
69
74
return
70
- self ._on_error (exc if exc else EOFError ())
75
+
76
+ # pipe_connection_lost() *may* be called before process_exited() is
77
+ # called, when a Nvim subprocess crashes (SIGABRT). Do not handle
78
+ # errors here, as errors will be handled somewhere else
79
+ # self._on_error(exc if exc else EOFError("pipe_connection_lost"))
71
80
72
81
@override
73
82
def pipe_data_received (self , fd , data ):
@@ -81,8 +90,13 @@ def pipe_data_received(self, fd, data):
81
90
@override
82
91
def process_exited (self ) -> None :
83
92
"""Used to signal `asyncio.SubprocessProtocol` when the child exits."""
84
- debug ("process_exited" )
85
- self ._on_error (EOFError ())
93
+ assert isinstance (self ._transport , asyncio .SubprocessTransport )
94
+ pid = self ._transport .get_pid ()
95
+ return_code = self ._transport .get_returncode ()
96
+
97
+ warn ("process_exited, pid = %s, return_code = %s" , pid , return_code )
98
+ err = EOFError (f"process_exited: pid = { pid } , return_code = { return_code } " )
99
+ self ._on_error (err )
86
100
87
101
88
102
class AsyncioEventLoop (BaseEventLoop ):
@@ -131,7 +145,8 @@ def _on_data(data: bytes) -> None:
131
145
def _connect_tcp (self , address : str , port : int ) -> None :
132
146
async def connect_tcp ():
133
147
transport , protocol = await self ._loop .create_connection (
134
- self ._protocol_factory , address , port )
148
+ self ._protocol_factory , address , port
149
+ )
135
150
debug (f"tcp connection successful: { address } :{ port } " )
136
151
self ._transport = transport
137
152
self ._protocol = protocol
@@ -146,8 +161,7 @@ async def connect_socket():
146
161
else :
147
162
_create_connection = self ._loop .create_unix_connection
148
163
149
- transport , protocol = await _create_connection (
150
- self ._protocol_factory , path )
164
+ transport , protocol = await _create_connection (self ._protocol_factory , path )
151
165
debug ("socket connection successful: %s" , self ._transport )
152
166
self ._transport = transport
153
167
self ._protocol = protocol
@@ -162,10 +176,12 @@ async def connect_stdin():
162
176
else :
163
177
pipe = sys .stdin
164
178
transport , protocol = await self ._loop .connect_read_pipe (
165
- self ._protocol_factory , pipe )
179
+ self ._protocol_factory , pipe
180
+ )
166
181
debug ("native stdin connection successful" )
167
182
self ._to_close .append (transport )
168
183
del protocol
184
+
169
185
self ._loop .run_until_complete (connect_stdin ())
170
186
171
187
# Make sure subprocesses don't clobber stdout,
@@ -177,26 +193,29 @@ async def connect_stdout():
177
193
if os .name == 'nt' :
178
194
pipe = PipeHandle (msvcrt .get_osfhandle (rename_stdout ))
179
195
else :
180
- pipe = os .fdopen (rename_stdout , 'wb' )
196
+ pipe = os .fdopen (rename_stdout , "wb" )
181
197
182
198
transport , protocol = await self ._loop .connect_write_pipe (
183
- self ._protocol_factory , pipe )
199
+ self ._protocol_factory , pipe
200
+ )
184
201
debug ("native stdout connection successful" )
185
202
self ._transport = transport
186
203
self ._protocol = protocol
204
+
187
205
self ._loop .run_until_complete (connect_stdout ())
188
206
189
207
@override
190
208
def _connect_child (self , argv : List [str ]) -> None :
191
- if os .name != 'nt' :
209
+ if os .name != "nt" :
192
210
# see #238, #241
193
211
self ._child_watcher = asyncio .get_child_watcher ()
194
212
self ._child_watcher .attach_loop (self ._loop )
195
213
196
214
async def create_subprocess ():
197
215
transport : asyncio .SubprocessTransport # type: ignore
198
216
transport , protocol = await self ._loop .subprocess_exec (
199
- self ._protocol_factory , * argv )
217
+ self ._protocol_factory , * argv
218
+ )
200
219
pid = transport .get_pid ()
201
220
debug ("child subprocess_exec successful, PID = %s" , pid )
202
221
@@ -250,11 +269,13 @@ def _close_transport(transport):
250
269
# Windows: for ProactorBasePipeTransport, close() doesn't take in
251
270
# effect immediately (closing happens asynchronously inside the
252
271
# event loop), need to wait a bit for completing graceful shutdown.
253
- if os .name == 'nt' and hasattr (transport , '_sock' ):
272
+ if os .name == 'nt' and hasattr (transport , "_sock" ):
273
+
254
274
async def wait_until_closed ():
255
275
# pylint: disable-next=protected-access
256
276
while transport ._sock is not None :
257
277
await asyncio .sleep (0.01 )
278
+
258
279
self ._loop .run_until_complete (wait_until_closed ())
259
280
260
281
if self ._transport :
0 commit comments