[m-rev.] diff: improve interrupting parallel mmc --make

Peter Wang novalazy at gmail.com
Fri Jul 31 11:28:01 AEST 2009


Branches: main

Make interrupting parallel `mmc --make' more robust.

compiler/make.util.m:
        When the parent process receives a signal, send SIGINT to child
        processes.

        When any process receives a signal, set the abort flag in the job
        control structure.  All the processes will then see the abort flag the
        next time they look for a task to work on.

compiler/process_util.m:
        Add a predicate to send a signal.

diff --git a/compiler/make.util.m b/compiler/make.util.m
index 05532e0..c36abcf 100644
--- a/compiler/make.util.m
+++ b/compiler/make.util.m
@@ -436,13 +436,14 @@ foldl2_maybe_stop_at_error_parallel_processes(KeepGoing, Jobs, MakeTarget,
     create_job_ctl(TotalTasks, MaybeJobCtl, !IO),
     (
         MaybeJobCtl = yes(JobCtl),
-        list.map_foldl(
+        list.foldl2(
             start_worker_process(KeepGoing, MakeTarget, Targets, JobCtl,
                 !.Info),
-            2 .. Jobs, MaybePids, !IO),
-        worker_loop(KeepGoing, MakeTarget, Targets, JobCtl, yes, Success0,
-            !Info, !IO),
-        list.foldl2(reap_worker_process, MaybePids, Success0, Success, !IO),
+            2 .. Jobs, [], Pids, !IO),
+        build_with_check_for_interrupt(
+            worker_loop(KeepGoing, MakeTarget, Targets, JobCtl, yes),
+            worker_loop_signal_cleanup(JobCtl, Pids), Success0, !Info, !IO),
+        list.foldl2(reap_worker_process, Pids, Success0, Success, !IO),
         destroy_job_ctl(JobCtl, !IO)
     ;
         MaybeJobCtl = no,
@@ -451,22 +452,29 @@ foldl2_maybe_stop_at_error_parallel_processes(KeepGoing, Jobs, MakeTarget,
 
 :- pred start_worker_process(bool::in,
     foldl2_pred_with_status(T, Info, io)::in(foldl2_pred_with_status),
-    list(T)::in, job_ctl::in, Info::in, int::in, maybe(pid)::out,
+    list(T)::in, job_ctl::in, Info::in, int::in, list(pid)::in, list(pid)::out,
     io::di, io::uo) is det.
 
 start_worker_process(KeepGoing, MakeTarget, Targets, JobCtl, Info, _ChildN,
-        MaybePid, !IO) :-
+        !Pids, !IO) :-
     start_in_forked_process(
         child_worker(KeepGoing, MakeTarget, Targets, JobCtl, Info),
-        MaybePid, !IO).
+        MaybePid, !IO),
+    (
+        MaybePid = yes(Pid),
+        !:Pids = [Pid | !.Pids]
+    ;
+        MaybePid = no
+    ).
 
 :- pred child_worker(bool::in,
     foldl2_pred_with_status(T, Info, io)::in(foldl2_pred_with_status),
     list(T)::in, job_ctl::in, Info::in, bool::out, io::di, io::uo) is det.
 
 child_worker(KeepGoing, MakeTarget, Targets, JobCtl, Info0, Success, !IO) :-
-    worker_loop(KeepGoing, MakeTarget, Targets, JobCtl, yes, Success,
-        Info0, _Info, !IO).
+    build_with_check_for_interrupt(
+        worker_loop(KeepGoing, MakeTarget, Targets, JobCtl, yes),
+        worker_loop_signal_cleanup(JobCtl, []), Success, Info0, _Info, !IO).
 
 :- pred worker_loop(bool::in,
     foldl2_pred_with_status(T, Info, io)::in(foldl2_pred_with_status),
@@ -493,23 +501,25 @@ worker_loop(KeepGoing, MakeTarget, Targets, JobCtl, !Success, !Info, !IO) :-
         true
     ).
 
-:- pred reap_worker_process(maybe(pid)::in, bool::in, bool::out,
+:- pred worker_loop_signal_cleanup(job_ctl::in, list(pid)::in,
+    Info::in, Info::out, io::di, io::uo) is det.
+
+worker_loop_signal_cleanup(JobCtl, Pids, !Info, !IO) :-
+    mark_abort(JobCtl, !IO),
+    list.foldl(send_signal(sigint), Pids, !IO).
+
+:- pred reap_worker_process(pid::in, bool::in, bool::out,
     io::di, io::uo) is det.
 
-reap_worker_process(MaybePid, !Success, !IO) :-
+reap_worker_process(Pid, !Success, !IO) :-
+    wait_pid(Pid, Status, !IO),
     (
-        MaybePid = yes(Pid),
-        wait_pid(Pid, Status, !IO),
-        (
-            !.Success = yes,
-            Status = ok(exited(0))
-        ->
-            true
-        ;
-            !:Success = no
-        )
+        !.Success = yes,
+        Status = ok(exited(0))
+    ->
+        true
     ;
-        MaybePid = no
+        !:Success = no
     ).
 
 %-----------------------------------------------------------------------------%
@@ -824,6 +834,21 @@ have_job_ctl_ipc :-
     IO = IO0;
 ").
 
+:- pred mark_abort(job_ctl::in, io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    mark_abort(JobCtl::in, IO0::di, IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io,
+        may_not_duplicate],
+"
+#ifdef MC_HAVE_JOBCTL_IPC
+    MC_lock_job_ctl(JobCtl);
+    JobCtl->jc_abort = MR_TRUE;
+    MC_unlock_job_ctl(JobCtl);
+#endif
+    IO = IO0;
+").
+
 :- func make_yes_job_ctl(job_ctl) = maybe(job_ctl).
 :- pragma foreign_export("C", make_yes_job_ctl(in) = out,
     "MC_make_yes_job_ctl").
diff --git a/compiler/process_util.m b/compiler/process_util.m
index c6e88b0..5fd42c8 100644
--- a/compiler/process_util.m
+++ b/compiler/process_util.m
@@ -51,6 +51,13 @@
     %
 :- pred raise_signal(int::in, io::di, io::uo) is det.
 
+    % send_signal(Signal, Pid).
+    % Send `Signal' to `Pid'.
+    %
+:- pred send_signal(int::in, pid::in, io::di, io::uo) is det.
+
+:- func sigint = int.
+
 %-----------------------------------------------------------------------------%
 
 :- type io_pred == pred(bool, io, io).
@@ -299,6 +306,21 @@ raise_signal(_::in, IO::di, IO::uo).
     raise(Signal);
 ").
 
+:- pragma foreign_proc("C",
+    send_signal(Pid::in, Signal::in, IO0::di, IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io],
+"
+    IO = IO0;
+    kill(Pid, Signal);
+").
+
+:- pragma foreign_proc("C",
+    sigint = (Sigint::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    Sigint = SIGINT;
+").
+
 %-----------------------------------------------------------------------------%
 
 call_in_forked_process(P, Success, !IO) :-

--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list