123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189(* 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.Infixletenter_iter_hooks=Lwt_sequence.create()letleave_iter_hooks=Lwt_sequence.create()letyield=Lwt.pauseletabandon_yielded_and_paused()=Lwt.abandon_paused()letrunp=letrecrun_loop()=matchLwt.pollpwith|Somex->x|None->(* Call enter hooks. *)Lwt_sequence.iter_l(funf->f())enter_iter_hooks;(* Do the main loop call. *)letshould_block_waiting_for_io=Lwt.paused_count()=0inLwt_engine.itershould_block_waiting_for_io;(* Fulfill paused promises. *)Lwt.wakeup_paused();(* Call leave hooks. *)Lwt_sequence.iter_l(funf->f())leave_iter_hooks;(* Repeat. *)run_loop()inrun_loop()letrun_already_called=ref`Noletrun_already_called_mutex=Mutex.create()letfinished()=Mutex.lockrun_already_called_mutex;run_already_called:=`No;Mutex.unlockrun_already_called_mutexletrunp=(* Fail in case a call to Lwt_main.run is nested under another invocation of
Lwt_main.run. *)Mutex.lockrun_already_called_mutex;leterror_message_if_call_is_nested=match!run_already_calledwith(* `From is effectively disabled for the time being, because there is a bug,
present in all versions of OCaml supported by Lwt, where, with the
bytecode runtime, if one changes the working directory and then attempts
to retrieve the backtrace, the runtime calls [abort] at the C level and
exits the program ungracefully. It is especially likely that a daemon
would change directory before calling [Lwt_main.run], so we can't have it
retrieving the backtrace, even though a daemon is not likely to be
compiled to bytecode.
This can be addressed with detection. Starting with 4.04, there is a
type [Sys.backend_type] that could be used. *)|`Frombacktrace_string->Some(Printf.sprintf"%s\n%s\n%s""Nested calls to Lwt_main.run are not allowed""Lwt_main.run already called from:"backtrace_string)|`From_somewhere->Some("Nested calls to Lwt_main.run are not allowed")|`No->letcalled_from=(* See comment above.
if Printexc.backtrace_status () then
let backtrace =
try raise Exit
with Exit -> Printexc.get_backtrace ()
in
`From backtrace
else *)`From_somewhereinrun_already_called:=called_from;NoneinMutex.unlockrun_already_called_mutex;beginmatcherror_message_if_call_is_nestedwith|Somemessage->failwithmessage|None->()end;matchrunpwith|result->finished();result|exceptionexnwhenLwt.Exception_filter.runexn->finished();raiseexnletexit_hooks=Lwt_sequence.create()letreccall_hooks()=matchLwt_sequence.take_opt_lexit_hookswith|None->Lwt.return_unit|Somef->Lwt.catch(fun()->f())(fun_->Lwt.return_unit)>>=fun()->call_hooks()let()=at_exit(fun()->ifnot(Lwt_sequence.is_emptyexit_hooks)thenbeginLwt.abandon_wakeups();finished();run(call_hooks())end)letat_exitf=ignore(Lwt_sequence.add_lfexit_hooks)moduletypeHooks=sigtype'return_valuekindtypehookvaladd_first:(unit->unitkind)->hookvaladd_last:(unit->unitkind)->hookvalremove:hook->unitvalremove_all:unit->unitendmoduletypeHook_sequence=sigtype'return_valuekindvalsequence:(unit->unitkind)Lwt_sequence.tendmoduleWrap_hooks(Sequence:Hook_sequence)=structtype'akind='aSequence.kindtypehook=(unit->unitSequence.kind)Lwt_sequence.nodeletadd_firsthook_fn=lethook_node=Lwt_sequence.add_lhook_fnSequence.sequenceinhook_nodeletadd_lasthook_fn=lethook_node=Lwt_sequence.add_rhook_fnSequence.sequenceinhook_nodeletremovehook_node=Lwt_sequence.removehook_nodeletremove_all()=Lwt_sequence.iter_node_lLwt_sequence.removeSequence.sequenceendmoduleEnter_iter_hooks=Wrap_hooks(structtype'return_valuekind='return_valueletsequence=enter_iter_hooksend)moduleLeave_iter_hooks=Wrap_hooks(structtype'return_valuekind='return_valueletsequence=leave_iter_hooksend)moduleExit_hooks=Wrap_hooks(structtype'return_valuekind='return_valueLwt.tletsequence=exit_hooksend)