Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file batUnix.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273(*
* BatUnix - additional and modified functions for Unix and Unix-compatible systems.
* Copyright (C) 1996 Xavier Leroy
* Copyright (C) 2009 David Teller, LIFO, Universite d'Orleans
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version,
* with the special exception on linking described in file LICENSE.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)##V>=5##modulePervasives=StdlibincludeUnix##V<4.8##external link:string->string->unit="unix_link"##V>=4.8####V<5.0##external link :?follow:bool->string->string->unit="unix_link"##V>=5.0##externallink:?follow:bool->string->string->unit="caml_unix_link"##V<4.2##letwrite_substring=write##V<4.2##letsingle_write_substring=single_write##V<4.2##letsend_substring=send##V<4.2##letsendto_substring=sendto##V<4.3##letsleepf(timeout:float):unit=##V<4.3##letelapsed=ref0.0in##V<4.3##while!elapsed<timeoutdo##V<4.3##letstart=gettimeofday()in##V<4.3##begin##V<4.3##tryignore(select[][][](timeout-.!elapsed))##V<4.3##withUnix_error(EINTR,_,_)->()##V<4.3##end;##V<4.3##letstop=gettimeofday()in##V<4.3##letdt=stop-.startin##V<4.3##elapsed:=!elapsed+.dt##V<4.3##done;##V<4.3##()(* chronometer is useful to test sleepf*)(*$inject
let chronometer f =
let start = gettimeofday () in
let res = f () in
let stop = gettimeofday () in
let dt = stop -. start in
(dt, res) ;;
*)(* do not underestimate the imprecission of sleepf
and so don't be too harsh when testing it *)(*$T sleepf
let dt, _ = chronometer (fun () ->sleepf 0.002) in \
dt >= 0.002
*)letrun_and_readcmd =(* This code is before the open of BatInnerIO
to avoidusing batteries' wrapped IOs *)letstring_of_file fn=letbuff_size=1024inlet buff=Buffer.createbuff_sizeinletic=open_in fninletline_buff =Bytes.createbuff_sizeinbeginletwas_read=ref(inputicline_buff0buff_size)inwhile!was_read <> 0doBatBytesCompat.buffer_add_subbytes buffline_buff0!was_read;was_read:=inputicline_buff0buff_size;done;close_inic;end;Buffer.contentsbuffinlettmp_fn=Filename.temp_file""""inletcmd_to_run=cmd^" > "^tmp_fninletstatus=Unix.systemcmd_to_runinletoutput=string_of_filetmp_fninUnix.unlinktmp_fn;(status,output)(*$T run_and_read
run_and_read "echo" = (WEXITED 0, "\n")
run_and_read "echo toto" = (WEXITED 0, "toto\n")
run_and_read "seq 1 3" = (WEXITED 0, "1\n2\n3\n")
run_and_read "printf 'abc'" = (WEXITED 0, "abc")
*)openBatInnerIO(**
{6 Thread-safety internals}
*)letlock=refBatConcurrent.nolock(**
{6 Tracking additional information on inputs/outputs}
{b Note} Having [input]/[output] as objects would have made this
easier. Here,we need to maintain an external weak hashtable to
tracklow-level information on our [input]s/[output]s.
*)moduleWrapped_in=BatInnerWeaktbl.Make(Input)(*input -> in_channel*)moduleWrapped_out=BatInnerWeaktbl.Make(Output)(*output -> out_channel*)letwrapped_in=Wrapped_in.create16letwrapped_out =Wrapped_out.create16letinput_addkv=BatConcurrent.sync!lock(Wrapped_in.addwrapped_ink)vletinput_getk=BatConcurrent.sync!lock(Wrapped_in.findwrapped_in)kletoutput_addkv=BatConcurrent.sync!lock(Wrapped_out.addwrapped_outk)vletoutput_getk=BatConcurrent.sync!lock(Wrapped_out.findwrapped_out)kletwrap_in?autoclose?cleanupcin=letinput=BatInnerIO.input_channel?autoclose?cleanupcininBatConcurrent.sync!lock(Wrapped_in.addwrapped_ininput)cin;inputletwrap_out ?cleanupcout=letoutput=cast_output(BatInnerIO.output_channel ?cleanupcout)inBatConcurrent.sync!lock(Wrapped_out.addwrapped_outoutput)cout;outputlet_=input_addstdinPervasives.stdin;output_addstdout Pervasives.stdout;output_addstderrPervasives.stderr(**
{6 File descriptors}
*)letinput_of_descr?autoclose?cleanupfd=wrap_in?autoclose?cleanup (in_channel_of_descrfd)letdescr_of_inputcin=trydescr_of_in_channel(input_getcin)withNot_found->invalid_arg"Unix.descr_of_input"letoutput_of_descr?cleanupfd=wrap_out?cleanup(out_channel_of_descrfd)letdescr_of_outputcout=trydescr_of_out_channel(output_get(cast_output cout))withNot_found->invalid_arg "Unix.descr_of_output"letin_channel_of_descrfd=input_of_descr~autoclose:false~cleanup:truefdletdescr_of_in_channel=descr_of_inputletout_channel_of_descrfd=output_of_descr~cleanup:truefdletdescr_of_out_channel=descr_of_output(**
{6 Processes}
*)letopen_process_in ?autoclose?(cleanup=true)s=wrap_in?autoclose~cleanup(open_process_ins)letopen_process_out?(cleanup=true)s=wrap_out~cleanup(open_process_out s)letopen_process?autoclose?(cleanup=true)s=let(cin,cout)=open_processsin(wrap_in?autoclosecin,wrap_out~cleanupcout)(*$T open_process
let s = "hello world" in let r,w = open_process "cat"in\
Printf.fprintf w "%s\n" s; IO.close_out w; \
IO.read_line r = s
try \
let r,w = open_process "cat" in\
Printf.fprintf w "hello world\n"; \
IO.close_out w; \
while true do ignore (input_char r) done; false \
with e -> e=IO.No_more_input || e=End_of_file
*)letopen_process_full?autoclose ?(cleanup=true)sargs=let(a,b,c)=open_process_fullsargsin(wrap_in?autoclose~cleanupa,wrap_out~cleanupb,wrap_in?autoclose~cleanupc)(**@TODO in a future version, [close_process_in] should also work
on processes opened with [open_process] or [open_process_full].
Same thing for [close_process_out].*)letclose_process_incin=tryclose_process_in(input_getcin)with Not_found->raise(Unix_error(EBADF,"close_process_in",""))letclose_process_outcout=tryclose_process_out(output_getcout)with Not_found->raise (Unix_error(EBADF,"close_process_out",""))letclose_process(cin,cout)=tryletpin=input_getcinandpout=output_getcoutinclose_process(pin,pout)withNot_found->raise(Unix_error(EBADF,"close_process",""))letclose_process_full (cin,cout,cin2)=tryclose_process_full(input_getcin,output_getcout,input_get cin2)with Not_found->raise(Unix_error(EBADF,"close_process_full",""))(**
{6 Network}
*)letshutdown_connectioncin=tryshutdown_connection(input_getcin)withNot_found->invalid_arg"Unix.shutdown_connection"letopen_connection?autocloseaddr=let(cin,cout)=open_connection addrinlet(cin',cout')=(wrap_in?autoclose~cleanup:truecin,wrap_out~cleanup:truecout)inletclose()=shutdown_connectioncin'in(inherit_incin'~close,inherit_outcout'~close)letestablish_server ?autoclose?cleanupfaddr=letf'cin cout=f(wrap_in?autoclose?cleanupcin)(wrap_outcout)inestablish_serverf'addr(**
{6 Tools}
*)letis_directoryfn=(lstatfn).st_kind=S_DIRletrecrestart_on_EINTRfx=tryfxwithUnix_error(EINTR,_,_)->restart_on_EINTR fx(**
{6 Locking}
*)letwith_locked_file~kindfilenamef=letperms=[O_CREAT;matchkindwith`Read->O_RDONLY|`Write->O_RDWR]inletlock_file=openfilefilenameperms0o644inletlock_action=matchkindwith|`Read->F_RLOCK|`Write->F_LOCKinlockflock_filelock_action0;BatInnerPervasives.finally(fun()->(* Although the user might expect EINTR to interrupt locking, we must
* not allow such interrupt here since there is no way to restart the
* unlock: *)ignore(restart_on_EINTR(lseeklock_file0)SEEK_SET);restart_on_EINTR(lockflock_fileF_ULOCK)0;restart_on_EINTRcloselock_file)flock_file