88import select
99import time
1010from pprint import pformat
11+ from queue import Empty , Queue
12+ from threading import Thread
1113from typing import Any , Dict , List , Optional , Tuple , Union
1214
1315from pygdbmi import gdbmiparser
1921)
2022
2123
22- if USING_WINDOWS :
23- import msvcrt
24- from ctypes import POINTER , WinError , byref , windll , wintypes # type: ignore
25- from ctypes .wintypes import BOOL , DWORD , HANDLE
26- else :
24+ if not USING_WINDOWS :
2725 import fcntl
2826
2927
@@ -67,9 +65,26 @@ def __init__(
6765 self ._allow_overwrite_timeout_times = (
6866 self .time_to_check_for_additional_output_sec > 0
6967 )
70- _make_non_blocking (self .stdout )
71- if self .stderr :
72- _make_non_blocking (self .stderr )
68+
69+ if USING_WINDOWS :
70+ self .queue_stdout = Queue () # type: Queue
71+ self .thread_stdout = Thread (
72+ target = _enqueue_output , args = (self .stdout , self .queue_stdout )
73+ )
74+ self .thread_stdout .daemon = True # thread dies with the program
75+ self .thread_stdout .start ()
76+
77+ if self .stderr :
78+ self .queue_stderr = Queue () # type: Queue
79+ self .thread_stderr = Thread (
80+ target = _enqueue_output , args = (self .stderr , self .queue_stderr )
81+ )
82+ self .thread_stderr .daemon = True # thread dies with the program
83+ self .thread_stderr .start ()
84+ else :
85+ fcntl .fcntl (self .stdout , fcntl .F_SETFL , os .O_NONBLOCK )
86+ if self .stderr :
87+ fcntl .fcntl (self .stderr , fcntl .F_SETFL , os .O_NONBLOCK )
7388
7489 def get_gdb_response (
7590 self , timeout_sec : float = DEFAULT_GDB_TIMEOUT_SEC , raise_error_on_timeout = True
@@ -109,22 +124,23 @@ def get_gdb_response(
109124
110125 def _get_responses_windows (self , timeout_sec ):
111126 """Get responses on windows. Assume no support for select and use a while loop."""
127+ assert USING_WINDOWS
128+
112129 timeout_time_sec = time .time () + timeout_sec
113130 responses = []
114131 while True :
115132 responses_list = []
133+
116134 try :
117- self .stdout .flush ()
118- raw_output = self .stdout .readline ().replace (b"\r " , b"\n " )
135+ raw_output = self .queue_stdout .get_nowait ()
119136 responses_list = self ._get_responses_list (raw_output , "stdout" )
120- except IOError :
137+ except Empty :
121138 pass
122139
123140 try :
124- self .stderr .flush ()
125- raw_output = self .stderr .readline ().replace (b"\r " , b"\n " )
141+ raw_output = self .queue_stderr .get_nowait ()
126142 responses_list += self ._get_responses_list (raw_output , "stderr" )
127- except IOError :
143+ except Empty :
128144 pass
129145
130146 responses += responses_list
@@ -137,11 +153,12 @@ def _get_responses_windows(self, timeout_sec):
137153 )
138154 elif time .time () > timeout_time_sec :
139155 break
140-
141156 return responses
142157
143158 def _get_responses_unix (self , timeout_sec ):
144159 """Get responses on unix-like system. Use select to wait for output."""
160+ assert not USING_WINDOWS
161+
145162 timeout_time_sec = time .time () + timeout_sec
146163 responses = []
147164 while True :
@@ -324,28 +341,7 @@ def _buffer_incomplete_responses(
324341 return (raw_output , buf )
325342
326343
327- def _make_non_blocking (file_obj : io .IOBase ):
328- """make file object non-blocking
329- Windows doesn't have the fcntl module, but someone on
330- stack overflow supplied this code as an answer, and it works
331- http://stackoverflow.com/a/34504971/2893090"""
332-
333- if USING_WINDOWS :
334- LPDWORD = POINTER (DWORD )
335- PIPE_NOWAIT = wintypes .DWORD (0x00000001 )
336-
337- SetNamedPipeHandleState = windll .kernel32 .SetNamedPipeHandleState
338- SetNamedPipeHandleState .argtypes = [HANDLE , LPDWORD , LPDWORD , LPDWORD ]
339- SetNamedPipeHandleState .restype = BOOL
340-
341- h = msvcrt .get_osfhandle (file_obj .fileno ()) # type: ignore
342-
343- res = windll .kernel32 .SetNamedPipeHandleState (h , byref (PIPE_NOWAIT ), None , None )
344- if res == 0 :
345- raise ValueError (WinError ())
346-
347- else :
348- # Set the file status flag (F_SETFL) on the pipes to be non-blocking
349- # so we can attempt to read from a pipe with no new data without locking
350- # the program up
351- fcntl .fcntl (file_obj , fcntl .F_SETFL , os .O_NONBLOCK )
344+ def _enqueue_output (out , queue ):
345+ for line in iter (out .readline , b"" ):
346+ queue .put (line .replace (b"\r " , b"\n " ))
347+ # Not necessary to close, it will be done in the main process.
0 commit comments