@@ -564,14 +564,52 @@ def _execute_args_sync(
564
564
565
565
return ArgumentsExecutionResult .from_process_result (result )
566
566
567
+ @staticmethod
568
+ def _wait_for_async_termination (
569
+ poller : select .poll ,
570
+ process : subprocess .Popen [bytes ],
571
+ process_fd : int ,
572
+ event_socket_fd : int ,
573
+ timeout : Optional [float ],
574
+ ):
575
+ start_time = time .time ()
576
+
577
+ while True :
578
+ now_time = time .time ()
579
+
580
+ if timeout is not None and now_time - start_time >= timeout :
581
+ raise TimeoutError (f"Compiler timed out. (Timeout: { timeout } s)." )
582
+
583
+ events = poller .poll (1 )
584
+ for fd , event in events :
585
+ if fd == event_socket_fd :
586
+ logger .info ("Terminating compilation process as socket got closed by remote. (event: %i)" , event )
587
+
588
+ process .terminate ()
589
+ # we need to wait for the process to terminate, so that the handle is correctly closed
590
+ process .wait ()
591
+
592
+ raise ClientDisconnectedError
593
+ elif fd == process_fd :
594
+ logger .debug ("Process has finished (process_fd has event): %i" , event )
595
+
596
+ stdout_bytes , stderr_bytes = process .communicate ()
597
+ stdout = stdout_bytes .decode (ENCODING )
598
+ stderr = stderr_bytes .decode (ENCODING )
599
+
600
+ return ArgumentsExecutionResult (process .returncode , stdout , stderr )
601
+ else :
602
+ logger .warning (
603
+ "Got poll() event for fd '%i', which does neither match the socket nor the process." , fd
604
+ )
605
+
567
606
@staticmethod
568
607
def _execute_async (
569
608
args : List [str ],
570
609
event_socket_fd : int ,
571
610
cwd : Path ,
572
611
timeout : Optional [float ],
573
612
) -> ArgumentsExecutionResult :
574
- start_time = time .time ()
575
613
with subprocess .Popen (args , cwd = cwd , stdout = subprocess .PIPE , stderr = subprocess .PIPE ) as process :
576
614
poller = select .poll ()
577
615
# socket is readable when TCP FIN is sended, so also check if we can read (POLLIN).
@@ -582,36 +620,10 @@ def _execute_async(
582
620
process_fd = os .pidfd_open (process .pid )
583
621
poller .register (process_fd , select .POLLRDHUP | select .POLLIN )
584
622
585
- while True :
586
- now_time = time .time ()
587
-
588
- if timeout is not None and now_time - start_time >= timeout :
589
- raise TimeoutError (f"Compiler timed out. (Timeout: { timeout } s)." )
590
-
591
- events = poller .poll (1 )
592
- for fd , event in events :
593
- if fd == event_socket_fd :
594
- logger .info (
595
- "Terminating compilation process as socket got closed by remote. (event: %i)" , event
596
- )
597
-
598
- process .terminate ()
599
- # we need to wait for the process to terminate, so that the handle is correctly closed
600
- process .wait ()
601
-
602
- raise ClientDisconnectedError
603
- elif fd == process_fd :
604
- logger .debug ("Process has finished (process_fd has event): %i" , event )
605
-
606
- stdout_bytes , stderr_bytes = process .communicate ()
607
- stdout = stdout_bytes .decode (ENCODING )
608
- stderr = stderr_bytes .decode (ENCODING )
609
-
610
- return ArgumentsExecutionResult (process .returncode , stdout , stderr )
611
- else :
612
- logger .warning (
613
- "Got poll() event for fd '%i', which does neither match the socket nor the process." , fd
614
- )
623
+ try :
624
+ return Arguments ._wait_for_async_termination (poller , process , process_fd , event_socket_fd , timeout )
625
+ finally :
626
+ os .close (process_fd )
615
627
616
628
def execute (self , ** kwargs ) -> ArgumentsExecutionResult :
617
629
"""
0 commit comments