123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134moduleZzz=Eio_utils.Zzztypejob=|New|Exit|Job:{fn:unit->'a;enqueue:('a,Eio.Exn.with_bt)result->unit;}->job(* Mailbox with blocking semaphore *)moduleMailbox=structtypet={available:Semaphore.Binary.t;mutablecell:job;}letcreate()={available=Semaphore.Binary.makefalse;cell=New}letputmboxx=(* The Semaphore contains an atomic frontier,
therefore [cell] does not need to be an atomic *)mbox.cell<-x;Semaphore.Binary.releasembox.availablelettakembox=Semaphore.Binary.acquirembox.available;mbox.cellendmoduleFree_pool=structtypelist=|Empty|Closed|FreeofMailbox.t*listtypet=listAtomic.tletrecclose_list=function|Free(x,xs)->Mailbox.putxExit;close_listxs|Empty|Closed->()letcloset=letitems=Atomic.exchangetClosedinclose_listitemsletrecdropt=matchAtomic.gettwith|Closed|Empty->()|Free_asitems->ifAtomic.compare_and_settitemsEmptythenclose_listitemselsedroptletrecputtmbox=matchAtomic.gettwith|Closed->assertfalse|(Empty|Free_)ascurrent->letnext=Free(mbox,current)inifnot(Atomic.compare_and_settcurrentnext)thenputtmbox(* concurrent update, try again *)letmake_threadt=letmbox=Mailbox.create()inlet_thread:Thread.t=Thread.create(fun()->whiletruedomatchMailbox.takemboxwith|New->assertfalse|Exit->raiseThread.Exit|Job{fn;enqueue}->letresult=tryOk(fn())withexn->letbt=Printexc.get_raw_backtrace()inError(exn,bt)inputtmbox;(* Ensure thread is in free-pool before enqueuing. *)enqueueresultdone)()inmboxletrecget_threadt=matchAtomic.gettwith|Closed->invalid_arg"Thread pool closed!"|Empty->make_threadt|Free(mbox,next)ascurrent->ifAtomic.compare_and_settcurrentnextthenmboxelseget_threadt(* concurrent update, try again *)endtypet={free:Free_pool.t;sleep_q:Zzz.t;mutabletimeout:Zzz.Key.toption;}type_Effect.t+=Run_in_systhread:(unit->'a)->(('a,Eio.Exn.with_bt)result*t)Effect.tletterminatet=Free_pool.closet.free;Option.iter(funkey->Zzz.removet.sleep_qkey;t.timeout<-None)t.timeoutletcreate~sleep_q={free=Atomic.makeFree_pool.Empty;sleep_q;timeout=None}letruntfn=matchfn()with|x->terminatet;x|exceptionex->letbt=Printexc.get_raw_backtrace()interminatet;Printexc.raise_with_backtraceexbtletsubmitt~ctx~enqueuefn=matchEio.Private.Fiber_context.get_errorctxwith|Somee->enqueue(Error(e,Eio.Exn.empty_backtrace))|None->letmbox=Free_pool.get_threadt.freeinMailbox.putmbox(Job{fn;enqueue})letrun_in_systhread?(label="systhread")fn=Eio.Private.Trace.suspend_fiberlabel;letr,t=Effect.perform(Run_in_systhreadfn)inift.timeout=Nonethen(lettime=Mtime.add_span(Mtime_clock.now())Mtime.Span.(20*ms)|>Option.value~default:Mtime.max_stampint.timeout<-Some(Zzz.addt.sleep_qtime(Fn(fun()->Free_pool.dropt.free;t.timeout<-None))));matchrwith|Okx->x|Error(ex,bt)->Printexc.raise_with_backtraceexbt