summaryrefslogtreecommitdiff
path: root/lib/system.ml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system.ml')
-rw-r--r--lib/system.ml378
1 files changed, 140 insertions, 238 deletions
diff --git a/lib/system.ml b/lib/system.ml
index 8f436366..73095f9c 100644
--- a/lib/system.ml
+++ b/lib/system.ml
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2014 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2015 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -9,126 +9,10 @@
(* $Id$ *)
open Pp
+open Errors
open Util
open Unix
-(* Expanding shell variables and home-directories *)
-
-let safe_getenv_def var def =
- try
- Sys.getenv var
- with Not_found ->
- warning ("Environment variable "^var^" not found: using '"^def^"' .");
- flush_all ();
- def
-
-let getenv_else s dft = try Sys.getenv s with Not_found -> dft
-
-(* On win32, the home directory is probably not in $HOME, but in
- some other environment variable *)
-
-let home =
- try Sys.getenv "HOME" with Not_found ->
- try (Sys.getenv "HOMEDRIVE")^(Sys.getenv "HOMEPATH") with Not_found ->
- try Sys.getenv "USERPROFILE" with Not_found ->
- warning ("Cannot determine user home directory, using '.' .");
- flush_all ();
- Filename.current_dir_name
-
-let safe_getenv n = safe_getenv_def n ("$"^n)
-
-let rec expand_atom s i =
- let l = String.length s in
- if i<l && (is_digit s.[i] or is_letter s.[i] or s.[i] = '_')
- then expand_atom s (i+1)
- else i
-
-let rec expand_macros s i =
- let l = String.length s in
- if i=l then s else
- match s.[i] with
- | '$' ->
- let n = expand_atom s (i+1) in
- let v = safe_getenv (String.sub s (i+1) (n-i-1)) in
- let s = (String.sub s 0 i)^v^(String.sub s n (l-n)) in
- expand_macros s (i + String.length v)
- | '~' when i = 0 ->
- let n = expand_atom s (i+1) in
- let v =
- if n=i+1 then home
- else (getpwnam (String.sub s (i+1) (n-i-1))).pw_dir
- in
- let s = v^(String.sub s n (l-n)) in
- expand_macros s (String.length v)
- | c -> expand_macros s (i+1)
-
-let expand_path_macros s = expand_macros s 0
-
-(* Files and load path. *)
-
-type physical_path = string
-type load_path = physical_path list
-
-let physical_path_of_string s = s
-let string_of_physical_path p = p
-
-(*
- * Split a path into a list of directories. A one-liner with Str, but Coq
- * doesn't seem to use this library at all, so here is a slighly longer version.
- *)
-
-let lpath_from_path path path_separator =
- let n = String.length path in
- let rec aux i l =
- if i < n then
- let j =
- try String.index_from path i path_separator
- with Not_found -> n
- in
- let dir = String.sub path i (j-i) in
- aux (j+1) (dir::l)
- else
- l
- in List.rev (aux 0 [])
-
-(* Hints to partially detects if two paths refer to the same repertory *)
-let rec remove_path_dot p =
- let curdir = Filename.concat Filename.current_dir_name "" in (* Unix: "./" *)
- let n = String.length curdir in
- let l = String.length p in
- if l > n && String.sub p 0 n = curdir then
- let n' =
- let sl = String.length Filename.dir_sep in
- let i = ref n in
- while !i <= l - sl && String.sub p !i sl = Filename.dir_sep do i := !i + sl done; !i in
- remove_path_dot (String.sub p n' (l - n'))
- else
- p
-
-let strip_path p =
- let cwd = Filename.concat (Sys.getcwd ()) "" in (* Unix: "`pwd`/" *)
- let n = String.length cwd in
- let l = String.length p in
- if l > n && String.sub p 0 n = cwd then
- let n' =
- let sl = String.length Filename.dir_sep in
- let i = ref n in
- while !i <= l - sl && String.sub p !i sl = Filename.dir_sep do i := !i + sl done; !i in
- remove_path_dot (String.sub p n' (l - n'))
- else
- remove_path_dot p
-
-let canonical_path_name p =
- let current = Sys.getcwd () in
- try
- Sys.chdir p;
- let p' = Sys.getcwd () in
- Sys.chdir current;
- p'
- with Sys_error _ ->
- (* We give up to find a canonical name and just simplify it... *)
- strip_path p
-
(* All subdirectories, recursively *)
let exists_dir dir =
@@ -139,9 +23,9 @@ let skipped_dirnames = ref ["CVS"; "_darcs"]
let exclude_search_in_dirname f = skipped_dirnames := f :: !skipped_dirnames
let ok_dirname f =
- f <> "" && f.[0] <> '.' && not (List.mem f !skipped_dirnames) &&
- try ignore (check_ident f); true
- with e when e <> Sys.Break -> false
+ not (String.is_empty f) && f.[0] != '.' &&
+ not (String.List.mem f !skipped_dirnames) &&
+ (match Unicode.ident_refutation f with None -> true | _ -> false)
let all_subdirs ~unix_path:root =
let l = ref [] in
@@ -154,11 +38,13 @@ let all_subdirs ~unix_path:root =
if ok_dirname f then
let file = Filename.concat dir f in
try
- if (stat file).st_kind = S_DIR then begin
- let newrel = rel@[f] in
+ begin match (stat file).st_kind with
+ | S_DIR ->
+ let newrel = rel @ [f] in
add file newrel;
traverse file newrel
- end
+ | _ -> ()
+ end
with Unix_error (e,s1,s2) -> ()
done
with End_of_file ->
@@ -167,28 +53,43 @@ let all_subdirs ~unix_path:root =
if exists_dir root then traverse root [];
List.rev !l
+let rec search paths test =
+ match paths with
+ | [] -> []
+ | lpe :: rem -> test lpe @ search rem test
+
let where_in_path ?(warn=true) path filename =
- let rec search = function
- | lpe :: rem ->
- let f = Filename.concat lpe filename in
- if Sys.file_exists f
- then (lpe,f) :: search rem
- else search rem
- | [] -> [] in
- let rec check_and_warn l =
- match l with
- | [] -> raise Not_found
- | (lpe, f) :: l' ->
- if warn & l' <> [] then
- msg_warning
- (str filename ++ str " has been found in" ++ spc () ++
- hov 0 (str "[ " ++
- hv 0 (prlist_with_sep (fun () -> str " " ++ pr_semicolon())
- (fun (lpe,_) -> str lpe) l)
- ++ str " ];") ++ fnl () ++
- str "loading " ++ str f);
- (lpe, f) in
- check_and_warn (search path)
+ let check_and_warn l = match l with
+ | [] -> raise Not_found
+ | (lpe, f) :: l' ->
+ let () = match l' with
+ | _ :: _ when warn ->
+ msg_warning
+ (str filename ++ str " has been found in" ++ spc () ++
+ hov 0 (str "[ " ++
+ hv 0 (prlist_with_sep (fun () -> str " " ++ pr_semicolon())
+ (fun (lpe,_) -> str lpe) l)
+ ++ str " ];") ++ fnl () ++
+ str "loading " ++ str f)
+ | _ -> ()
+ in
+ (lpe, f)
+ in
+ check_and_warn (search path (fun lpe ->
+ let f = Filename.concat lpe filename in
+ if Sys.file_exists f then [lpe,f] else []))
+
+let where_in_path_rex path rex =
+ search path (fun lpe ->
+ try
+ let files = Sys.readdir lpe in
+ CList.map_filter (fun name ->
+ try
+ ignore(Str.search_forward rex name 0);
+ Some (lpe,Filename.concat lpe name)
+ with Not_found -> None)
+ (Array.to_list files)
+ with Sys_error _ -> [])
let find_file_in_path ?(warn=true) paths filename =
if not (Filename.is_implicit filename) then
@@ -209,56 +110,87 @@ let is_in_path lpath filename =
try ignore (where_in_path ~warn:false lpath filename); true
with Not_found -> false
-let path_separator = if Sys.os_type = "Unix" then ':' else ';'
-
let is_in_system_path filename =
- let path = try Sys.getenv "PATH"
+ let path = try Sys.getenv "PATH"
with Not_found -> error "system variable PATH not found" in
- let lpath = lpath_from_path path path_separator in
+ let lpath = CUnix.path_to_list path in
is_in_path lpath filename
-let make_suffix name suffix =
- if Filename.check_suffix name suffix then name else (name ^ suffix)
-
-let file_readable_p name =
- try access name [R_OK];true with Unix_error (_, _, _) -> false
-
let open_trapping_failure name =
try open_out_bin name
- with e when e <> Sys.Break -> error ("Can't open " ^ name)
+ with e when Errors.noncritical e -> error ("Can't open " ^ name)
let try_remove filename =
try Sys.remove filename
- with e when e <> Sys.Break ->
- msgnl (str"Warning: " ++ str"Could not remove file " ++
- str filename ++ str" which is corrupted!" )
+ with e when Errors.noncritical e ->
+ msg_warning
+ (str"Could not remove file " ++ str filename ++ str" which is corrupted!")
-let marshal_out ch v = Marshal.to_channel ch v []
+let error_corrupted file s = error (file ^": " ^ s ^ ". Try to rebuild it.")
+
+let input_binary_int f ch =
+ try input_binary_int ch
+ with
+ | End_of_file -> error_corrupted f "premature end of file"
+ | Failure s -> error_corrupted f s
+let output_binary_int ch x = output_binary_int ch x; flush ch
+
+let marshal_out ch v = Marshal.to_channel ch v []; flush ch
let marshal_in filename ch =
try Marshal.from_channel ch
with
- | End_of_file -> error "corrupted file: reached end of file"
- | Failure _ (* e.g. "truncated object" *) ->
- error (filename ^ " is corrupted, try to rebuild it.")
+ | End_of_file -> error_corrupted filename "premature end of file"
+ | Failure s -> error_corrupted filename s
+
+let digest_out = Digest.output
+let digest_in filename ch =
+ try Digest.input ch
+ with
+ | End_of_file -> error_corrupted filename "premature end of file"
+ | Failure s -> error_corrupted filename s
+
+let marshal_out_segment f ch v =
+ let start = pos_out ch in
+ output_binary_int ch 0; (* dummy value for stop *)
+ marshal_out ch v;
+ let stop = pos_out ch in
+ seek_out ch start;
+ output_binary_int ch stop;
+ seek_out ch stop;
+ digest_out ch (Digest.file f)
+
+let marshal_in_segment f ch =
+ let stop = (input_binary_int f ch : int) in
+ let v = marshal_in f ch in
+ let digest = digest_in f ch in
+ v, stop, digest
+
+let skip_in_segment f ch =
+ let stop = (input_binary_int f ch : int) in
+ seek_in ch stop;
+ stop, digest_in f ch
exception Bad_magic_number of string
-let raw_extern_intern magic suffix =
- let extern_state name =
- let filename = make_suffix name suffix in
+let raw_extern_intern magic =
+ let extern_state filename =
let channel = open_trapping_failure filename in
output_binary_int channel magic;
- filename,channel
+ filename, channel
and intern_state filename =
- let channel = open_in_bin filename in
- if input_binary_int channel <> magic then
- raise (Bad_magic_number filename);
- channel
+ try
+ let channel = open_in_bin filename in
+ if not (Int.equal (input_binary_int filename channel) magic) then
+ raise (Bad_magic_number filename);
+ channel
+ with
+ | End_of_file -> error_corrupted filename "premature end of file"
+ | Failure s | Sys_error s -> error_corrupted filename s
in
(extern_state,intern_state)
-let extern_intern ?(warn=true) magic suffix =
- let (raw_extern,raw_intern) = raw_extern_intern magic suffix in
+let extern_intern ?(warn=true) magic =
+ let (raw_extern,raw_intern) = raw_extern_intern magic in
let extern_state name val_0 =
try
let (filename,channel) = raw_extern name in
@@ -266,11 +198,13 @@ let extern_intern ?(warn=true) magic suffix =
marshal_out channel val_0;
close_out channel
with reraise ->
- begin try_remove filename; raise reraise end
+ let reraise = Errors.push reraise in
+ let () = try_remove filename in
+ iraise reraise
with Sys_error s -> error ("System error: " ^ s)
and intern_state paths name =
try
- let _,filename = find_file_in_path ~warn paths (make_suffix name suffix) in
+ let _,filename = find_file_in_path ~warn paths name in
let channel = raw_intern filename in
let v = marshal_in filename channel in
close_in channel;
@@ -284,79 +218,47 @@ let with_magic_number_check f a =
try f a
with Bad_magic_number fname ->
errorlabstrm "with_magic_number_check"
- (str"File " ++ str fname ++ strbrk" has bad magic number." ++ spc () ++
+ (str"File " ++ str fname ++ strbrk" has bad magic number." ++ spc () ++
strbrk "It is corrupted or was compiled with another version of Coq.")
-(* Communication through files with another executable *)
-
-let connect writefun readfun com =
- let name = Filename.basename com in
- let tmp_to = Filename.temp_file ("coq-"^name^"-in") ".xml" in
- let tmp_from = Filename.temp_file ("coq-"^name^"-out") ".xml" in
- let ch_to_in,ch_to_out =
- try open_in tmp_to, open_out tmp_to
- with Sys_error s -> error ("Cannot set connection to "^com^"("^s^")") in
- let ch_from_in,ch_from_out =
- try open_in tmp_from, open_out tmp_from
- with Sys_error s ->
- close_out ch_to_out; close_in ch_to_in;
- error ("Cannot set connection from "^com^"("^s^")") in
- writefun ch_to_out;
- close_out ch_to_out;
- let pid =
- let ch_to' = Unix.descr_of_in_channel ch_to_in in
- let ch_from' = Unix.descr_of_out_channel ch_from_out in
- try Unix.create_process com [|com|] ch_to' ch_from' Unix.stdout
- with Unix.Unix_error (err,_,_) ->
- close_in ch_to_in; close_in ch_from_in; close_out ch_from_out;
- unlink tmp_from; unlink tmp_to;
- error ("Cannot execute "^com^"("^(Unix.error_message err)^")") in
- close_in ch_to_in;
- close_out ch_from_out;
- (match snd (Unix.waitpid [] pid) with
- | Unix.WEXITED 127 -> error (com^": cannot execute")
- | Unix.WEXITED 0 -> ()
- | _ -> error (com^" exited abnormally"));
- let a = readfun ch_from_in in
- close_in ch_from_in;
- unlink tmp_from;
- unlink tmp_to;
- a
-
-let run_command converter f c =
- let result = Buffer.create 127 in
- let cin,cout,cerr = Unix.open_process_full c (Unix.environment ()) in
- let buff = String.make 127 ' ' in
- let buffe = String.make 127 ' ' in
- let n = ref 0 in
- let ne = ref 0 in
-
- while n:= input cin buff 0 127 ; ne := input cerr buffe 0 127 ;
- !n+ !ne <> 0
- do
- let r = converter (String.sub buff 0 !n) in
- f r;
- Buffer.add_string result r;
- let r = converter (String.sub buffe 0 !ne) in
- f r;
- Buffer.add_string result r
- done;
- (Unix.close_process_full (cin,cout,cerr), Buffer.contents result)
-
(* Time stamps. *)
type time = float * float * float
let get_time () =
- let t = times () in
- (time(), t.tms_utime, t.tms_stime)
+ let t = Unix.times () in
+ (Unix.gettimeofday(), t.tms_utime, t.tms_stime)
-let time_difference (t1,_,_) (t2,_,_) = t2 -. t1
+(* Keep only 3 significant digits *)
+let round f = (floor (f *. 1e3)) *. 1e-3
+
+let time_difference (t1,_,_) (t2,_,_) = round (t2 -. t1)
let fmt_time_difference (startreal,ustart,sstart) (stopreal,ustop,sstop) =
- real (stopreal -. startreal) ++ str " secs " ++
+ real (round (stopreal -. startreal)) ++ str " secs " ++
str "(" ++
- real ((-.) ustop ustart) ++ str "u" ++
+ real (round (ustop -. ustart)) ++ str "u" ++
str "," ++
- real ((-.) sstop sstart) ++ str "s" ++
+ real (round (sstop -. sstart)) ++ str "s" ++
str ")"
+
+let with_time time f x =
+ let tstart = get_time() in
+ let msg = if time then "" else "Finished transaction in " in
+ try
+ let y = f x in
+ let tend = get_time() in
+ let msg2 = if time then "" else " (successful)" in
+ msg_info (str msg ++ fmt_time_difference tstart tend ++ str msg2);
+ y
+ with e ->
+ let tend = get_time() in
+ let msg = if time then "" else "Finished failing transaction in " in
+ let msg2 = if time then "" else " (failure)" in
+ msg_info (str msg ++ fmt_time_difference tstart tend ++ str msg2);
+ raise e
+
+let process_id () =
+ if Flags.async_proofs_is_worker () then !Flags.async_proofs_worker_id
+ else Printf.sprintf "master:%d" (Thread.id (Thread.self ()))
+