123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208openCore_kernelmoduleScheduler=Scheduler1includeDeferred0(* To avoid a space leak, it is necessary that [never] allocates a new ivar whenever it is
called. Code can bind on [never ()], so if we re-used the ivar, we could endlessly
accumulate handlers. *)letnever()=Ivar.read(Ivar.create())moduleM=Monad.Make(structincludeDeferred0letmapt~f=(* We manually inline [Deferred.create] here, because the non-flambda compiler isn't
able to optimize away the closure that would be be created. *)letresult=Ivar.create()inupont(funa->Ivar.fillresult(fa));of_ivarresult;;letmap=`Custommapend)include(M:moduletypeofstructincludeMendwithmoduleLet_syntax:=M.Let_syntax)(* We rebind all the various [return]s because the use of the [Monad.Make] functor
causes the compiler to not inline [return], and hence makes it impossible to
statically allocate constants like [return ()]. By rebinding [return] as
[Deferred0.return], the compiler can see that:
{[
return a = { Ivar.Immutable. cell = Full a } ]}
And hence, if [a] is constant, then the return is constant and can be statically
allocated. When compiling with flambda, the compiler inlines [return] and this manual
rebinding would not help; we've decided to do it anyway so that non-flambda builds
get the optimization. *)letreturn=Deferred0.returnmoduleLet_syntax=structinclude(M.Let_syntax:moduletypeofstructincludeM.Let_syntaxendwithmoduleLet_syntax:=M.Let_syntax.Let_syntax)letreturn=Deferred0.returnmoduleLet_syntax=structincludeM.Let_syntax.Let_syntaxletreturn=Deferred0.returnendendopenLet_syntax(* We shadow [all] on-purpose here, since the default definition introduces a chain of
binds as long as the list. *)letall=`Make_sure_to_define_all_elsewherelet_=allletunit=return()letignore=ignore_mletbotht1t2=create(funresult->upont1(funa1->upont2(funa2->Ivar.fillresult(a1,a2))));;moduleInfix=structincludeMonad_infixlet(>>>)=uponletppx_both=bothendopenInfixletdon't_wait_for(_:unitt)=()moduleChoice=structtype+'at=T:'bDeferred0.t*('b->'a)->'atletmap(T(t,f1))~f:f2=T(t,funx->f2(f1x))endtype'achoice='aChoice.tmoduleUnregister=struct(* This representation saves 2n words for a list of n choices. *)typet=|Nil:t|Cons:'aDeferred0.t*'aDeferred0.Handler.t*t->tletrecprocess=function|Nil->()|Cons(t,handler,rest)->remove_handlerthandler;processrest;;endletchoicetf=Choice.T(t,f)letenabledchoices=letresult=Ivar.create()inletunregisters=refUnregister.Nilinletready_=ifIvar.is_emptyresultthen(Unregister.process!unregisters;Ivar.fillresult(fun()->List.rev(List.foldchoices~init:[]~f:(funac(Choice.T(t,f))->matchpeektwith|None->ac|Somev->fv::ac))))inletexecution_context=Scheduler.(current_execution_context(t()))inunregisters:=List.foldchoices~init:Unregister.Nil~f:(funacc(Choice.T(t,_))->Cons(t,Deferred0.add_handlertreadyexecution_context,acc));Ivar.readresult;;letrecchoose_resultchoices=matchchoiceswith|[]->assertfalse|Choice.T(t,f)::choices->(matchpeektwith|None->choose_resultchoices|Somev->fv);;letchoosechoices=letresult=Ivar.create()inletunregisters=refUnregister.Nilinletready_=ifIvar.is_emptyresultthen(Unregister.process!unregisters;Ivar.fillresult(choose_resultchoices))inletexecution_context=Scheduler.(current_execution_context(t()))inunregisters:=List.foldchoices~init:Unregister.Nil~f:(funacc(Choice.T(t,_))->Cons(t,Deferred0.add_handlertreadyexecution_context,acc));Ivar.readresult;;letany_ftsf=choose(List.mapts~f:(funt->choicetf))letanyts=any_ftsFn.idletany_unitts=any_fts(Fn.ignore:unit->unit)letfor_start~to_~do_=letrecloopi=ifi>to_thenreturn()else(let%bind()=do_iinloop(i+1))inloopstart;;letrepeat_until_finishedstatef=create(funfinished->letrecloopstate=fstate>>>function|`Repeatstate->loopstate|`Finishedresult->Ivar.fillfinishedresultinloopstate);;letforeverstatef=repeat_until_finishedstate(funstate->let%mapstate=fstatein`Repeatstate)>>>never_returns;;typehow=Monad_sequence.how[@@derivingsexp_of]moduletypeMonad_sequence=Monad_sequence.Swithtype'amonad:='atletfoldt~init~f=create(funresult->letreclooptb=matchtwith|[]->Ivar.fillresultb|x::xs->fbx>>>funb->loopxsbinlooptinit);;letseqmapt~f=foldt~init:[]~f:(funbsa->fa>>|funb->b::bs)>>|List.revletallds=seqmapds~f:Fn.idletall_unitds=foldds~init:()~f:(fun()d->d)letall_ignore=all_unitletokx=x>>|funx->Okx