Don't "forget" earlier exceptions.
let lock = Mutex.create () and cond = Condition.create () in
(* If a job throws an exception it is saved here. *)
- let last_exn = ref None in
+ let last_exn = ref [] in
(* This is the background thread which runs each job. *)
let runner (job, f) =
Mutex.lock lock;
(match exn with
| None -> retire_job job
- | Some exn -> last_exn := Some exn
+ | Some exn -> last_exn := exn :: !last_exn
);
decr running;
Condition.signal cond;
in
let rec loop () =
- if !last_exn = None then (
+ if !last_exn = [] then (
match next_job () with
| Complete -> ()
| Not_ready ->
Condition.wait cond lock
done;
- let exn = !last_exn in
+ let exns = !last_exn in
Mutex.unlock lock;
- (* Re-raise the saved exception from the job which failed. *)
- match exn with
- | None -> ()
- | Some exn -> raise exn
+ (* Re-raise the saved exception(s) from the job(s) which failed. *)
+ match exns with
+ | [] -> ()
+ | [exn] -> raise exn
+ | exns ->
+ (* Combine the multiple exceptions into a single Failure exn. *)
+ let exns = List.rev exns in
+ let exn_to_string = function
+ | Failure s -> s
+ | exn -> Printexc.to_string exn in
+ let exns = List.map exn_to_string exns in
+ let exns = String.concat "\n" exns in
+ raise (Failure exns)
--- /dev/null
+# Goals test.
+# Copyright (C) 2020 Richard W.M. Jones
+# Copyright (C) 2020 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Multiple failures should all be reported in the error message.
+
+goal all = : fail ("1"), fail ("2"), fail ("3")
+
+goal fail (n) = {
+ sleep 1
+ echo FAIL %n
+ exit 1
+}
--- /dev/null
+#!/usr/bin/env bash
+# Goals test.
+# Copyright (C) 2020 Richard W.M. Jones
+# Copyright (C) 2020 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+set -e
+set -x
+
+goals -j 4 -f 20-multiple-failures.gl > 20-multiple-failures.out 2>&1 ||:
+fgrep 'fail ("1")' 20-multiple-failures.out
+fgrep 'fail ("2")' 20-multiple-failures.out
+fgrep 'fail ("3")' 20-multiple-failures.out
+rm 20-multiple-failures.out