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 |