val new_group : unit -> group
val start : group -> key -> (unit -> unit) -> unit
val wait : group -> unit
+ val stop_all : unit -> unit
end
module Make (K : Key) = struct
*)
let ready = ref 1
+ (* If stop_all is called, this is set to true and we stop
+ * running new jobs.
+ *)
+ let stop = ref false
+
(* The worker thread. *)
let rec worker _ =
let id = Thread.id (Thread.self ()) in
Mutex.lock lock;
incr ready;
- while !ready <= Cmdline.nr_jobs do
+ while not !stop && !ready <= Cmdline.nr_jobs do
(* See if there's any queue with a job which is ready to run. *)
Cmdline.debug "thread %d: checking for a runnable queue" id;
match get_runnable_queue () with
*)
and all_done group = List.for_all (fun { state } -> state = Done) !group
+ let stop_all () =
+ Mutex.lock lock;
+ (* All threads will exit after running jobs if this is set. *)
+ stop := true;
+ while !ready > 1 do
+ Condition.wait idle lock;
+ done;
+ Mutex.unlock lock
+
end
val wait : group -> unit
(** [wait group] waits for all of the jobs in the group to finish. *)
+
+ val stop_all : unit -> unit
+ (** This is used when goals exits with an error. All jobs which
+ are waiting to run are deleted, and we wait for all running
+ jobs to finish. *)
end
module Make (K : Key) : Jobs with type key = K.t
try main ()
with
Failure msg | Sys_error msg ->
- prerr_endline ("error: " ^ msg); exit 1
+ Run.stop_all ();
+ prerr_endline ("*** error: " ^ msg);
+ exit 1
end
)
+let stop_all = Jobs.stop_all
+
(* Starts the target expressions running and waits for them to complete. *)
let rec run_targets_to_completion env exprs =
let group = Jobs.new_group () in
parallel) until they are complete or we reach an error. The
expressions are either a list of dependencies and/or a list of
initial targets. *)
+
+val stop_all : unit -> unit
+(** Wait until all running jobs finish, and don't start any new ones.
+ See [Jobs.stop_all]. *)