2015-12-19 02:35:13 +01:00
|
|
|
open Core.Std;;
|
|
|
|
|
|
|
|
let _list = ref [] ;;
|
|
|
|
let _running = ref false;;
|
|
|
|
let _threads = ref [] ;;
|
|
|
|
|
|
|
|
(** Kill the current process and all children *)
|
|
|
|
let kill () =
|
|
|
|
let kill pid =
|
2015-12-29 03:31:08 +01:00
|
|
|
Signal.send_i Signal.int (`Pid pid);
|
|
|
|
Printf.printf "Killed %d\n" (Pid.to_int pid)
|
2015-12-19 02:35:13 +01:00
|
|
|
in
|
|
|
|
List.iter ~f:kill (!_list);
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
|
|
(** Start watchdog *)
|
|
|
|
let start () =
|
|
|
|
|
|
|
|
if (!_running) then
|
|
|
|
failwith "Watchdog error: Already running"
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
_running := true;
|
|
|
|
|
|
|
|
let pause () =
|
|
|
|
Time.Span.of_sec 1.
|
|
|
|
|> Time.pause
|
|
|
|
in
|
|
|
|
|
|
|
|
let pid_is_running pid =
|
|
|
|
match (Sys.file_exists ("/proc/"^(Pid.to_string pid)^"/stat")) with
|
|
|
|
| `No | `Unknown -> false
|
|
|
|
| `Yes -> true
|
|
|
|
in
|
|
|
|
|
|
|
|
let f () =
|
|
|
|
while (!_running)
|
|
|
|
do
|
|
|
|
pause () ;
|
|
|
|
|
|
|
|
(*DEBUG
|
|
|
|
List.iter (!_list) ~f:(fun x -> Printf.printf "%d\n%!" (Pid.to_int x));
|
|
|
|
*)
|
|
|
|
|
|
|
|
let continue () =
|
|
|
|
List.fold_left (!_list) ~init:true ~f:(
|
|
|
|
fun accu x -> accu && (pid_is_running x)
|
|
|
|
)
|
|
|
|
in
|
|
|
|
if ( not (continue ()) ) then
|
|
|
|
kill ()
|
|
|
|
done
|
|
|
|
in
|
|
|
|
_threads := ( (Thread.create f) () ) :: (!_threads)
|
|
|
|
end
|
|
|
|
;;
|
|
|
|
|
|
|
|
(** Stop watchdog *)
|
|
|
|
let stop () =
|
|
|
|
if (!_running) then
|
|
|
|
_running := false
|
|
|
|
else
|
|
|
|
failwith "Watchdog error: Already stopped"
|
|
|
|
;;
|
|
|
|
|
|
|
|
(** Add a PID to tracking *)
|
|
|
|
let add pid =
|
|
|
|
if (not !_running) then
|
|
|
|
start ();
|
|
|
|
_list := pid :: (!_list)
|
|
|
|
;;
|
|
|
|
|
|
|
|
(** Remove a PID from tracking *)
|
|
|
|
let del pid =
|
|
|
|
let rec aux accu = function
|
|
|
|
| [] -> accu
|
|
|
|
| a :: rest ->
|
|
|
|
if (a <> pid) then
|
|
|
|
aux (a::accu) rest
|
|
|
|
else
|
|
|
|
aux accu rest
|
|
|
|
in
|
|
|
|
_list := aux [] (!_list);
|
|
|
|
|
|
|
|
match (!_list) with
|
|
|
|
| [] -> if (!_running) then stop ()
|
|
|
|
| _ -> ()
|
|
|
|
;;
|
|
|
|
|
|
|
|
(** Fork and exec a new process *)
|
|
|
|
let fork_exec ~prog ~args () =
|
|
|
|
let pid =
|
|
|
|
Unix.fork_exec ~prog ~args ()
|
|
|
|
in
|
|
|
|
|
|
|
|
let f () =
|
|
|
|
add pid;
|
|
|
|
let success =
|
|
|
|
match (Unix.waitpid pid) with
|
|
|
|
| Core_kernel.Std.Result.Ok () -> true
|
|
|
|
| Core_kernel.Std.Result.Error (`Exit_non_zero n) ->
|
|
|
|
( Printf.printf "PID %d exited with code %d\n%!"
|
|
|
|
(Pid.to_int pid) n ;
|
|
|
|
false )
|
|
|
|
| Core_kernel.Std.Result.Error (`Signal n) ->
|
|
|
|
( Printf.printf "PID %d killed with signal %d (%s)\n%!"
|
|
|
|
(Pid.to_int pid) (Signal.to_system_int n)
|
|
|
|
(Signal.to_string n) ;
|
|
|
|
false )
|
|
|
|
in
|
|
|
|
del pid ;
|
|
|
|
if (not success) then
|
|
|
|
kill ()
|
|
|
|
in
|
|
|
|
_threads := ( (Thread.create f) () ) :: (!_threads);
|
|
|
|
pid
|
|
|
|
;;
|
|
|
|
|
|
|
|
(** Wait for threads to finish *)
|
|
|
|
let join () =
|
|
|
|
(* if (!_running) then stop (); *)
|
|
|
|
List.iter ~f:Thread.join (!_threads);
|
|
|
|
assert (not !_running)
|
|
|
|
;;
|