123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960open!CoreopenAsync_kernelopen!ImportmoduletypeS=sigtypet[@@derivingequal]valhash:t->intvalflushed:t->unitDeferred.tvalis_closed:t->boolvalflush_and_close:t->unitDeferred.tendmoduleMake(M:S)=structmoduleWeak_table=Stdlib.Weak.Make(M)letpending_actions=Bag.create()letlive_entries=Weak_table.create1letadd_pendingt~action=ifnot(M.is_closedt)then(letfinished=actiontinlettag=Bag.addpending_actionsfinishedinuponfinished(fun()->Bag.removepending_actionstag));;letlive_entries_flushed()=Weak_table.iter(add_pending~action:M.flushed)live_entries;Deferred.all_unit(Bag.to_listpending_actions);;letregisterentry=Weak_table.removelive_entriesentry;Weak_table.addlive_entriesentry;(* Historically, the finalizer for a log flushes /and/ closes it, while the shutdown
hook only flushes it. We wrap the flush_and_close in [add_pending] to make sure a
shutdown in the middle of finalization doesn't abruptly stop the flush.
We could maybe change the [at_shutdown] call to also [flush_and_close], but didn't
since closing also sets the outputs to none (which then causes the outputs to be
closed if they're finalized) and we think it may cause future writes--in
particular, potential writes in later shutdown hooks--to raise. Since [flush] was
the historical value there, we thought it was safer to keep it as-is. *)Gc.add_finalizer_exnentry(add_pending~action:M.flush_and_close);;endtype'at={register:'a->unit;live_entries_flushed:unit->unitDeferred.t}letcreate(typea)(moduleM:Swithtypet=a)=letmoduleM=Make(M)in{register=M.register;live_entries_flushed=M.live_entries_flushed};;letregistertentry=t.registerentryletlive_entries_flushedt=t.live_entries_flushed()