17
17
GdbTimeoutError ,
18
18
)
19
19
20
- if USING_WINDOWS :
21
- import msvcrt
22
- from ctypes import windll , byref , wintypes , WinError , POINTER # type: ignore
23
- from ctypes .wintypes import HANDLE , DWORD , BOOL
24
- else :
20
+ from threading import Thread
21
+ from queue import Queue , Empty
22
+
23
+ if not USING_WINDOWS :
25
24
import fcntl
26
25
27
26
28
- __all__ = [
29
- "IoManager" ,
30
- "make_non_blocking" ,
31
- ]
27
+ __all__ = ["IoManager" ]
32
28
33
29
34
30
logger = logging .getLogger (__name__ )
@@ -68,9 +64,26 @@ def __init__(
68
64
self ._allow_overwrite_timeout_times = (
69
65
self .time_to_check_for_additional_output_sec > 0
70
66
)
71
- make_non_blocking (self .stdout )
72
- if self .stderr :
73
- make_non_blocking (self .stderr )
67
+
68
+ if USING_WINDOWS :
69
+ self .queue_stdout = Queue () # type: Queue
70
+ self .thread_stdout = Thread (
71
+ target = _enqueue_output , args = (self .stdout , self .queue_stdout )
72
+ )
73
+ self .thread_stdout .daemon = True # thread dies with the program
74
+ self .thread_stdout .start ()
75
+
76
+ if self .stderr :
77
+ self .queue_stderr = Queue () # type: Queue
78
+ self .thread_stderr = Thread (
79
+ target = _enqueue_output , args = (self .stderr , self .queue_stderr )
80
+ )
81
+ self .thread_stderr .daemon = True # thread dies with the program
82
+ self .thread_stderr .start ()
83
+ else :
84
+ fcntl .fcntl (self .stdout , fcntl .F_SETFL , os .O_NONBLOCK )
85
+ if self .stderr :
86
+ fcntl .fcntl (self .stderr , fcntl .F_SETFL , os .O_NONBLOCK )
74
87
75
88
def get_gdb_response (
76
89
self , timeout_sec : float = DEFAULT_GDB_TIMEOUT_SEC , raise_error_on_timeout = True
@@ -110,22 +123,23 @@ def get_gdb_response(
110
123
111
124
def _get_responses_windows (self , timeout_sec ):
112
125
"""Get responses on windows. Assume no support for select and use a while loop."""
126
+ assert USING_WINDOWS
127
+
113
128
timeout_time_sec = time .time () + timeout_sec
114
129
responses = []
115
130
while True :
116
131
responses_list = []
132
+
117
133
try :
118
- self .stdout .flush ()
119
- raw_output = self .stdout .readline ().replace (b"\r " , b"\n " )
134
+ raw_output = self .queue_stdout .get_nowait ()
120
135
responses_list = self ._get_responses_list (raw_output , "stdout" )
121
- except IOError :
136
+ except Empty :
122
137
pass
123
138
124
139
try :
125
- self .stderr .flush ()
126
- raw_output = self .stderr .readline ().replace (b"\r " , b"\n " )
140
+ raw_output = self .queue_stderr .get_nowait ()
127
141
responses_list += self ._get_responses_list (raw_output , "stderr" )
128
- except IOError :
142
+ except Empty :
129
143
pass
130
144
131
145
responses += responses_list
@@ -138,11 +152,12 @@ def _get_responses_windows(self, timeout_sec):
138
152
)
139
153
elif time .time () > timeout_time_sec :
140
154
break
141
-
142
155
return responses
143
156
144
157
def _get_responses_unix (self , timeout_sec ):
145
158
"""Get responses on unix-like system. Use select to wait for output."""
159
+ assert not USING_WINDOWS
160
+
146
161
timeout_time_sec = time .time () + timeout_sec
147
162
responses = []
148
163
while True :
@@ -325,28 +340,7 @@ def _buffer_incomplete_responses(
325
340
return (raw_output , buf )
326
341
327
342
328
- def make_non_blocking (file_obj : io .IOBase ):
329
- """make file object non-blocking
330
- Windows doesn't have the fcntl module, but someone on
331
- stack overflow supplied this code as an answer, and it works
332
- http://stackoverflow.com/a/34504971/2893090"""
333
-
334
- if USING_WINDOWS :
335
- LPDWORD = POINTER (DWORD )
336
- PIPE_NOWAIT = wintypes .DWORD (0x00000001 )
337
-
338
- SetNamedPipeHandleState = windll .kernel32 .SetNamedPipeHandleState
339
- SetNamedPipeHandleState .argtypes = [HANDLE , LPDWORD , LPDWORD , LPDWORD ]
340
- SetNamedPipeHandleState .restype = BOOL
341
-
342
- h = msvcrt .get_osfhandle (file_obj .fileno ()) # type: ignore
343
-
344
- res = windll .kernel32 .SetNamedPipeHandleState (h , byref (PIPE_NOWAIT ), None , None )
345
- if res == 0 :
346
- raise ValueError (WinError ())
347
-
348
- else :
349
- # Set the file status flag (F_SETFL) on the pipes to be non-blocking
350
- # so we can attempt to read from a pipe with no new data without locking
351
- # the program up
352
- fcntl .fcntl (file_obj , fcntl .F_SETFL , os .O_NONBLOCK )
343
+ def _enqueue_output (out , queue ):
344
+ for line in iter (out .readline , b"" ):
345
+ queue .put (line .replace (b"\r " , b"\n " ))
346
+ # Not necessary to close, it will be done in the main process.
0 commit comments