123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379# 1 "src/unix/lwt_unix.cppo.ml"(* This file is part of Lwt, released under the MIT license. See LICENSE.md for
details, or visit https://github.com/ocsigen/lwt/blob/master/LICENSE.md. *)(* [Lwt_sequence] is deprecated – we don't want users outside Lwt using it.
However, it is still used internally by Lwt. So, briefly disable warning 3
("deprecated"), and create a local, non-deprecated alias for
[Lwt_sequence] that can be referred to by the rest of the code in this
module without triggering any more warnings. *)[@@@ocaml.warning"-3"]moduleLwt_sequence=Lwt_sequence[@@@ocaml.warning"+3"]openLwt.Infix(* +-----------------------------------------------------------------+
| Configuration |
+-----------------------------------------------------------------+ *)typeasync_method=|Async_none|Async_detach|Async_switchletdefault_async_method_var=refAsync_detachlet()=trymatchSys.getenv"LWT_ASYNC_METHOD"with|"none"->default_async_method_var:=Async_none|"detach"->default_async_method_var:=Async_detach|"switch"->default_async_method_var:=Async_switch|str->Printf.eprintf"%s: invalid lwt async method: '%s', must be 'none', 'detach' or 'switch'\n%!"(Filename.basenameSys.executable_name)strwithNot_found->()letdefault_async_method()=!default_async_method_varletset_default_async_methodam=default_async_method_var:=amletasync_method_key=Lwt.new_key()letasync_method()=matchLwt.getasync_method_keywith|Someam->am|None->!default_async_method_varletwith_async_nonef=Lwt.with_valueasync_method_key(SomeAsync_none)fletwith_async_detachf=Lwt.with_valueasync_method_key(SomeAsync_detach)fletwith_async_switchf=Lwt.with_valueasync_method_key(SomeAsync_switch)f(* +-----------------------------------------------------------------+
| Notifications management |
+-----------------------------------------------------------------+ *)(* Informations about a notifier *)typenotifier={notify_handler:unit->unit;(* The callback *)notify_once:bool;(* Whether to remove the notifier after the reception of the first
notification *)}moduleNotifiers=Hashtbl.Make(structtypet=intletequal(x:int)(y:int)=x=ylethash(x:int)=xend)letnotifiers=Notifiers.create1024(* See https://github.com/ocsigen/lwt/issues/277 and
https://github.com/ocsigen/lwt/pull/278. *)letcurrent_notification_id=ref(0x7FFFFFFF-1000)letrecfind_free_idid=ifNotifiers.memnotifiersidthenfind_free_id(id+1)elseidletmake_notification?(once=false)f=letid=find_free_id(!current_notification_id+1)incurrent_notification_id:=id;Notifiers.addnotifiersid{notify_once=once;notify_handler=f};idletstop_notificationid=Notifiers.removenotifiersidletset_notificationidf=letnotifier=Notifiers.findnotifiersidinNotifiers.replacenotifiersid{notifierwithnotify_handler=f}letcall_notificationid=matchtrySome(Notifiers.findnotifiersid)withNot_found->Nonewith|Somenotifier->ifnotifier.notify_oncethenstop_notificationid;notifier.notify_handler()|None->()(* +-----------------------------------------------------------------+
| Sleepers |
+-----------------------------------------------------------------+ *)letsleepdelay=letwaiter,wakener=Lwt.task()inletev=Lwt_engine.on_timerdelayfalse(funev->Lwt_engine.stop_eventev;Lwt.wakeupwakener())inLwt.on_cancelwaiter(fun()->Lwt_engine.stop_eventev);waiterletyield=Lwt_main.yieldletauto_yieldtimeout=letlimit=ref(Unix.gettimeofday()+.timeout)infun()->letcurrent=Unix.gettimeofday()inifcurrent>=!limitthenbeginlimit:=current+.timeout;yield();endelseLwt.return_unitexceptionTimeoutlettimeoutd=sleepd>>=fun()->Lwt.failTimeoutletwith_timeoutdf=Lwt.pick[timeoutd;Lwt.applyf()](* +-----------------------------------------------------------------+
| Jobs |
+-----------------------------------------------------------------+ *)type'ajobexternalstart_job:'ajob->async_method->bool="lwt_unix_start_job"(* Starts the given job with given parameters. It returns [true]
if the job is already terminated. *)[@@@ocaml.warning"-3"]externalcheck_job:'ajob->int->bool="lwt_unix_check_job""noalloc"(* Check whether that a job has terminated or not. If it has not
yet terminated, it is marked so it will send a notification
when it finishes. *)[@@@ocaml.warning"+3"](* For all running job, a waiter and a function to abort it. *)letjobs=Lwt_sequence.create()letrecabort_jobsexn=matchLwt_sequence.take_opt_ljobswith|Some(_,f)->fexn;abort_jobsexn|None->()letcancel_jobs()=abort_jobsLwt.Canceledletwait_for_jobs()=Lwt.join(Lwt_sequence.fold_l(fun(w,_)l->w::l)jobs[])letwrap_resultfx=tryResult.Ok(fx)withexn->Result.Errorexnletrun_job_auxasync_methodjobresult=(* Starts the job. *)ifstart_jobjobasync_methodthen(* The job has already terminated, read and return the result
immediately. *)Lwt.of_result(resultjob)elsebegin(* Thread for the job. *)letwaiter,wakener=Lwt.wait()in(* Add the job to the sequence of all jobs. *)letnode=Lwt_sequence.add_l((waiter>>=fun_->Lwt.return_unit),(funexn->ifLwt.statewaiter=Lwt.SleepthenLwt.wakeup_exnwakenerexn))jobsinignorebegin(* Create the notification for asynchronous wakeup. *)letid=make_notification~once:true(fun()->Lwt_sequence.removenode;letresult=resultjobinifLwt.statewaiter=Lwt.SleepthenLwt.wakeup_resultwakenerresult)in(* Give the job some time before we fallback to asynchronous
notification. *)Lwt.pause()>>=fun()->(* The job has terminated, send the result immediately. *)ifcheck_jobjobidthencall_notificationid;Lwt.return_unitend;waiterendletchoose_async_method=function|Someasync_method->async_method|None->matchLwt.getasync_method_keywith|Someam->am|None->!default_async_method_varletexecute_job?async_method~job~result~free=letasync_method=choose_async_methodasync_methodinrun_job_auxasync_methodjob(funjob->letx=wrap_resultresultjobinfreejob;x)externalself_result:'ajob->'a="lwt_unix_self_result"(* returns the result of a job using the [result] field of the C
job structure. *)externalrun_job_sync:'ajob->'a="lwt_unix_run_job_sync"(* Exeuctes a job synchronously and returns its result. *)letself_resultjob=tryResult.Ok(self_resultjob)withexn->Result.Errorexnletrun_job?async_methodjob=letasync_method=choose_async_methodasync_methodinifasync_method=Async_nonethentryLwt.return(run_job_syncjob)withexn->Lwt.failexnelserun_job_auxasync_methodjobself_result(* +-----------------------------------------------------------------+
| File descriptor wrappers |
+-----------------------------------------------------------------+ *)typestate=Opened|Closed|Abortedofexntypefile_descr={fd:Unix.file_descr;(* The underlying unix file descriptor *)mutablestate:state;(* The state of the file descriptor *)mutableset_flags:bool;(* Whether to set file flags *)mutableblocking:boolLwt.tLazy.t;(* Is the file descriptor in blocking or non-blocking mode *)mutableevent_readable:Lwt_engine.eventoption;(* The event used to check the file descriptor for readability. *)mutableevent_writable:Lwt_engine.eventoption;(* The event used to check the file descriptor for writability. *)hooks_readable:(unit->unit)Lwt_sequence.t;(* Hooks to call when the file descriptor becomes readable. *)hooks_writable:(unit->unit)Lwt_sequence.t;(* Hooks to call when the file descriptor becomes writable. *)}[@@@ocaml.warning"-3"]externalis_socket:Unix.file_descr->bool="lwt_unix_is_socket""noalloc"[@@@ocaml.warning"+3"]externalguess_blocking_job:Unix.file_descr->booljob="lwt_unix_guess_blocking_job"letguess_blockingfd=run_job(guess_blocking_jobfd)letis_blocking?blocking?(set_flags=true)fd=ifSys.win32thenbeginifis_socketfdthenmatchblocking,set_flagswith|Somestate,false->lazy(Lwt.returnstate)|Sometrue,true->lazy(Unix.clear_nonblockfd;Lwt.return_true)|Somefalse,true->lazy(Unix.set_nonblockfd;Lwt.return_false)|None,false->lazy(Lwt.return_false)|None,true->lazy(Unix.set_nonblockfd;Lwt.return_false)elsematchblockingwith|Somestate->lazy(Lwt.returnstate)|None->lazy(Lwt.return_true)endelsebeginmatchblocking,set_flagswith|Somestate,false->lazy(Lwt.returnstate)|Sometrue,true->lazy(Unix.clear_nonblockfd;Lwt.return_true)|Somefalse,true->lazy(Unix.set_nonblockfd;Lwt.return_false)|None,false->lazy(guess_blockingfd)|None,true->lazy(guess_blockingfd>>=function|true->Unix.clear_nonblockfd;Lwt.return_true|false->Unix.set_nonblockfd;Lwt.return_false)endletmk_ch?blocking?(set_flags=true)fd={fd=fd;state=Opened;set_flags=set_flags;blocking=is_blocking?blocking~set_flagsfd;event_readable=None;event_writable=None;hooks_readable=Lwt_sequence.create();hooks_writable=Lwt_sequence.create();}letcheck_descriptorch=matchch.statewith|Opened->()|Abortede->raisee|Closed->raise(Unix.Unix_error(Unix.EBADF,"check_descriptor",""))letstatech=ch.stateletblockingch=check_descriptorch;Lazy.forcech.blockingletset_blocking?(set_flags=true)chblocking=check_descriptorch;ch.set_flags<-set_flags;ch.blocking<-is_blocking~blocking~set_flagsch.fdexternalunix_stub_readable:Unix.file_descr->bool="lwt_unix_readable"externalunix_stub_writable:Unix.file_descr->bool="lwt_unix_writable"letrecunix_readablefd=tryifSys.win32thenUnix.select[fd][][]0.0<>([],[],[])elseunix_stub_readablefdwithUnix.Unix_error(Unix.EINTR,_,_)->unix_readablefdletrecunix_writablefd=tryifSys.win32thenUnix.select[][fd][]0.0<>([],[],[])elseunix_stub_writablefdwithUnix.Unix_error(Unix.EINTR,_,_)->unix_writablefdletreadablech=check_descriptorch;unix_readablech.fdletwritablech=check_descriptorch;unix_writablech.fdletset_statechst=ch.state<-stletclear_eventsch=Lwt_sequence.iter_node_l(funnode->Lwt_sequence.removenode;Lwt_sequence.getnode())ch.hooks_readable;Lwt_sequence.iter_node_l(funnode->Lwt_sequence.removenode;Lwt_sequence.getnode())ch.hooks_writable;beginmatchch.event_readablewith|Someev->ch.event_readable<-None;Lwt_engine.stop_eventev|None->()end;beginmatchch.event_writablewith|Someev->ch.event_writable<-None;Lwt_engine.stop_eventev|None->()endletabortche=ifch.state<>Closedthenbeginset_statech(Abortede);clear_eventschendletunix_file_descrch=ch.fdletof_unix_file_descr=mk_chletstdin=of_unix_file_descr~set_flags:false~blocking:trueUnix.stdinletstdout=of_unix_file_descr~set_flags:false~blocking:trueUnix.stdoutletstderr=of_unix_file_descr~set_flags:false~blocking:trueUnix.stderr(* +-----------------------------------------------------------------+
| Actions on file descriptors |
+-----------------------------------------------------------------+ *)typeio_event=Read|WriteexceptionRetryexceptionRetry_writeexceptionRetry_readtype'aoutcome=|Successof'a|Exnofexn|Requeuedofio_event(* Wait a bit, then stop events that are no more used. *)letstop_eventsch=Lwt.on_success(Lwt.pause())(fun()->ifLwt_sequence.is_emptych.hooks_readablethenbeginmatchch.event_readablewith|Someev->ch.event_readable<-None;Lwt_engine.stop_eventev|None->()end;ifLwt_sequence.is_emptych.hooks_writablethenbeginmatchch.event_writablewith|Someev->ch.event_writable<-None;Lwt_engine.stop_eventev|None->()end)letregister_readablech=ifch.event_readable=Nonethench.event_readable<-Some(Lwt_engine.on_readablech.fd(fun_->Lwt_sequence.iter_l(funf->f())ch.hooks_readable))letregister_writablech=ifch.event_writable=Nonethench.event_writable<-Some(Lwt_engine.on_writablech.fd(fun_->Lwt_sequence.iter_l(funf->f())ch.hooks_writable))(* Retry a queued syscall, [wakener] is the thread to wakeup if the
action succeeds: *)letrecretry_syscallnodeeventchwakeneraction=letres=trycheck_descriptorch;Success(action())with|Retry|Unix.Unix_error((Unix.EAGAIN|Unix.EWOULDBLOCK|Unix.EINTR),_,_)|Sys_blocked_io->(* EINTR because we are catching SIG_CHLD hence the system
call might be interrupted to handle the signal; this lets
us restart the system call eventually. *)Requeuedevent|Retry_read->RequeuedRead|Retry_write->RequeuedWrite|e->Exneinmatchreswith|Successv->Lwt_sequence.remove!node;stop_eventsch;Lwt.wakeupwakenerv|Exne->Lwt_sequence.remove!node;stop_eventsch;Lwt.wakeup_exnwakenere|Requeuedevent'->ifevent<>event'thenbeginLwt_sequence.remove!node;stop_eventsch;matchevent'with|Read->node:=Lwt_sequence.add_r(fun()->retry_syscallnodeReadchwakeneraction)ch.hooks_readable;register_readablech|Write->node:=Lwt_sequence.add_r(fun()->retry_syscallnodeWritechwakeneraction)ch.hooks_writable;register_writablechendletdummy=Lwt_sequence.add_rignore(Lwt_sequence.create())letregister_actioneventchaction=letwaiter,wakener=Lwt.task()inmatcheventwith|Read->letnode=refdummyinnode:=Lwt_sequence.add_r(fun()->retry_syscallnodeReadchwakeneraction)ch.hooks_readable;Lwt.on_cancelwaiter(fun()->Lwt_sequence.remove!node;stop_eventsch);register_readablech;waiter|Write->letnode=refdummyinnode:=Lwt_sequence.add_r(fun()->retry_syscallnodeWritechwakeneraction)ch.hooks_writable;Lwt.on_cancelwaiter(fun()->Lwt_sequence.remove!node;stop_eventsch);register_writablech;waiter(* Wraps a system call *)letwrap_syscalleventchaction=check_descriptorch;Lazy.forcech.blocking>>=funblocking->tryifnotblocking||(event=Read&&unix_readablech.fd)||(event=Write&&unix_writablech.fd)thenLwt.return(action())elseregister_actioneventchactionwith|Retry|Unix.Unix_error((Unix.EAGAIN|Unix.EWOULDBLOCK|Unix.EINTR),_,_)|Sys_blocked_io->(* The action could not be completed immediately, register it: *)register_actioneventchaction|Retry_read->register_actionReadchaction|Retry_write->register_actionWritechaction|e->Lwt.faile(* +-----------------------------------------------------------------+
| Generated jobs |
+-----------------------------------------------------------------+ *)moduleJobs=Lwt_unix_jobs.Make(structtype'at='ajobend)(* +-----------------------------------------------------------------+
| Basic file input/output |
+-----------------------------------------------------------------+ *)typeopen_flag=Unix.open_flag=|O_RDONLY|O_WRONLY|O_RDWR|O_NONBLOCK|O_APPEND|O_CREAT|O_TRUNC|O_EXCL|O_NOCTTY|O_DSYNC|O_SYNC|O_RSYNC|O_SHARE_DELETE|O_CLOEXEC# 588 "src/unix/lwt_unix.cppo.ml"|O_KEEPEXEC# 591 "src/unix/lwt_unix.cppo.ml"externalopen_job:string->Unix.open_flaglist->int->(Unix.file_descr*bool)job="lwt_unix_open_job"letopenfilenameflagsperms=ifSys.win32thenLwt.return(of_unix_file_descr(Unix.openfilenameflagsperms))elserun_job(open_jobnameflagsperms)>>=fun(fd,blocking)->Lwt.return(of_unix_file_descr~blockingfd)letclosech=ifch.state=Closedthencheck_descriptorch;set_statechClosed;clear_eventsch;ifSys.win32thenLwt.return(Unix.closech.fd)elserun_job(Jobs.close_jobch.fd)letwait_readch=Lwt.catch(fun()->ifreadablechthenLwt.return_unitelseregister_actionReadchignore)Lwt.failexternalstub_read:Unix.file_descr->Bytes.t->int->int->int="lwt_unix_read"externalread_job:Unix.file_descr->Bytes.t->int->int->intjob="lwt_unix_read_job"letreadchbufposlen=ifpos<0||len<0||pos>Bytes.lengthbuf-lentheninvalid_arg"Lwt_unix.read"elseLazy.forcech.blocking>>=function|true->wait_readch>>=fun()->run_job(read_jobch.fdbufposlen)|false->wrap_syscallReadch(fun()->stub_readch.fdbufposlen)letwait_writech=Lwt.catch(fun()->ifwritablechthenLwt.return_unitelseregister_actionWritechignore)Lwt.failexternalstub_write:Unix.file_descr->Bytes.t->int->int->int="lwt_unix_write"externalwrite_job:Unix.file_descr->Bytes.t->int->int->intjob="lwt_unix_write_job"letwritechbufposlen=ifpos<0||len<0||pos>Bytes.lengthbuf-lentheninvalid_arg"Lwt_unix.write"elseLazy.forcech.blocking>>=function|true->wait_writech>>=fun()->run_job(write_jobch.fdbufposlen)|false->wrap_syscallWritech(fun()->stub_writech.fdbufposlen)letwrite_stringchbufposlen=letbuf=Bytes.unsafe_of_stringbufinwritechbufposlenmoduleIO_vectors=structtype_bigarray=(char,Bigarray.int8_unsigned_elt,Bigarray.c_layout)Bigarray.Array1.ttypebuffer=|Bytesofbytes|Bigarrayof_bigarraytypeio_vector={buffer:buffer;mutableoffset:int;mutablelength:int}(* This representation does not give constant amortized time append across all
possible operation sequences, but it does for expected typical usage, in
which some number of append operations is followed by some number of
flatten operations. *)typet={mutableprefix:io_vectorlist;mutablereversed_suffix:io_vectorlist;mutablecount:int}letcreate()={prefix=[];reversed_suffix=[];count=0}letbyte_count{prefix;reversed_suffix;_}=letcount_buff=List.fold_left(funacc{length;_}->acc+length)0incount_buffprefix+count_buffreversed_suffixletappendio_vectorsio_vector=io_vectors.reversed_suffix<-io_vector::io_vectors.reversed_suffix;io_vectors.count<-io_vectors.count+1letappend_bytesio_vectorsbufferoffsetlength=appendio_vectors{buffer=Bytesbuffer;offset;length}letappend_bigarrayio_vectorsbufferoffsetlength=appendio_vectors{buffer=Bigarraybuffer;offset;length}letflattenio_vectors=matchio_vectors.reversed_suffixwith|[]->()|_->io_vectors.prefix<-io_vectors.prefix@(List.revio_vectors.reversed_suffix);io_vectors.reversed_suffix<-[]letdropio_vectorscount=flattenio_vectors;letrecloopcountprefix=ifcount<=0thenprefixelsematchprefixwith|[]->[]|{length;_}::restwhenlength<=count->io_vectors.count<-io_vectors.count-1;loop(count-length)rest|first::_->first.offset<-first.offset+count;first.length<-first.length-count;prefixinio_vectors.prefix<-loopcountio_vectors.prefixletis_emptyio_vectors=flattenio_vectors;letrecloop=function|[]->true|{length=0;_}::rest->looprest|_->falseinloopio_vectors.prefixexternalstub_iov_max:unit->int="lwt_unix_iov_max"letsystem_limit=ifSys.win32thenNoneelseSome(stub_iov_max())letchecktagio_vector=letbuffer_length=matchio_vector.bufferwith|Bytess->Bytes.lengths|Bigarraya->Bigarray.Array1.dimainifio_vector.length<0||io_vector.offset<0||io_vector.offset+io_vector.length>buffer_lengththeninvalid_argtagend(* Flattens the I/O vectors into a single list, checks their bounds, and
evaluates to the minimum of: the number of vectors and the system's
IOV_MAX. *)letcheck_io_vectorsfunction_nameio_vectors=IO_vectors.flattenio_vectors;List.iter(IO_vectors.checkfunction_name)io_vectors.IO_vectors.prefix;matchIO_vectors.system_limitwith|Somelimitwhenio_vectors.IO_vectors.count>limit->limit|_->io_vectors.IO_vectors.countexternalstub_readv:Unix.file_descr->IO_vectors.io_vectorlist->int->int="lwt_unix_readv"externalreadv_job:Unix.file_descr->IO_vectors.io_vectorlist->int->intjob="lwt_unix_readv_job"letreadvfdio_vectors=letcount=check_io_vectors"Lwt_unix.readv"io_vectorsinLazy.forcefd.blocking>>=function|true->wait_readfd>>=fun()->run_job(readv_jobfd.fdio_vectors.IO_vectors.prefixcount)|false->wrap_syscallReadfd(fun()->stub_readvfd.fdio_vectors.IO_vectors.prefixcount)externalstub_writev:Unix.file_descr->IO_vectors.io_vectorlist->int->int="lwt_unix_writev"externalwritev_job:Unix.file_descr->IO_vectors.io_vectorlist->int->intjob="lwt_unix_writev_job"letwritevfdio_vectors=letcount=check_io_vectors"Lwt_unix.writev"io_vectorsinLazy.forcefd.blocking>>=function|true->wait_writefd>>=fun()->run_job(writev_jobfd.fdio_vectors.IO_vectors.prefixcount)|false->wrap_syscallWritefd(fun()->stub_writevfd.fdio_vectors.IO_vectors.prefixcount)(* +-----------------------------------------------------------------+
| Seeking and truncating |
+-----------------------------------------------------------------+ *)typeseek_command=Unix.seek_command=|SEEK_SET|SEEK_CUR|SEEK_ENDletlseekchoffsetwhence=check_descriptorch;ifSys.win32thenLwt.return(Unix.lseekch.fdoffsetwhence)elserun_job(Jobs.lseek_jobch.fdoffsetwhence)lettruncatenameoffset=ifSys.win32thenLwt.return(Unix.truncatenameoffset)elserun_job(Jobs.truncate_jobnameoffset)letftruncatechoffset=check_descriptorch;ifSys.win32thenLwt.return(Unix.ftruncatech.fdoffset)elserun_job(Jobs.ftruncate_jobch.fdoffset)(* +-----------------------------------------------------------------+
| File system synchronisation |
+-----------------------------------------------------------------+ *)letfdatasyncch=check_descriptorch;run_job(Jobs.fdatasync_jobch.fd)letfsyncch=check_descriptorch;run_job(Jobs.fsync_jobch.fd)(* +-----------------------------------------------------------------+
| File status |
+-----------------------------------------------------------------+ *)typefile_perm=Unix.file_permtypefile_kind=Unix.file_kind=|S_REG|S_DIR|S_CHR|S_BLK|S_LNK|S_FIFO|S_SOCKtypestats=Unix.stats={st_dev:int;st_ino:int;st_kind:file_kind;st_perm:file_perm;st_nlink:int;st_uid:int;st_gid:int;st_rdev:int;st_size:int;st_atime:float;st_mtime:float;st_ctime:float;}externalstat_job:string->Unix.statsjob="lwt_unix_stat_job"letstatname=ifSys.win32thenLwt.return(Unix.statname)elserun_job(stat_jobname)externallstat_job:string->Unix.statsjob="lwt_unix_lstat_job"letlstatname=ifSys.win32thenLwt.return(Unix.statname)elserun_job(lstat_jobname)externalfstat_job:Unix.file_descr->Unix.statsjob="lwt_unix_fstat_job"letfstatch=check_descriptorch;ifSys.win32thenLwt.return(Unix.fstatch.fd)elserun_job(fstat_jobch.fd)letfile_existsname=Lwt.try_bind(fun()->statname)(fun_->Lwt.return_true)(fune->matchewith|Unix.Unix_error_->Lwt.return_false|_->Lwt.faile)[@ocaml.warning"-4"]externalutimes_job:string->float->float->unitjob="lwt_unix_utimes_job"letutimespathatimemtime=ifSys.win32thenLwt.return(Unix.utimespathatimemtime)elserun_job(utimes_jobpathatimemtime)externalisatty_job:Unix.file_descr->booljob="lwt_unix_isatty_job"letisattych=check_descriptorch;ifSys.win32thenLwt.return(Unix.isattych.fd)elserun_job(isatty_jobch.fd)(* +-----------------------------------------------------------------+
| File operations on large files |
+-----------------------------------------------------------------+ *)moduleLargeFile=structtypestats=Unix.LargeFile.stats={st_dev:int;st_ino:int;st_kind:file_kind;st_perm:file_perm;st_nlink:int;st_uid:int;st_gid:int;st_rdev:int;st_size:int64;st_atime:float;st_mtime:float;st_ctime:float;}letlseekchoffsetwhence=check_descriptorch;ifSys.win32thenLwt.return(Unix.LargeFile.lseekch.fdoffsetwhence)elserun_job(Jobs.lseek_64_jobch.fdoffsetwhence)lettruncatenameoffset=ifSys.win32thenLwt.return(Unix.LargeFile.truncatenameoffset)elserun_job(Jobs.truncate_64_jobnameoffset)letftruncatechoffset=check_descriptorch;ifSys.win32thenLwt.return(Unix.LargeFile.ftruncatech.fdoffset)elserun_job(Jobs.ftruncate_64_jobch.fdoffset)externalstat_job:string->Unix.LargeFile.statsjob="lwt_unix_stat_64_job"letstatname=ifSys.win32thenLwt.return(Unix.LargeFile.statname)elserun_job(stat_jobname)externallstat_job:string->Unix.LargeFile.statsjob="lwt_unix_lstat_64_job"letlstatname=ifSys.win32thenLwt.return(Unix.LargeFile.lstatname)elserun_job(lstat_jobname)externalfstat_job:Unix.file_descr->Unix.LargeFile.statsjob="lwt_unix_fstat_64_job"letfstatch=check_descriptorch;ifSys.win32thenLwt.return(Unix.LargeFile.fstatch.fd)elserun_job(fstat_jobch.fd)letfile_existsname=Lwt.try_bind(fun()->statname)(fun_->Lwt.return_true)(fune->matchewith|Unix.Unix_error_->Lwt.return_false|_->Lwt.faile)[@ocaml.warning"-4"]end(* +-----------------------------------------------------------------+
| Operations on file names |
+-----------------------------------------------------------------+ *)letunlinkname=ifSys.win32thenLwt.return(Unix.unlinkname)elserun_job(Jobs.unlink_jobname)letrenamename1name2=ifSys.win32thenLwt.return(Unix.renamename1name2)elserun_job(Jobs.rename_jobname1name2)letlinkoldpathnewpath=ifSys.win32thenLwt.return(Unix.linkoldpathnewpath)elserun_job(Jobs.link_joboldpathnewpath)(* +-----------------------------------------------------------------+
| File permissions and ownership |
+-----------------------------------------------------------------+ *)letchmodnamemode=ifSys.win32thenLwt.return(Unix.chmodnamemode)elserun_job(Jobs.chmod_jobnamemode)letfchmodchmode=check_descriptorch;ifSys.win32thenLwt.return(Unix.fchmodch.fdmode)elserun_job(Jobs.fchmod_jobch.fdmode)letchownnameuidgid=ifSys.win32thenLwt.return(Unix.chownnameuidgid)elserun_job(Jobs.chown_jobnameuidgid)letfchownchuidgid=check_descriptorch;ifSys.win32thenLwt.return(Unix.fchownch.fduidgid)elserun_job(Jobs.fchown_jobch.fduidgid)typeaccess_permission=Unix.access_permission=|R_OK|W_OK|X_OK|F_OKletaccessnamemode=ifSys.win32thenLwt.return(Unix.accessnamemode)elserun_job(Jobs.access_jobnamemode)(* +-----------------------------------------------------------------+
| Operations on file descriptors |
+-----------------------------------------------------------------+ *)letdupch=check_descriptorch;letfd=Unix.dupch.fdin{fd=fd;state=Opened;set_flags=ch.set_flags;blocking=ifch.set_flagsthenlazy(Lazy.forcech.blocking>>=function|true->Unix.clear_nonblockfd;Lwt.return_true|false->Unix.set_nonblockfd;Lwt.return_false)elsech.blocking;event_readable=None;event_writable=None;hooks_readable=Lwt_sequence.create();hooks_writable=Lwt_sequence.create();}letdup2ch1ch2=check_descriptorch1;Unix.dup2ch1.fdch2.fd;ch2.set_flags<-ch1.set_flags;ch2.blocking<-(ifch2.set_flagsthenlazy(Lazy.forcech1.blocking>>=function|true->Unix.clear_nonblockch2.fd;Lwt.return_true|false->Unix.set_nonblockch2.fd;Lwt.return_false)elsech1.blocking)letset_close_on_execch=check_descriptorch;Unix.set_close_on_execch.fdletclear_close_on_execch=check_descriptorch;Unix.clear_close_on_execch.fd(* +-----------------------------------------------------------------+
| Directories |
+-----------------------------------------------------------------+ *)letmkdirnameperms=ifSys.win32thenLwt.return(Unix.mkdirnameperms)elserun_job(Jobs.mkdir_jobnameperms)letrmdirname=ifSys.win32thenLwt.return(Unix.rmdirname)elserun_job(Jobs.rmdir_jobname)letchdirname=ifSys.win32thenLwt.return(Unix.chdirname)elserun_job(Jobs.chdir_jobname)externalgetcwd_job:unit->stringjob="lwt_unix_getcwd_job"letgetcwd()=ifSys.win32thenLwt.return(Unix.getcwd())elserun_job(getcwd_job())letchrootname=ifSys.win32thenLwt.return(Unix.chrootname)elserun_job(Jobs.chroot_jobname)typedir_handle=Unix.dir_handleexternalopendir_job:string->Unix.dir_handlejob="lwt_unix_opendir_job"letopendirname=ifSys.win32thenLwt.return(Unix.opendirname)elserun_job(opendir_jobname)externalvalid_dir:Unix.dir_handle->bool="lwt_unix_valid_dir"externalreaddir_job:Unix.dir_handle->stringjob="lwt_unix_readdir_job"letreaddirhandle=ifSys.win32thenLwt.return(Unix.readdirhandle)elseifvalid_dirhandlethenrun_job(readdir_jobhandle)elseLwt.fail(Unix.(Unix_error(EBADF,"Lwt_unix.readdir","")))externalreaddir_n_job:Unix.dir_handle->int->stringarrayjob="lwt_unix_readdir_n_job"letreaddir_nhandlecount=ifcount<0thenLwt.fail(Invalid_argument"Lwt_unix.readdir_n")elseifSys.win32thenletarray=Array.makecount""inletrecfilli=ifi=countthenLwt.returnarrayelsematchtryarray.(i)<-Unix.readdirhandle;truewithEnd_of_file->falsewith|true->fill(i+1)|false->Lwt.return(Array.subarray0i)infill0elseifvalid_dirhandlethenrun_job(readdir_n_jobhandlecount)elseLwt.fail(Unix.(Unix_error(EBADF,"Lwt_unix.readdir_n","")))externalrewinddir_job:Unix.dir_handle->unitjob="lwt_unix_rewinddir_job"letrewinddirhandle=ifSys.win32thenLwt.return(Unix.rewinddirhandle)elseifvalid_dirhandlethenrun_job(rewinddir_jobhandle)elseLwt.fail(Unix.(Unix_error(EBADF,"Lwt_unix.rewinddir","")))externalclosedir_job:Unix.dir_handle->unitjob="lwt_unix_closedir_job"externalinvalidate_dir:Unix.dir_handle->unit="lwt_unix_invalidate_dir"letclosedirhandle=ifSys.win32thenLwt.return(Unix.closedirhandle)elseifvalid_dirhandlethenrun_job(closedir_jobhandle)>>=fun()->invalidate_dirhandle;Lwt.return_unitelseLwt.fail(Unix.(Unix_error(EBADF,"Lwt_unix.closedir","")))typelist_directory_state=|LDS_not_started|LDS_listingofUnix.dir_handle|LDS_doneletcleanup_dir_handlestate=match!statewith|LDS_listinghandle->ignore(closedirhandle)|LDS_not_started|LDS_done->()letfiles_of_directorypath=letchunk_size=1024inletstate=refLDS_not_startedinLwt_stream.concat(Lwt_stream.from(fun()->match!statewith|LDS_not_started->opendirpath>>=funhandle->Lwt.catch(fun()->readdir_nhandlechunk_size)(funexn->closedirhandle>>=fun()->Lwt.failexn)>>=funentries->ifArray.lengthentries<chunk_sizethenbeginstate:=LDS_done;closedirhandle>>=fun()->Lwt.return(Some(Lwt_stream.of_arrayentries))endelsebeginstate:=LDS_listinghandle;Gc.finalisecleanup_dir_handlestate;Lwt.return(Some(Lwt_stream.of_arrayentries))end|LDS_listinghandle->Lwt.catch(fun()->readdir_nhandlechunk_size)(funexn->closedirhandle>>=fun()->Lwt.failexn)>>=funentries->ifArray.lengthentries<chunk_sizethenbeginstate:=LDS_done;closedirhandle>>=fun()->Lwt.return(Some(Lwt_stream.of_arrayentries))endelseLwt.return(Some(Lwt_stream.of_arrayentries))|LDS_done->Lwt.return_none))(* +-----------------------------------------------------------------+
| Pipes and redirections |
+-----------------------------------------------------------------+ *)letpipe()=let(out_fd,in_fd)=Unix.pipe()in(mk_ch~blocking:Sys.win32out_fd,mk_ch~blocking:Sys.win32in_fd)letpipe_in()=let(out_fd,in_fd)=Unix.pipe()in(mk_ch~blocking:Sys.win32out_fd,in_fd)letpipe_out()=let(out_fd,in_fd)=Unix.pipe()in(out_fd,mk_ch~blocking:Sys.win32in_fd)letmkfifonameperms=ifSys.win32thenLwt.return(Unix.mkfifonameperms)elserun_job(Jobs.mkfifo_jobnameperms)(* +-----------------------------------------------------------------+
| Symbolic links |
+-----------------------------------------------------------------+ *)letsymlinkname1name2=ifSys.win32thenLwt.return(Unix.symlinkname1name2)elserun_job(Jobs.symlink_jobname1name2)externalreadlink_job:string->stringjob="lwt_unix_readlink_job"letreadlinkname=ifSys.win32thenLwt.return(Unix.readlinkname)elserun_job(readlink_jobname)(* +-----------------------------------------------------------------+
| Locking |
+-----------------------------------------------------------------+ *)typelock_command=Unix.lock_command=|F_ULOCK|F_LOCK|F_TLOCK|F_TEST|F_RLOCK|F_TRLOCKexternallockf_job:Unix.file_descr->Unix.lock_command->int->unitjob="lwt_unix_lockf_job"letlockfchcmdsize=check_descriptorch;ifSys.win32thenLwt.return(Unix.lockfch.fdcmdsize)elserun_job(lockf_jobch.fdcmdsize)(* +-----------------------------------------------------------------+
| User id, group id |
+-----------------------------------------------------------------+ *)typepasswd_entry=Unix.passwd_entry={pw_name:string;pw_passwd:string;pw_uid:int;pw_gid:int;pw_gecos:string;pw_dir:string;pw_shell:string}typegroup_entry=Unix.group_entry={gr_name:string;gr_passwd:string;gr_gid:int;gr_mem:stringarray}externalgetlogin_job:unit->stringjob="lwt_unix_getlogin_job"letgetlogin()=ifSys.win32||Lwt_config.androidthenLwt.return(Unix.getlogin())elserun_job(getlogin_job())externalgetpwnam_job:string->Unix.passwd_entryjob="lwt_unix_getpwnam_job"letgetpwnamname=ifSys.win32||Lwt_config.androidthenLwt.return(Unix.getpwnamname)elserun_job(getpwnam_jobname)externalgetgrnam_job:string->Unix.group_entryjob="lwt_unix_getgrnam_job"letgetgrnamname=ifSys.win32||Lwt_config.androidthenLwt.return(Unix.getgrnamname)elserun_job(getgrnam_jobname)externalgetpwuid_job:int->Unix.passwd_entryjob="lwt_unix_getpwuid_job"letgetpwuiduid=ifSys.win32||Lwt_config.androidthenLwt.return(Unix.getpwuiduid)elserun_job(getpwuid_jobuid)externalgetgrgid_job:int->Unix.group_entryjob="lwt_unix_getgrgid_job"letgetgrgidgid=ifSys.win32||Lwt_config.androidthenLwt.return(Unix.getgrgidgid)elserun_job(getgrgid_jobgid)(* +-----------------------------------------------------------------+
| Sockets |
+-----------------------------------------------------------------+ *)typemsg_flag=Unix.msg_flag=|MSG_OOB|MSG_DONTROUTE|MSG_PEEKexternalstub_recv:Unix.file_descr->Bytes.t->int->int->Unix.msg_flaglist->int="lwt_unix_recv"letrecvchbufposlenflags=ifpos<0||len<0||pos>Bytes.lengthbuf-lentheninvalid_arg"Lwt_unix.recv"elseletdo_recv=ifSys.win32thenUnix.recvelsestub_recvinwrap_syscallReadch(fun()->do_recvch.fdbufposlenflags)externalstub_send:Unix.file_descr->Bytes.t->int->int->Unix.msg_flaglist->int="lwt_unix_send"letsendchbufposlenflags=ifpos<0||len<0||pos>Bytes.lengthbuf-lentheninvalid_arg"Lwt_unix.send"elseletdo_send=ifSys.win32thenUnix.sendelsestub_sendinwrap_syscallWritech(fun()->do_sendch.fdbufposlenflags)externalstub_recvfrom:Unix.file_descr->Bytes.t->int->int->Unix.msg_flaglist->int*Unix.sockaddr="lwt_unix_recvfrom"letrecvfromchbufposlenflags=ifpos<0||len<0||pos>Bytes.lengthbuf-lentheninvalid_arg"Lwt_unix.recvfrom"elseletdo_recvfrom=ifSys.win32thenUnix.recvfromelsestub_recvfrominwrap_syscallReadch(fun()->do_recvfromch.fdbufposlenflags)externalstub_sendto:Unix.file_descr->Bytes.t->int->int->Unix.msg_flaglist->Unix.sockaddr->int="lwt_unix_sendto_byte""lwt_unix_sendto"letsendtochbufposlenflagsaddr=ifpos<0||len<0||pos>Bytes.lengthbuf-lentheninvalid_arg"Lwt_unix.sendto"elseletdo_sendto=ifSys.win32thenUnix.sendtoelsestub_sendtoinwrap_syscallWritech(fun()->do_sendtoch.fdbufposlenflagsaddr)typeio_vector={iov_buffer:string;iov_offset:int;iov_length:int;}letio_vector~buffer~offset~length={iov_buffer=buffer;iov_offset=offset;iov_length=length;}letcheck_io_vectorsfunc_nameiovs=List.iter(funiov->ifiov.iov_offset<0||iov.iov_length<0||iov.iov_offset>String.lengthiov.iov_buffer-iov.iov_lengththeninvalid_argfunc_name)iovsexternalstub_recv_msg:Unix.file_descr->int->io_vectorlist->int*Unix.file_descrlist="lwt_unix_recv_msg"letrecv_msg~socket~io_vectors=check_io_vectors"Lwt_unix.recv_msg"io_vectors;letn_iovs=List.lengthio_vectorsinwrap_syscallReadsocket(fun()->stub_recv_msgsocket.fdn_iovsio_vectors)externalstub_send_msg:Unix.file_descr->int->io_vectorlist->int->Unix.file_descrlist->int="lwt_unix_send_msg"letsend_msg~socket~io_vectors~fds=check_io_vectors"Lwt_unix.send_msg"io_vectors;letn_iovs=List.lengthio_vectorsandn_fds=List.lengthfdsinwrap_syscallWritesocket(fun()->stub_send_msgsocket.fdn_iovsio_vectorsn_fdsfds)typeinet_addr=Unix.inet_addrtypesocket_domain=Unix.socket_domain=|PF_UNIX|PF_INET|PF_INET6typesocket_type=Unix.socket_type=|SOCK_STREAM|SOCK_DGRAM|SOCK_RAW|SOCK_SEQPACKETtypesockaddr=Unix.sockaddr=ADDR_UNIXofstring|ADDR_INETofinet_addr*intletsocketdomtypproto=lets=Unix.socketdomtypprotoinmk_ch~blocking:falsestypeshutdown_command=Unix.shutdown_command=|SHUTDOWN_RECEIVE|SHUTDOWN_SEND|SHUTDOWN_ALLletshutdownchshutdown_command=check_descriptorch;Unix.shutdownch.fdshutdown_commandexternalstub_socketpair:socket_domain->socket_type->int->Unix.file_descr*Unix.file_descr="lwt_unix_socketpair_stub"letsocketpairdomtypproto=# 1525 "src/unix/lwt_unix.cppo.ml"letdo_socketpair=ifSys.win32thenstub_socketpairelseUnix.socketpair?cloexec:Nonein# 1531 "src/unix/lwt_unix.cppo.ml"let(s1,s2)=do_socketpairdomtypprotoin(mk_ch~blocking:falses1,mk_ch~blocking:falses2)letacceptch=wrap_syscallReadch(fun_->let(fd,addr)=Unix.acceptch.fdin(mk_ch~blocking:falsefd,addr))letaccept_nchn=letl=ref[]inLazy.forcech.blocking>>=funblocking->Lwt.catch(fun()->wrap_syscallReadchbeginfun()->begintryfor_i=1tondoifblocking&¬(unix_readablech.fd)thenraiseRetry;letfd,addr=Unix.acceptch.fdinl:=(mk_ch~blocking:falsefd,addr)::!ldonewith|(Unix.Unix_error((Unix.EAGAIN|Unix.EWOULDBLOCK|Unix.EINTR),_,_)|Retry)when!l<>[]->(* Ignore blocking errors if we have at least one file-descriptor: *)()end;(List.rev!l,None)end)(funexn->Lwt.return(List.rev!l,Someexn))letconnectchaddr=ifSys.win32then(* [in_progress] tell wether connection has started but not
terminated: *)letin_progress=reffalseinwrap_syscallWritechbeginfun()->if!in_progressthen(* Nothing works without this test and i have no idea why... *)ifwritablechthentryUnix.connectch.fdaddrwith|Unix.Unix_error(Unix.EISCONN,_,_)->(* This is the windows way of telling that the connection
has completed. *)()elseraiseRetryelsetryUnix.connectch.fdaddrwith|Unix.Unix_error(Unix.EWOULDBLOCK,_,_)->in_progress:=true;raiseRetryendelse(* [in_progress] tell wether connection has started but not
terminated: *)letin_progress=reffalseinwrap_syscallWritechbeginfun()->if!in_progressthen(* If the connection is in progress, [getsockopt_error] tells
wether it succceed: *)matchUnix.getsockopt_errorch.fdwith|None->(* The socket is connected *)()|Someerr->(* An error happened: *)raise(Unix.Unix_error(err,"connect",""))elsetry(* We should pass only one time here, unless the system call
is interrupted by a signal: *)Unix.connectch.fdaddrwith|Unix.Unix_error(Unix.EINPROGRESS,_,_)->in_progress:=true;raiseRetryendexternalbind_job:Unix.file_descr->Unix.sockaddr->unitjob="lwt_unix_bind_job"letbindfdaddr=check_descriptorfd;matchSys.win32,addrwith|true,_|false,Unix.ADDR_INET_->Lwt.return(Unix.bindfd.fdaddr)|false,Unix.ADDR_UNIX_->run_job(bind_jobfd.fdaddr)letlistenchcnt=check_descriptorch;Unix.listench.fdcntletgetpeernamech=check_descriptorch;Unix.getpeernamech.fdletgetsocknamech=check_descriptorch;Unix.getsocknamech.fdtypecredentials={cred_pid:int;cred_uid:int;cred_gid:int;}externalstub_get_credentials:Unix.file_descr->credentials="lwt_unix_get_credentials"letget_credentialsch=check_descriptorch;stub_get_credentialsch.fd(* +-----------------------------------------------------------------+
| Socket options |
+-----------------------------------------------------------------+ *)typesocket_bool_option=Unix.socket_bool_option=|SO_DEBUG|SO_BROADCAST|SO_REUSEADDR|SO_KEEPALIVE|SO_DONTROUTE|SO_OOBINLINE|SO_ACCEPTCONN|TCP_NODELAY|IPV6_ONLYtypesocket_int_option=Unix.socket_int_option=|SO_SNDBUF|SO_RCVBUF|SO_ERROR|SO_TYPE|SO_RCVLOWAT|SO_SNDLOWATtypesocket_optint_option=Unix.socket_optint_option=SO_LINGERtypesocket_float_option=Unix.socket_float_option=|SO_RCVTIMEO|SO_SNDTIMEOletgetsockoptchopt=check_descriptorch;Unix.getsockoptch.fdoptletsetsockoptchoptx=check_descriptorch;Unix.setsockoptch.fdoptxletgetsockopt_intchopt=check_descriptorch;Unix.getsockopt_intch.fdoptletsetsockopt_intchoptx=check_descriptorch;Unix.setsockopt_intch.fdoptxletgetsockopt_optintchopt=check_descriptorch;Unix.getsockopt_optintch.fdoptletsetsockopt_optintchoptx=check_descriptorch;Unix.setsockopt_optintch.fdoptxletgetsockopt_floatchopt=check_descriptorch;Unix.getsockopt_floatch.fdoptletsetsockopt_floatchoptx=check_descriptorch;Unix.setsockopt_floatch.fdoptxletgetsockopt_errorch=check_descriptorch;Unix.getsockopt_errorch.fd(* +-----------------------------------------------------------------+
| Multicast functions |
+-----------------------------------------------------------------+ *)externalstub_mcast_set_loop:Unix.file_descr->bool->unit="lwt_unix_mcast_set_loop"externalstub_mcast_set_ttl:Unix.file_descr->int->unit="lwt_unix_mcast_set_ttl"typemcast_action=Add|Dropexternalstub_mcast_modify_membership:Unix.file_descr->mcast_action->Unix.inet_addr->Unix.inet_addr->unit="lwt_unix_mcast_modify_membership"letmcast_set_loopchflag=check_descriptorch;stub_mcast_set_loopch.fdflagletmcast_set_ttlchttl=check_descriptorch;stub_mcast_set_ttlch.fdttlletmcast_add_membershipch?(ifname=Unix.inet_addr_any)addr=check_descriptorch;stub_mcast_modify_membershipch.fdAddifnameaddrletmcast_drop_membershipch?(ifname=Unix.inet_addr_any)addr=check_descriptorch;stub_mcast_modify_membershipch.fdDropifnameaddr(* +-----------------------------------------------------------------+
| Host and protocol databases |
+-----------------------------------------------------------------+ *)typehost_entry=Unix.host_entry={h_name:string;h_aliases:stringarray;h_addrtype:socket_domain;h_addr_list:inet_addrarray}typeprotocol_entry=Unix.protocol_entry={p_name:string;p_aliases:stringarray;p_proto:int}typeservice_entry=Unix.service_entry={s_name:string;s_aliases:stringarray;s_port:int;s_proto:string}externalgethostname_job:unit->stringjob="lwt_unix_gethostname_job"letgethostname()=ifSys.win32thenLwt.return(Unix.gethostname())elserun_job(gethostname_job())lethostent_mutex=Lwt_mutex.create()externalgethostbyname_job:string->Unix.host_entryjob="lwt_unix_gethostbyname_job"letgethostbynamename=ifSys.win32thenLwt.return(Unix.gethostbynamename)elseifLwt_config._HAVE_REENTRANT_HOSTENTthenrun_job(gethostbyname_jobname)elseLwt_mutex.with_lockhostent_mutex(fun()->run_job(gethostbyname_jobname))externalgethostbyaddr_job:Unix.inet_addr->Unix.host_entryjob="lwt_unix_gethostbyaddr_job"letgethostbyaddraddr=ifSys.win32thenLwt.return(Unix.gethostbyaddraddr)elseifLwt_config._HAVE_REENTRANT_HOSTENTthenrun_job(gethostbyaddr_jobaddr)elseLwt_mutex.with_lockhostent_mutex(fun()->run_job(gethostbyaddr_jobaddr))letprotoent_mutex=ifSys.win32||Lwt_config._HAVE_NETDB_REENTRANTthenhostent_mutexelseLwt_mutex.create()externalgetprotobyname_job:string->Unix.protocol_entryjob="lwt_unix_getprotobyname_job"letgetprotobynamename=ifSys.win32thenLwt.return(Unix.getprotobynamename)elseifLwt_config._HAVE_NETDB_REENTRANTthenrun_job(getprotobyname_jobname)elseLwt_mutex.with_lockprotoent_mutex(fun()->run_job(getprotobyname_jobname))externalgetprotobynumber_job:int->Unix.protocol_entryjob="lwt_unix_getprotobynumber_job"letgetprotobynumbernumber=ifSys.win32thenLwt.return(Unix.getprotobynumbernumber)elseifLwt_config._HAVE_NETDB_REENTRANTthenrun_job(getprotobynumber_jobnumber)elseLwt_mutex.with_lockprotoent_mutex(fun()->run_job(getprotobynumber_jobnumber))(* TODO: Not used anywhere, and that might be a bug. *)let_servent_mutex=ifSys.win32||Lwt_config._HAVE_NETDB_REENTRANTthenhostent_mutexelseLwt_mutex.create()externalgetservbyname_job:string->string->Unix.service_entryjob="lwt_unix_getservbyname_job"letgetservbynamenamex=ifSys.win32thenLwt.return(Unix.getservbynamenamex)elseifLwt_config._HAVE_NETDB_REENTRANTthenrun_job(getservbyname_jobnamex)elseLwt_mutex.with_lockprotoent_mutex(fun()->run_job(getservbyname_jobnamex))externalgetservbyport_job:int->string->Unix.service_entryjob="lwt_unix_getservbyport_job"letgetservbyportportx=ifSys.win32thenLwt.return(Unix.getservbyportportx)elseifLwt_config._HAVE_NETDB_REENTRANTthenrun_job(getservbyport_jobportx)elseLwt_mutex.with_lockprotoent_mutex(fun()->run_job(getservbyport_jobportx))typeaddr_info=Unix.addr_info={ai_family:socket_domain;ai_socktype:socket_type;ai_protocol:int;ai_addr:sockaddr;ai_canonname:string;}typegetaddrinfo_option=Unix.getaddrinfo_option=|AI_FAMILYofsocket_domain|AI_SOCKTYPEofsocket_type|AI_PROTOCOLofint|AI_NUMERICHOST|AI_CANONNAME|AI_PASSIVEexternalgetaddrinfo_job:string->string->Unix.getaddrinfo_optionlist->Unix.addr_infolistjob="lwt_unix_getaddrinfo_job"letgetaddrinfohostserviceopts=ifSys.win32thenLwt.return(Unix.getaddrinfohostserviceopts)elserun_job(getaddrinfo_jobhostserviceopts)>>=funl->Lwt.return(List.revl)typename_info=Unix.name_info={ni_hostname:string;ni_service:string;}typegetnameinfo_option=Unix.getnameinfo_option=|NI_NOFQDN|NI_NUMERICHOST|NI_NAMEREQD|NI_NUMERICSERV|NI_DGRAMexternalgetnameinfo_job:Unix.sockaddr->Unix.getnameinfo_optionlist->Unix.name_infojob="lwt_unix_getnameinfo_job"letgetnameinfoaddropts=ifSys.win32thenLwt.return(Unix.getnameinfoaddropts)elserun_job(getnameinfo_jobaddropts)(* +-----------------------------------------------------------------+
| Terminal interface |
+-----------------------------------------------------------------+ *)typeterminal_io=Unix.terminal_io={mutablec_ignbrk:bool;mutablec_brkint:bool;mutablec_ignpar:bool;mutablec_parmrk:bool;mutablec_inpck:bool;mutablec_istrip:bool;mutablec_inlcr:bool;mutablec_igncr:bool;mutablec_icrnl:bool;mutablec_ixon:bool;mutablec_ixoff:bool;mutablec_opost:bool;mutablec_obaud:int;mutablec_ibaud:int;mutablec_csize:int;mutablec_cstopb:int;mutablec_cread:bool;mutablec_parenb:bool;mutablec_parodd:bool;mutablec_hupcl:bool;mutablec_clocal:bool;mutablec_isig:bool;mutablec_icanon:bool;mutablec_noflsh:bool;mutablec_echo:bool;mutablec_echoe:bool;mutablec_echok:bool;mutablec_echonl:bool;mutablec_vintr:char;mutablec_vquit:char;mutablec_verase:char;mutablec_vkill:char;mutablec_veof:char;mutablec_veol:char;mutablec_vmin:int;mutablec_vtime:int;mutablec_vstart:char;mutablec_vstop:char;}typesetattr_when=Unix.setattr_when=|TCSANOW|TCSADRAIN|TCSAFLUSHtypeflush_queue=Unix.flush_queue=|TCIFLUSH|TCOFLUSH|TCIOFLUSHtypeflow_action=Unix.flow_action=|TCOOFF|TCOON|TCIOFF|TCIONexternaltcgetattr_job:Unix.file_descr->Unix.terminal_iojob="lwt_unix_tcgetattr_job"lettcgetattrch=check_descriptorch;ifSys.win32thenLwt.return(Unix.tcgetattrch.fd)elserun_job(tcgetattr_jobch.fd)externaltcsetattr_job:Unix.file_descr->Unix.setattr_when->Unix.terminal_io->unitjob="lwt_unix_tcsetattr_job"lettcsetattrchwhen_attrs=check_descriptorch;ifSys.win32thenLwt.return(Unix.tcsetattrch.fdwhen_attrs)elserun_job(tcsetattr_jobch.fdwhen_attrs)lettcsendbreakchdelay=check_descriptorch;ifSys.win32thenLwt.return(Unix.tcsendbreakch.fddelay)elserun_job(Jobs.tcsendbreak_jobch.fddelay)lettcdrainch=check_descriptorch;ifSys.win32thenLwt.return(Unix.tcdrainch.fd)elserun_job(Jobs.tcdrain_jobch.fd)lettcflushchq=check_descriptorch;ifSys.win32thenLwt.return(Unix.tcflushch.fdq)elserun_job(Jobs.tcflush_jobch.fdq)lettcflowchact=check_descriptorch;ifSys.win32thenLwt.return(Unix.tcflowch.fdact)elserun_job(Jobs.tcflow_jobch.fdact)(* +-----------------------------------------------------------------+
| Reading notifications |
+-----------------------------------------------------------------+ *)externalinit_notification:unit->Unix.file_descr="lwt_unix_init_notification"externalsend_notification:int->unit="lwt_unix_send_notification_stub"externalrecv_notifications:unit->intarray="lwt_unix_recv_notifications"lethandle_notifications_=(* Process available notifications. *)Array.itercall_notification(recv_notifications())letevent_notifications=ref(Lwt_engine.on_readable(init_notification())handle_notifications)(* +-----------------------------------------------------------------+
| Signals |
+-----------------------------------------------------------------+ *)externalset_signal:int->int->unit="lwt_unix_set_signal"externalremove_signal:int->unit="lwt_unix_remove_signal"externalinit_signals:unit->unit="lwt_unix_init_signals"let()=init_signals()moduleSignal_map=Map.Make(structtypet=intletcompareab=a-bend)typesignal_handler={sh_num:int;sh_node:(signal_handler_id->int->unit)Lwt_sequence.node;}andsignal_handler_id=signal_handleroptionrefletsignals=refSignal_map.emptyletsignal_count()=Signal_map.fold(fun_signum(_id,actions)len->len+Lwt_sequence.lengthactions)!signals0leton_signal_fullsignumhandler=letid=refNoneinlet_,actions=trySignal_map.findsignum!signalswithNot_found->letactions=Lwt_sequence.create()inletnotification=make_notification(fun()->Lwt_sequence.iter_l(funf->fidsignum)actions)in(tryset_signalsignumnotificationwithexn->stop_notificationnotification;raiseexn);signals:=Signal_map.addsignum(notification,actions)!signals;(notification,actions)inletnode=Lwt_sequence.add_rhandleractionsinid:=Some{sh_num=signum;sh_node=node};idleton_signalsignumf=on_signal_fullsignum(fun_idnum->fnum)letdisable_signal_handlerid=match!idwith|None->()|Somesh->id:=None;Lwt_sequence.removesh.sh_node;letnotification,actions=Signal_map.findsh.sh_num!signalsinifLwt_sequence.is_emptyactionsthenbeginremove_signalsh.sh_num;signals:=Signal_map.removesh.sh_num!signals;stop_notificationnotificationendletreinstall_signal_handlersignum=matchtrySome(Signal_map.findsignum!signals)withNot_found->Nonewith|Some(notification,_)->set_signalsignumnotification|None->()(* +-----------------------------------------------------------------+
| Processes |
+-----------------------------------------------------------------+ *)externalreset_after_fork:unit->unit="lwt_unix_reset_after_fork"letfork()=matchUnix.fork()with|0->(* Reset threading. *)reset_after_fork();(* Stop the old event for notifications. *)Lwt_engine.stop_event!event_notifications;(* Reinitialise the notification system. *)event_notifications:=Lwt_engine.on_readable(init_notification())handle_notifications;(* Collect all pending jobs. *)letl=Lwt_sequence.fold_l(fun(_,f)l->f::l)jobs[]in(* Remove them all. *)Lwt_sequence.iter_node_lLwt_sequence.removejobs;(* And cancel them all. We yield first so that if the program
do an exec just after, it won't be executed. *)Lwt.on_termination(Lwt_main.yield())(fun()->List.iter(funf->fLwt.Canceled)l);0|pid->pidtypeprocess_status=Unix.process_status=|WEXITEDofint|WSIGNALEDofint|WSTOPPEDofinttypewait_flag=Unix.wait_flag=|WNOHANG|WUNTRACEDtyperesource_usage={ru_utime:float;ru_stime:float}lethas_wait4=notSys.win32externalstub_wait4:Unix.wait_flaglist->int->int*Unix.process_status*resource_usage="lwt_unix_wait4"letdo_wait4flagspid=ifSys.win32thenletpid,status=Unix.waitpidflagspidin(pid,status,{ru_utime=0.0;ru_stime=0.0})elsestub_wait4flagspidletwait_children=Lwt_sequence.create()letwait_count()=Lwt_sequence.lengthwait_childrenlet()=ifnotSys.win32thenignorebeginon_signalSys.sigchld(fun_->Lwt_sequence.iter_node_lbeginfunnode->letwakener,flags,pid=Lwt_sequence.getnodeintrylet(pid',_,_)asv=do_wait4flagspidinifpid'<>0thenbeginLwt_sequence.removenode;Lwt.wakeupwakenervendwithe->Lwt_sequence.removenode;Lwt.wakeup_exnwakenereendwait_children)endlet_waitpidflagspid=Lwt.catch(fun()->Lwt.return(Unix.waitpidflagspid))Lwt.failletwaitpid=ifSys.win32then_waitpidelsefunflagspid->ifList.memUnix.WNOHANGflagsthen_waitpidflagspidelseletflags=Unix.WNOHANG::flagsin_waitpidflagspid>>=fun((pid',_)asres)->ifpid'<>0thenLwt.returnreselsebeginlet(res,w)=Lwt.task()inletnode=Lwt_sequence.add_l(w,flags,pid)wait_childreninLwt.on_cancelres(fun_->Lwt_sequence.removenode);res>>=fun(pid,status,_)->Lwt.return(pid,status)endletwait4flagspid=ifSys.win32thenLwt.return(do_wait4flagspid)elseifList.memUnix.WNOHANGflagsthenLwt.return(do_wait4flagspid)elseletflags=Unix.WNOHANG::flagsinlet(pid',_,_)asres=do_wait4flagspidinifpid'<>0thenLwt.returnreselsebeginlet(res,w)=Lwt.task()inletnode=Lwt_sequence.add_l(w,flags,pid)wait_childreninLwt.on_cancelres(fun_->Lwt_sequence.removenode);resendletwait()=waitpid[](-1)externalsystem_job:string->intjob="lwt_unix_system_job"externalsys_exit:int->'a="caml_sys_exit"letsystemcmd=ifSys.win32thenrun_job(system_job("cmd.exe /c "^cmd))>>=funcode->Lwt.return(Unix.WEXITEDcode)elsematchfork()with|0->begintryUnix.execv"/bin/sh"[|"/bin/sh";"-c";cmd|]with_->(* Do not run at_exit hooks *)sys_exit127end|id->waitpid[]id>|=snd(* +-----------------------------------------------------------------+
| Misc |
+-----------------------------------------------------------------+ *)letrun=Lwt_main.runlethandle_unix_errorfx=Lwt.catch(fun()->fx)(funexn->Unix.handle_unix_error(fun()->raiseexn)())(* +-----------------------------------------------------------------+
| System thread pool |
+-----------------------------------------------------------------+ *)[@@@ocaml.warning"-3"]externalpool_size:unit->int="lwt_unix_pool_size""noalloc"externalset_pool_size:int->unit="lwt_unix_set_pool_size""noalloc"externalthread_count:unit->int="lwt_unix_thread_count""noalloc"externalthread_waiting_count:unit->int="lwt_unix_thread_waiting_count""noalloc"[@@@ocaml.warning"+3"](* +-----------------------------------------------------------------+
| CPUs |
+-----------------------------------------------------------------+ *)externalget_cpu:unit->int="lwt_unix_get_cpu"externalstub_get_affinity:int->intlist="lwt_unix_get_affinity"externalstub_set_affinity:int->intlist->unit="lwt_unix_set_affinity"letget_affinity?(pid=0)()=stub_get_affinitypidletset_affinity?(pid=0)l=stub_set_affinitypidl(* +-----------------------------------------------------------------+
| Error printing |
+-----------------------------------------------------------------+ *)let()=Printexc.register_printer(function|Unix.Unix_error(error,func,arg)->leterror=matcherrorwith|Unix.E2BIG->"E2BIG"|Unix.EACCES->"EACCES"|Unix.EAGAIN->"EAGAIN"|Unix.EBADF->"EBADF"|Unix.EBUSY->"EBUSY"|Unix.ECHILD->"ECHILD"|Unix.EDEADLK->"EDEADLK"|Unix.EDOM->"EDOM"|Unix.EEXIST->"EEXIST"|Unix.EFAULT->"EFAULT"|Unix.EFBIG->"EFBIG"|Unix.EINTR->"EINTR"|Unix.EINVAL->"EINVAL"|Unix.EIO->"EIO"|Unix.EISDIR->"EISDIR"|Unix.EMFILE->"EMFILE"|Unix.EMLINK->"EMLINK"|Unix.ENAMETOOLONG->"ENAMETOOLONG"|Unix.ENFILE->"ENFILE"|Unix.ENODEV->"ENODEV"|Unix.ENOENT->"ENOENT"|Unix.ENOEXEC->"ENOEXEC"|Unix.ENOLCK->"ENOLCK"|Unix.ENOMEM->"ENOMEM"|Unix.ENOSPC->"ENOSPC"|Unix.ENOSYS->"ENOSYS"|Unix.ENOTDIR->"ENOTDIR"|Unix.ENOTEMPTY->"ENOTEMPTY"|Unix.ENOTTY->"ENOTTY"|Unix.ENXIO->"ENXIO"|Unix.EPERM->"EPERM"|Unix.EPIPE->"EPIPE"|Unix.ERANGE->"ERANGE"|Unix.EROFS->"EROFS"|Unix.ESPIPE->"ESPIPE"|Unix.ESRCH->"ESRCH"|Unix.EXDEV->"EXDEV"|Unix.EWOULDBLOCK->"EWOULDBLOCK"|Unix.EINPROGRESS->"EINPROGRESS"|Unix.EALREADY->"EALREADY"|Unix.ENOTSOCK->"ENOTSOCK"|Unix.EDESTADDRREQ->"EDESTADDRREQ"|Unix.EMSGSIZE->"EMSGSIZE"|Unix.EPROTOTYPE->"EPROTOTYPE"|Unix.ENOPROTOOPT->"ENOPROTOOPT"|Unix.EPROTONOSUPPORT->"EPROTONOSUPPORT"|Unix.ESOCKTNOSUPPORT->"ESOCKTNOSUPPORT"|Unix.EOPNOTSUPP->"EOPNOTSUPP"|Unix.EPFNOSUPPORT->"EPFNOSUPPORT"|Unix.EAFNOSUPPORT->"EAFNOSUPPORT"|Unix.EADDRINUSE->"EADDRINUSE"|Unix.EADDRNOTAVAIL->"EADDRNOTAVAIL"|Unix.ENETDOWN->"ENETDOWN"|Unix.ENETUNREACH->"ENETUNREACH"|Unix.ENETRESET->"ENETRESET"|Unix.ECONNABORTED->"ECONNABORTED"|Unix.ECONNRESET->"ECONNRESET"|Unix.ENOBUFS->"ENOBUFS"|Unix.EISCONN->"EISCONN"|Unix.ENOTCONN->"ENOTCONN"|Unix.ESHUTDOWN->"ESHUTDOWN"|Unix.ETOOMANYREFS->"ETOOMANYREFS"|Unix.ETIMEDOUT->"ETIMEDOUT"|Unix.ECONNREFUSED->"ECONNREFUSED"|Unix.EHOSTDOWN->"EHOSTDOWN"|Unix.EHOSTUNREACH->"EHOSTUNREACH"|Unix.ELOOP->"ELOOP"|Unix.EOVERFLOW->"EOVERFLOW"|Unix.EUNKNOWNERRn->Printf.sprintf"EUNKNOWNERR %d"ninSome(Printf.sprintf"Unix.Unix_error(Unix.%s, %S, %S)"errorfuncarg)|_->None)moduleVersioned=structletbind_1chaddr=check_descriptorch;Unix.bindch.fdaddrletbind_2=bindend