8
8
import select
9
9
import time
10
10
from pprint import pformat
11
+ from queue import Empty , Queue
12
+ from threading import Thread
11
13
from typing import Any , Dict , List , Optional , Tuple , Union
12
14
13
15
from pygdbmi import gdbmiparser
19
21
)
20
22
21
23
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 :
27
25
import fcntl
28
26
29
27
@@ -67,9 +65,26 @@ def __init__(
67
65
self ._allow_overwrite_timeout_times = (
68
66
self .time_to_check_for_additional_output_sec > 0
69
67
)
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 )
73
88
74
89
def get_gdb_response (
75
90
self , timeout_sec : float = DEFAULT_GDB_TIMEOUT_SEC , raise_error_on_timeout = True
@@ -109,22 +124,23 @@ def get_gdb_response(
109
124
110
125
def _get_responses_windows (self , timeout_sec ):
111
126
"""Get responses on windows. Assume no support for select and use a while loop."""
127
+ assert USING_WINDOWS
128
+
112
129
timeout_time_sec = time .time () + timeout_sec
113
130
responses = []
114
131
while True :
115
132
responses_list = []
133
+
116
134
try :
117
- self .stdout .flush ()
118
- raw_output = self .stdout .readline ().replace (b"\r " , b"\n " )
135
+ raw_output = self .queue_stdout .get_nowait ()
119
136
responses_list = self ._get_responses_list (raw_output , "stdout" )
120
- except IOError :
137
+ except Empty :
121
138
pass
122
139
123
140
try :
124
- self .stderr .flush ()
125
- raw_output = self .stderr .readline ().replace (b"\r " , b"\n " )
141
+ raw_output = self .queue_stderr .get_nowait ()
126
142
responses_list += self ._get_responses_list (raw_output , "stderr" )
127
- except IOError :
143
+ except Empty :
128
144
pass
129
145
130
146
responses += responses_list
@@ -137,11 +153,12 @@ def _get_responses_windows(self, timeout_sec):
137
153
)
138
154
elif time .time () > timeout_time_sec :
139
155
break
140
-
141
156
return responses
142
157
143
158
def _get_responses_unix (self , timeout_sec ):
144
159
"""Get responses on unix-like system. Use select to wait for output."""
160
+ assert not USING_WINDOWS
161
+
145
162
timeout_time_sec = time .time () + timeout_sec
146
163
responses = []
147
164
while True :
@@ -324,28 +341,7 @@ def _buffer_incomplete_responses(
324
341
return (raw_output , buf )
325
342
326
343
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