44import inspect
55import itertools
66import json
7- from multiprocessing import Pool , set_start_method
7+ from multiprocessing import Pool , set_start_method , Lock
88import os
99import resource
1010import shutil
7777 34 : 'skipped' ,
7878 35 : 'suspicious' ,
7979 36 : 'timeout' ,
80+ - 24 : 'timeout' , # SIGXCPU
8081 24 : 'timeout' , # SIGXCPU
8182 152 : 'timeout' , # SIGXCPU
8283 255 : 'timeout' ,
@@ -282,15 +283,17 @@ def load(self):
282283
283284 def register_pid (self , * , pid , key , estimated_time_of_tests ):
284285 self .key_by_pid [pid ] = key
285- self .start_time_by_pid [pid ] = datetime .now ()
286+ with START_TIMES_BY_PID_LOCK :
287+ self .start_time_by_pid [pid ] = datetime .now ()
286288 self .estimated_time_of_tests_by_pid [pid ] = estimated_time_of_tests
287289
288290 def register_result (self , * , pid , exit_code ):
289291 assert self .key_by_pid [pid ] in self .exit_code_by_key
290292 self .exit_code_by_key [self .key_by_pid [pid ]] = exit_code
291293 # TODO: maybe rate limit this? Saving on each result can slow down mutation testing a lot if the test run is fast.
292294 del self .key_by_pid [pid ]
293- del self .start_time_by_pid [pid ]
295+ with START_TIMES_BY_PID_LOCK :
296+ del self .start_time_by_pid [pid ]
294297 self .save ()
295298
296299 def stop_children (self ):
@@ -860,6 +863,9 @@ def stop_all_children(mutants):
860863 for m , _ , _ in mutants :
861864 m .stop_children ()
862865
866+ # used to copy the global mutmut.config to subprocesses
867+ set_start_method ('fork' )
868+ START_TIMES_BY_PID_LOCK = Lock ()
863869
864870def timeout_checker (mutants ):
865871 def inner_timout_checker ():
@@ -868,7 +874,10 @@ def inner_timout_checker():
868874
869875 now = datetime .now ()
870876 for m , mutant_name , result in mutants :
871- for pid , start_time in m .start_time_by_pid .items ():
877+ # copy dict inside lock, so it is not modified by another process while we iterate it
878+ with START_TIMES_BY_PID_LOCK :
879+ start_times_by_pid = dict (m .start_time_by_pid )
880+ for pid , start_time in start_times_by_pid .items ():
872881 run_time = now - start_time
873882 if run_time .total_seconds () > (m .estimated_time_of_tests_by_mutant [mutant_name ] + 1 ) * 4 :
874883 try :
@@ -882,9 +891,6 @@ def inner_timout_checker():
882891@click .option ('--max-children' , type = int )
883892@click .argument ('mutant_names' , required = False , nargs = - 1 )
884893def run (mutant_names , * , max_children ):
885- # used to copy the global mutmut.config to subprocesses
886- set_start_method ('fork' )
887-
888894 assert isinstance (mutant_names , (tuple , list )), mutant_names
889895 _run (mutant_names , max_children )
890896
0 commit comments