src/Pure/ML-Systems/multithreading_polyml.ML
changeset 41001 591b6778d076
parent 40553 bf39a257b3d3
child 42581 11ae688e4e30
equal deleted inserted replaced
41000:889b7545a408 41001:591b6778d076
     6 
     6 
     7 signature MULTITHREADING_POLYML =
     7 signature MULTITHREADING_POLYML =
     8 sig
     8 sig
     9   val interruptible: ('a -> 'b) -> 'a -> 'b
     9   val interruptible: ('a -> 'b) -> 'a -> 'b
    10   val uninterruptible: ((('c -> 'd) -> 'c -> 'd) -> 'a -> 'b) -> 'a -> 'b
    10   val uninterruptible: ((('c -> 'd) -> 'c -> 'd) -> 'a -> 'b) -> 'a -> 'b
    11   val bash_output: string -> string * int
       
    12   structure TimeLimit: TIME_LIMIT
    11   structure TimeLimit: TIME_LIMIT
    13 end;
    12 end;
    14 
    13 
    15 signature BASIC_MULTITHREADING =
    14 signature BASIC_MULTITHREADING =
    16 sig
    15 sig
    38     if m > 0 then m
    37     if m > 0 then m
    39     else Int.min (Int.max (Thread.numProcessors (), 1), 4)
    38     else Int.min (Int.max (Thread.numProcessors (), 1), 4)
    40   end;
    39   end;
    41 
    40 
    42 fun enabled () = max_threads_value () > 1;
    41 fun enabled () = max_threads_value () > 1;
    43 
       
    44 
       
    45 (* misc utils *)
       
    46 
       
    47 fun show "" = "" | show name = " " ^ name;
       
    48 fun show' "" = "" | show' name = " [" ^ name ^ "]";
       
    49 
       
    50 fun read_file name =
       
    51   let val is = TextIO.openIn name
       
    52   in Exn.release (Exn.capture TextIO.inputAll is before TextIO.closeIn is) end;
       
    53 
       
    54 fun write_file name txt =
       
    55   let val os = TextIO.openOut name
       
    56   in Exn.release (Exn.capture TextIO.output (os, txt) before TextIO.closeOut os) end;
       
    57 
    42 
    58 
    43 
    59 (* thread attributes *)
    44 (* thread attributes *)
    60 
    45 
    61 val no_interrupts =
    46 val no_interrupts =
   154   in if was_timeout then raise TimeOut else Exn.release result end) ();
   139   in if was_timeout then raise TimeOut else Exn.release result end) ();
   155 
   140 
   156 end;
   141 end;
   157 
   142 
   158 
   143 
   159 (* GNU bash processes, with propagation of interrupts *)
       
   160 
       
   161 fun bash_output script = with_attributes no_interrupts (fn orig_atts =>
       
   162   let
       
   163     val script_name = OS.FileSys.tmpName ();
       
   164     val _ = write_file script_name script;
       
   165 
       
   166     val pid_name = OS.FileSys.tmpName ();
       
   167     val output_name = OS.FileSys.tmpName ();
       
   168 
       
   169     (*result state*)
       
   170     datatype result = Wait | Signal | Result of int;
       
   171     val result = ref Wait;
       
   172     val lock = Mutex.mutex ();
       
   173     val cond = ConditionVar.conditionVar ();
       
   174     fun set_result res =
       
   175       (Mutex.lock lock; result := res; ConditionVar.signal cond; Mutex.unlock lock);
       
   176 
       
   177     val _ = Mutex.lock lock;
       
   178 
       
   179     (*system thread*)
       
   180     val system_thread = Thread.fork (fn () =>
       
   181       let
       
   182         val status =
       
   183           OS.Process.system ("exec \"$ISABELLE_HOME/lib/scripts/process\" group " ^ pid_name ^
       
   184             " script \"exec bash " ^ script_name ^ " > " ^ output_name ^ "\"");
       
   185         val res =
       
   186           (case Posix.Process.fromStatus status of
       
   187             Posix.Process.W_EXITED => Result 0
       
   188           | Posix.Process.W_EXITSTATUS 0wx82 => Signal
       
   189           | Posix.Process.W_EXITSTATUS w => Result (Word8.toInt w)
       
   190           | Posix.Process.W_SIGNALED s =>
       
   191               if s = Posix.Signal.int then Signal
       
   192               else Result (256 + LargeWord.toInt (Posix.Signal.toWord s))
       
   193           | Posix.Process.W_STOPPED s => Result (512 + LargeWord.toInt (Posix.Signal.toWord s)));
       
   194       in set_result res end handle _ (*sic*) => set_result (Result 2), []);
       
   195 
       
   196     (*main thread -- proxy for interrupts*)
       
   197     fun kill n =
       
   198       (case Int.fromString (read_file pid_name) of
       
   199         SOME pid =>
       
   200           Posix.Process.kill
       
   201             (Posix.Process.K_GROUP (Posix.Process.wordToPid (LargeWord.fromInt pid)),
       
   202               Posix.Signal.int)
       
   203       | NONE => ())
       
   204       handle OS.SysErr _ => () | IO.Io _ =>
       
   205         (OS.Process.sleep (seconds 0.1); if n > 0 then kill (n - 1) else ());
       
   206 
       
   207     val _ =
       
   208       while ! result = Wait do
       
   209         let val res =
       
   210           sync_wait (SOME orig_atts)
       
   211             (SOME (Time.+ (Time.now (), seconds 0.1))) cond lock
       
   212         in if Exn.is_interrupt_exn res then kill 10 else () end;
       
   213 
       
   214     (*cleanup*)
       
   215     val output = read_file output_name handle IO.Io _ => "";
       
   216     val _ = OS.FileSys.remove script_name handle OS.SysErr _ => ();
       
   217     val _ = OS.FileSys.remove pid_name handle OS.SysErr _ => ();
       
   218     val _ = OS.FileSys.remove output_name handle OS.SysErr _ => ();
       
   219     val _ = Thread.interrupt system_thread handle Thread _ => ();
       
   220     val rc = (case ! result of Signal => Exn.interrupt () | Result rc => rc);
       
   221   in (output, rc) end);
       
   222 
       
   223 
       
   224 (* critical section -- may be nested within the same thread *)
   144 (* critical section -- may be nested within the same thread *)
   225 
   145 
   226 local
   146 local
   227 
   147 
   228 val critical_lock = Mutex.mutex ();
   148 val critical_lock = Mutex.mutex ();
   229 val critical_thread = ref (NONE: Thread.thread option);
   149 val critical_thread = ref (NONE: Thread.thread option);
   230 val critical_name = ref "";
   150 val critical_name = ref "";
       
   151 
       
   152 fun show "" = "" | show name = " " ^ name;
       
   153 fun show' "" = "" | show' name = " [" ^ name ^ "]";
   231 
   154 
   232 in
   155 in
   233 
   156 
   234 fun self_critical () =
   157 fun self_critical () =
   235   (case ! critical_thread of
   158   (case ! critical_thread of