3636IGNORE_WIDGETS = ["LaunchWindow" ]
3737PROCESS_TERMINATION_TIMEOUT = 10
3838PROCESS_OUTPUT_THREAD_JOIN_TIMEOUT = 2
39+ PROCESS_OUTPUT_SELECT_TIMEOUT = 0.2
3940GRACEFUL_SERVER_SHUTDOWN_TIMEOUT = 5
41+ OUTPUT_READER_STOP_EVENT_ATTR = "_bec_output_reader_stop_event"
4042
4143RegistryState : TypeAlias = dict [
4244 Literal ["gui_id" , "name" , "widget_class" , "config" , "__rpc__" , "container_proxy" ],
@@ -57,14 +59,16 @@ def _filter_output(output: str) -> str:
5759 return output
5860
5961
60- def _get_output (process , logger ) -> None :
62+ def _get_output (process , logger , stop_event : threading . Event | None = None ) -> None :
6163 log_func = {process .stdout : logger .debug , process .stderr : logger .info }
6264 stream_buffer = {process .stdout : [], process .stderr : []}
6365 try :
6466 os .set_blocking (process .stdout .fileno (), False )
6567 os .set_blocking (process .stderr .fileno (), False )
66- while process .poll () is None :
67- readylist , _ , _ = select .select ([process .stdout , process .stderr ], [], [], 1 )
68+ while process .poll () is None and not (stop_event and stop_event .is_set ()):
69+ readylist , _ , _ = select .select (
70+ [process .stdout , process .stderr ], [], [], PROCESS_OUTPUT_SELECT_TIMEOUT
71+ )
6872 for stream in (process .stdout , process .stderr ):
6973 buf = stream_buffer [stream ]
7074 if stream in readylist :
@@ -180,14 +184,16 @@ def _join_process_output_thread(process, thread: threading.Thread | None, logger
180184 if not thread .is_alive ():
181185 return
182186
187+ if stop_event := getattr (thread , OUTPUT_READER_STOP_EVENT_ATTR , None ):
188+ stop_event .set ()
189+
183190 for stream in (process .stdout , process .stderr ):
184191 if stream is None :
185192 continue
186193 try :
187194 stream .close ()
188195 except OSError as e :
189196 logger .error (f"Failed to close stream { str (e )} " )
190- pass
191197 thread .join (timeout = PROCESS_OUTPUT_THREAD_JOIN_TIMEOUT )
192198 if thread .is_alive ():
193199 logger .warning (
@@ -247,8 +253,14 @@ def _start_plot_process(
247253 if logger is None :
248254 process_output_processing_thread = None
249255 else :
256+ process_output_stop_event = threading .Event ()
250257 process_output_processing_thread = threading .Thread (
251- target = _get_output , args = (process , logger )
258+ target = _get_output , args = (process , logger , process_output_stop_event )
259+ )
260+ setattr (
261+ process_output_processing_thread ,
262+ OUTPUT_READER_STOP_EVENT_ATTR ,
263+ process_output_stop_event ,
252264 )
253265 process_output_processing_thread .start ()
254266 return process , process_output_processing_thread
0 commit comments