src/Pure/Concurrent/par_exn.ML
author wenzelm
Thu, 18 Aug 2011 15:15:43 +0200
changeset 45147 c21ecbb028b6
parent 45127 64620f1d6f87
child 45149 d9c7bf932eab
permissions -rw-r--r--
tune Par_Exn.make: balance merge;
clarified Par_Exn.dest: later exceptions first;
     1 (*  Title:      Pure/Concurrent/par_exn.ML
     2     Author:     Makarius
     3 
     4 Parallel exceptions as flattened results from acyclic graph of
     5 evaluations.  Interrupt counts as neutral element.
     6 *)
     7 
     8 signature PAR_EXN =
     9 sig
    10   val serial: exn -> serial * exn
    11   val make: exn list -> exn
    12   val dest: exn -> exn list option
    13   val release_all: 'a Exn.result list -> 'a list
    14   val release_first: 'a Exn.result list -> 'a list
    15 end;
    16 
    17 structure Par_Exn =
    18 struct
    19 
    20 (* identification via serial numbers *)
    21 
    22 fun serial exn =
    23   (case get_exn_serial exn of
    24     SOME i => (i, exn)
    25   | NONE => let val i = Library.serial () in (i, set_exn_serial i exn) end);
    26 
    27 val exn_ord = rev_order o int_ord o pairself (the o get_exn_serial);
    28 
    29 
    30 (* parallel exceptions *)
    31 
    32 exception Par_Exn of exn list;
    33   (*non-empty list with unique identified elements sorted by exn_ord;
    34     no occurrences of Par_Exn or Exn.Interrupt*)
    35 
    36 fun par_exns (Par_Exn exns) = exns
    37   | par_exns exn = if Exn.is_interrupt exn then [] else [#2 (serial exn)];
    38 
    39 fun make exns =
    40   (case Balanced_Tree.make (Ord_List.merge exn_ord) ([] :: map par_exns exns) of
    41     [] => Exn.Interrupt
    42   | es => Par_Exn es);
    43 
    44 fun dest (Par_Exn exns) = SOME exns
    45   | dest _ = NONE;
    46 
    47 
    48 (* parallel results *)
    49 
    50 fun all_res results = forall (fn Exn.Res _ => true | _ => false) results;
    51 
    52 fun release_all results =
    53   if all_res results then map Exn.release results
    54   else raise make (map_filter Exn.get_exn results);
    55 
    56 fun release_first results =
    57   if all_res results then map Exn.release results
    58   else
    59     (case get_first
    60         (fn res => if Exn.is_interrupt_exn res then NONE else Exn.get_exn res) results of
    61       NONE => Exn.interrupt ()
    62     | SOME exn => reraise exn);
    63 
    64 end;
    65