123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167open!BaseopenImportmoduleDefinitions(C:sigmoduleMutex:sigtype'ktendmoduleRwlock:sigtype'ktendend)=structmoduletypeModule_with_mutex=sigtypekvalmutex:kC.Mutex.tendmoduletypeModule_with_rwlock=sigtypekvalrwlock:kC.Rwlock.tendendmoduletypeCapsule=sig@@portableincludemoduletypeofstructincludeCapsuleend(** Locks protecting explicit capsules which take a {!Sync.t}, and may only be held for
a bounded period of time.
The [Sync.t] capability is passed to all callbacks to allow further use of
synchronization primitives.
You should prefer the primitives exported by this module over those exported by the
[Await] module if you can, as they are easier to reason about and less likely to
lead to deadlocks *)moduleSync:sigincludemoduletypeofstructincludeDefinitions(Sync)endmoduleMutex:sigtype'kt='kSync.Mutex.t[@@@ocaml.warning"-incompatible-with-upstream"]typepacked=P:'kt->packed[@@unboxed](** Creates a mutex with a fresh existential key type. *)valcreate:unit->packed(** Like [create]. Useful in module definitions, where GADTs cannot be unpacked. *)moduleCreate():Module_with_mutex(** [with_lock s t ~f] locks [t] and runs [f], providing it access to the capsule.
The [Sync.t] is passed to [f] to allow further use of synchronization
primitives. *)valwith_lock:'k'a('b:value_or_null).Sync.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t->'a@contendedportable)@localonceportableunyielding->'a@contendedportable(** [with_lock_or_cancel s c t ~f] is [Completed (with_lock s t ~f)] if [c] is not
canceled, otherwise it is [Canceled]. *)valwith_lock_or_cancel:'k'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t->'a@contendedportable)@localonceportableunyielding->'aOr_canceled.t@contendedportable(** Functions that poison the mutex if the provided callback raises an exception. *)modulePoisoning:sig(** [with_lock s t ~f] locks [t] and runs [f], providing it access to the capsule.
The [Sync.t] is passed to [f] to allow further use of synchronization
primitives.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_lock:'k'a('b:value_or_null).Sync.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t->'a@contendedportable)@localonceportableunyielding->'a@contendedportable(** [with_lock_or_cancel s c t ~f] is [Completed (with_lock s t ~f)] if [c] is not
canceled, otherwise it is [Canceled].
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_lock_or_cancel:'k'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t->'a@contendedportable)@localonceportableunyielding->'aOr_canceled.t@contendedportableendmoduleExpert=Sync.MutexendmoduleWith_mutex:sig(** An ['a Capsule.With_mutex.t] is a value of type ['a] in its own capsule,
protected by a mutex *)type'at=|P:{data:('a,'k)Capsule.Data.t;mutex:'kMutex.t}->'at(** [create f] runs [f] within a fresh capsule, and creates a [Capsule.With_mutex.t]
containing the result *)valcreate:(unit->'a)@localonceportable->'at(** [of_owned owned] creates a [Capsule.With_mutex.t] from a value in an owned
capsule, consuming the owned capsule. *)valof_owned:'aCapsule.Owned.t@unique->'at(** [with_lock s t ~f] locks the mutex associated with [t] and calls [f] on the
protected value, returning the result. The [Sync.t] is passed to [f] to allow
further use of synchronization primitives. *)valwith_lock:'a('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'a->'b@contendedportable)@localonceportableunyielding->'b@contendedportable(** [with_lock_or_cancel s c t ~f] is [Completed (with_lock s t ~f)] if [c] is not
canceled, otherwise it is [Canceled]. *)valwith_lock_or_cancel:'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'a->'b@contendedportable)@localonceportableunyielding->'bOr_canceled.t@contendedportable(** [with_scoped sync t ~f] locks the mutex associated with [t] and calls [f] with
the provided [sync] and a [Scoped.t] for the protected data, returning the
result.
Since the provided callback does not have to be [portable], this is useful when
you need to acquire two mutexes for different capsules at the same time and move
data between them. For example:
{[
open! Core
open! Await
(* Lock both mutexes, and set the value of both refs to the maximum of their
previous values, without any data races
Make sure to always call this with locks in the same order, to avoid
deadlocks! *)
let set_to_max
: Sync.t @ local -> int ref Capsule.Sync.With_mutex.t
-> int ref Capsule.Sync.With_mutex.t -> unit
=
fun sync ref1 ref2 ->
Capsule.Sync.With_mutex.with_scoped sync ref1 ~f:(fun sync scope1 ->
Capsule.Sync.With_mutex.with_scoped sync ref2 ~f:(fun _sync scope2 ->
(* At this point we have both mutexes locked, so we can freely
manipulate the data they protect without the potential for data races *)
let value1 = Capsule.Scoped.get scope1 ~f:(fun r -> !r) in
let value2 = Capsule.Scoped.get scope2 ~f:(fun r -> !r) in
let new_value = Int.max value1 value2 in
Capsule.Scoped.iter scope1 ~f:(fun r -> r := new_value);
Capsule.Scoped.iter scope2 ~f:(fun r -> r := new_value) [@nontail])
[@nontail])
[@nontail]
;;
]} *)valwith_scoped:'a('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'aScoped.t@local->'b)@localonceunyielding->'b(** [with_scoped_or_cancel s c t ~f] is [Completed (with_scoped s t ~f)] if [c] is
not canceled, otherwise it is [Canceled]. *)valwith_scoped_or_cancel:'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'aScoped.t@local->'b)@localonceunyielding->'bOr_canceled.t(** Functions that poison the mutex if the provided callback raises an exception. *)modulePoisoning:sig(** [with_lock s t ~f] locks the mutex associated with [t] and calls [f] on the
protected value, returning the result. The [Sync.t] is passed to [f] to allow
further use of synchronization primitives.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_lock:'a('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'a->'b@contendedportable)@localonceportableunyielding->'b@contendedportable(** [with_lock_or_cancel s c t ~f] is [Completed (with_lock s t ~f)] if [c] is not
canceled, otherwise it is [Canceled].
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_lock_or_cancel:'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'a->'b@contendedportable)@localonceportableunyielding->'bOr_canceled.t@contendedportableend(** [iter s t ~f] is [with_lock s t ~f], specialised to a function that returns
[unit] *)valiter:Sync.t@local->'at->f:(Sync.t@local->'a->unit)@localonceportableunyielding->unit(** [map s t ~f] locks the mutex associated with [t] and calls [f] on the protected
value, returning a new [With_mutex.t] containing the result in the same capsule,
and protected by the same mutex. The [Sync.t] is passed to [f] to allow further
use of synchronization primitives. *)valmap:Sync.t@local->'at->f:(Sync.t@local->'a->'b)@localonceportableunyielding->'bt(** [destroy s t] poisons the mutex associated with [t], merging the protected value
into the current capsule and returning it. *)valdestroy:Sync.t@local->'at->'aendmoduleRwlock:sigtype'kt='kSync.Rwlock.t[@@@ocaml.warning"-incompatible-with-upstream"]typepacked=P:'kt->packed[@@unboxed](** Creates a reader-writer lock with a fresh existential key type. *)valcreate:unit->packed(** Like [create]. Useful in module definitions, where GADTs cannot be unpacked. *)moduleCreate():Module_with_rwlock(** [with_write s t ~f] locks [t] for writing and runs [f], providing it access to
the capsule. The [Sync.t] is passed to [f] to allow further use of
synchronization primitives. *)valwith_write:'k'a('b:value_or_null).Sync.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t->'a@contendedportable)@localonceportableunyielding->'a@contendedportable(** [with_write_or_cancel s c t ~f] is [Completed (with_write s t ~f)] if [c] is not
canceled, otherwise it is [Canceled]. *)valwith_write_or_cancel:'k'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t->'a@contendedportable)@localonceportableunyielding->'aOr_canceled.t@contendedportable(** [with_read s t ~f] locks [t] for reading and runs [f], providing it shared
access to the capsule. The [Sync.t] is passed to [f] to allow further use of
synchronization primitives. *)valwith_read:'k'a('b:value_or_null).Sync.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t@shared->'a@contendedportable)@localonceportableunyielding->'a@contendedportable(** [with_read_or_cancel s c t ~f] is [Completed (with_read s t ~f)] if [c] is not
canceled, otherwise it is [Canceled]. *)valwith_read_or_cancel:'k'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t@shared->'a@contendedportable)@localonceportableunyielding->'aOr_canceled.t@contendedportable(** Functions that poison or freeze the lock if the provided callback raises an
exception. *)modulePoisoning:sig(** [with_write s t ~f] locks [t] for writing and runs [f], providing it access to
the capsule. The [Sync.t] is passed to [f] to allow further use of
synchronization primitives.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_write:'k'a('b:value_or_null).Sync.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t->'a@contendedportable)@localonceportableunyielding->'a@contendedportable(** [with_write_or_cancel s c t ~f] is [Completed (with_write s t ~f)] if [c] is
not canceled, otherwise it is [Canceled].
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_write_or_cancel:'k'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t->'a@contendedportable)@localonceportableunyielding->'aOr_canceled.t@contendedportable(** [with_read s t ~f] locks [t] for reading and runs [f], providing it shared
access to the capsule. The [Sync.t] is passed to [f] to allow further use of
synchronization primitives.
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_read:'k'a('b:value_or_null).Sync.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t@shared->'a@contendedportable)@localonceportableunyielding->'a@contendedportable(** [with_read_or_cancel s c t ~f] is [Completed (with_read s t ~f)] if [c] is not
canceled, otherwise it is [Canceled].
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_read_or_cancel:'k'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'kt->f:(Sync.t@local->'kCapsule.Access.t@shared->'a@contendedportable)@localonceportableunyielding->'aOr_canceled.t@contendedportableendmoduleExpert=Sync.RwlockendmoduleWith_rwlock:sig(** An ['a Capsule.With_rwlock.t] is a value of type ['a] in its own capsule,
protected by a reader-writer lock *)type'at=|P:{data:('a,'k)Capsule.Data.t;rwlock:'kRwlock.t}->'at(** [create f] runs [f] within a fresh capsule, and creates a
[Capsule.With_rwlock.t] containing the result *)valcreate:(unit->'a)@localonceportable->'at(** [of_owned owned] creates a [Capsule.With_rwlock.t] from a value in an owned
capsule, consuming the owned capsule. *)valof_owned:'aCapsule.Owned.t@unique->'at(** [with_write s t ~f] locks the reader-writer lock associated with [t] for writing
and calls [f] on the protected value, returning the result. The [Sync.t] is
passed to [f] to allow further use of synchronization primitives. *)valwith_write:'a('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'a->'b@contendedportable)@localonceportableunyielding->'b@contendedportable(** [with_write_or_cancel s c t ~f] is [Completed (with_write s t ~f)] if [c] is not
canceled, otherwise it is [Canceled]. *)valwith_write_or_cancel:'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'a->'b@contendedportable)@localonceportableunyielding->'bOr_canceled.t@contendedportable(** [with_scoped s t ~f] locks the reader-writer lock associated with [t] for
writing and calls [f] with the provided [sync] and a [Scoped.t] for the
protected data, returning the result.
Since the provided callback does not have to be [portable], this is useful when
you need to acquire two mutexes for different capsules at the same time and move
data between them. See {!With_mutex.with_scoped} for an example. *)valwith_scoped:'a('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'aScoped.t@local->'b)@localonceunyielding->'b(** [with_scoped_or_cancel s c t ~f] is [Completed (with_scoped s t ~f)] if [c] is
not canceled, otherwise it is [Canceled]. *)valwith_scoped_or_cancel:'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'aScoped.t@local->'b)@localonceunyielding->'bOr_canceled.t(** [with_read s t ~f] locks the reader-writer lock associated with [t] for reading
and calls [f] on the protected value, returning the result. The [Sync.t] is
passed to [f] to allow further use of synchronization primitives. *)valwith_read:('a:valuemodportable)('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'a@shared->'b@contendedportable)@localonceportableunyielding->'b@contendedportable(** [with_read_or_cancel s c t ~f] is [Completed (with_read s t ~f)] if [c] is not
canceled, otherwise it is [Canceled]. *)valwith_read_or_cancel:('a:valuemodportable)('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'a@shared->'b@contendedportable)@localonceportableunyielding->'bOr_canceled.t@contendedportable(** [with_scoped_shared s t ~f] locks the reader-writer lock associated with [t] for
reading and calls [f] with the provided [sync] and a [Scoped.Shared.t] for the
protected data, returning the result. *)valwith_scoped_shared:('a:valuemodportable)('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'aScoped.Shared.t@forkablelocal->'b)@localonceunyielding->'b(** [with_scoped_shared_or_cancel s c t ~f] is
[Completed (with_scoped_shared s t ~f)] if [c] is not canceled, otherwise it is
[Canceled]. *)valwith_scoped_shared_or_cancel:('a:valuemodportable)('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'aScoped.Shared.t@forkablelocal->'b)@localonceunyielding->'bOr_canceled.t(** Functions that poison or freeze the lock if the provided callback raises an
exception. *)modulePoisoning:sig(** [with_write s t ~f] locks the reader-writer lock associated with [t] for
writing and calls [f] on the protected value, returning the result. The
[Sync.t] is passed to [f] to allow further use of synchronization primitives.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_write:'a('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'a->'b@contendedportable)@localonceportableunyielding->'b@contendedportable(** [with_write_or_cancel s c t ~f] is [Completed (with_write s t ~f)] if [c] is
not canceled, otherwise it is [Canceled].
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_write_or_cancel:'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'a->'b@contendedportable)@localonceportableunyielding->'bOr_canceled.t@contendedportable(** [with_scoped s t ~f] locks the reader-writer lock associated with [t] for
writing and calls [f] with the provided [sync] and a [Scoped.t] for the
protected data, returning the result. The [Sync.t] is passed to [f] to allow
further use of synchronization primitives.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_scoped:'a('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'aScoped.t@local->'b)@localonceunyielding->'b(** [with_scoped_or_cancel s c t ~f] is [Completed (with_scoped s t ~f)] if [c] is
not canceled, otherwise it is [Canceled].
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_scoped_or_cancel:'a('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'aScoped.t@local->'b)@localonceunyielding->'bOr_canceled.t(** [with_read s t ~f] locks the reader-writer lock associated with [t] for
reading and calls [f] on the protected value, returning the result. The
[Sync.t] is passed to [f] to allow further use of synchronization primitives.
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_read:('a:valuemodportable)('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'a@shared->'b@contendedportable)@localonceportableunyielding->'b@contendedportable(** [with_read_or_cancel s c t ~f] is [Completed (with_read s t ~f)] if [c] is not
canceled, otherwise it is [Canceled].
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_read_or_cancel:('a:valuemodportable)('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'a@shared->'b@contendedportable)@localonceportableunyielding->'bOr_canceled.t@contendedportable(** [with_scoped_shared s t ~f] locks the reader-writer lock associated with [t]
for reading and calls [f] with the provided [sync] and a [Scoped.Shared.t] for
the protected data, returning the result. The [Sync.t] is passed to [f] to
allow further use of synchronization primitives.
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_scoped_shared:('a:valuemodportable)('b:value_or_null).Sync.t@local->'at->f:(Sync.t@local->'aScoped.Shared.t@forkablelocal->'b)@localonceunyielding->'b(** [with_scoped_shared_or_cancel s c t ~f] is
[Completed (with_scoped_shared s t ~f)] if [c] is not canceled, otherwise it
is [Canceled].
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_scoped_shared_or_cancel:('a:valuemodportable)('b:value_or_null).Sync.t@local->Cancellation.t@local->'at->f:(Sync.t@local->'aScoped.Shared.t@forkablelocal->'b)@localonceunyielding->'bOr_canceled.tend(** [iter_write s t ~f] is [with_write s t ~f], specialised to a function that
returns [unit] *)valiter_write:Sync.t@local->'at->f:(Sync.t@local->'a->unit)@localonceportableunyielding->unit(** [iter_read s t ~f] is [with_read s t ~f], specialised to a function that returns
[unit] *)valiter_read:('a:valuemodportable).Sync.t@local->'at->f:(Sync.t@local->'a@shared->unit)@localonceportableunyielding->unitendend(** Locks protecting explicit capsules which take an {!Await.t}, and may be held for an
unbounded period of time. *)moduleAwait:sigincludemoduletypeofstructincludeDefinitions(Await)endmoduleMutex:sigtype'kt='kAwait.Mutex.t[@@@ocaml.warning"-incompatible-with-upstream"]typepacked=P:'kt->packed[@@unboxed](** Creates a mutex with a fresh existential key type. *)valcreate:unit->packed(** Like [create]. Useful in module definitions, where GADTs cannot be unpacked. *)moduleCreate():Module_with_mutex(** [with_lock await t ~f] acquires [t], runs [f] within the associated capsule
(providing it {{!Capsule.Access.t} access} to the capsule), then releases [t].
If [t] is locked, [with_lock] uses [await] to wait until it is unlocked. *)valwith_lock:'k'a('b:value_or_null).Await.t@local->'kt->f:('kCapsule.Access.t->'a@contendedportable)@localonceportable->'a@contendedportable(** [with_lock_or_cancel await c t ~f] is [Completed (with_lock await t ~f)] if [c]
is not canceled, otherwise it is [Canceled]. *)valwith_lock_or_cancel:'k'a('b:value_or_null).Await.t@local->Cancellation.t@local->'kt->f:('kCapsule.Access.t->'a@contendedportable)@localonceportable->'aOr_canceled.t@contendedportable(** Functions that poison the mutex if the provided callback raises an exception. *)modulePoisoning:sig(** [with_lock await t ~f] acquires [t], runs [f] within the associated capsule
(providing it {{!Capsule.Access.t} access} to the capsule), then releases [t].
If [t] is locked, [with_lock] uses [await] to wait until it is unlocked.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_lock:'k'a('b:value_or_null).Await.t@local->'kt->f:('kCapsule.Access.t->'a@contendedportable)@localonceportable->'a@contendedportable(** [with_lock_or_cancel await c t ~f] is [Completed (with_lock await t ~f)] if
[c] is not canceled, otherwise it is [Canceled].
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_lock_or_cancel:'k'a('b:value_or_null).Await.t@local->Cancellation.t@local->'kt->f:('kCapsule.Access.t->'a@contendedportable)@localonceportable->'aOr_canceled.t@contendedportableendmoduleExpert=Await.MutexendmoduleWith_mutex:sig(** An ['a Capsule.With_mutex.t] is a value of type ['a] in its own capsule,
protected by a mutex *)type'at=|P:{data:('a,'k)Capsule.Data.t;mutex:'kMutex.t}->'at(** [create f] runs [f] within a fresh capsule, and creates a [Capsule.With_mutex.t]
containing the result *)valcreate:(unit->'a)@localonceportable->'at(** [of_owned owned] creates a [Capsule.With_mutex.t] from a value in an owned
capsule, consuming the owned capsule. *)valof_owned:'aCapsule.Owned.t@unique->'at(** [with_lock await t ~f] locks the mutex associated with [t] and calls [f] on the
protected value, returning the result. If [t] is locked, [with_lock] uses
[await] to wait until it is unlocked. *)valwith_lock:'a('b:value_or_null).Await.t@local->'at->f:('a->'b@contendedportable)@localonceportable->'b@contendedportable(** [with_lock_or_cancel await c t ~f] is [Completed (with_lock await t ~f)] if [c]
is not canceled, otherwise it is [Canceled]. *)valwith_lock_or_cancel:'a('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('a->'b@contendedportable)@localonceportable->'bOr_canceled.t@contendedportable(** [with_scoped await t ~f] locks the mutex associated with [t] and calls [f] with
a [Scoped.t] for the protected data, returning the result. If [t] is locked,
[with_scoped] uses [await] to wait until it is unlocked.
Since the provided callback does not have to be [portable], this is useful when
you need to acquire two mutexes for different capsules at the same time and move
data between them. For example:
{[
(* Lock both mutexes, and set the value of both refs to the maximum of their
previous values, without any data races
Make sure to always call this with locks in the same order, to avoid
deadlocks! *)
let set_to_max
: Await.t @ local -> int ref Capsule.Await.With_mutex.t
-> int ref Capsule.Await.With_mutex.t -> unit
=
fun await ref1 ref2 ->
Capsule.Await.With_mutex.with_scoped await ref1 ~f:(fun guard1 ->
Capsule.Await.With_mutex.with_scoped await ref2 ~f:(fun guard2 ->
(* At this point we have both mutexes locked, so we can freely
manipulate the data they protect without the potential for data races *)
let value1 = Capsule.Scoped.get guard1 ~f:(fun r -> !r) in
let value2 = Capsule.Scoped.get guard2 ~f:(fun r -> !r) in
let new_value = Int.max value1 value2 in
Capsule.Scoped.iter guard1 ~f:(fun r -> r := new_value);
Capsule.Scoped.iter guard2 ~f:(fun r -> r := new_value) [@nontail])
[@nontail])
[@nontail]
;;
]} *)valwith_scoped:'a('b:value_or_null).Await.t@local->'at->f:('aScoped.t@local->'b)@localonce->'b(** [with_scoped_or_cancel await c t ~f] is [Completed (with_scoped await t ~f)] if
[c] is not canceled, otherwise it is [Canceled]. *)valwith_scoped_or_cancel:'a('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('aScoped.t@local->'b)@localonce->'bOr_canceled.t(** Functions that poison the mutex if the provided callback raises an exception. *)modulePoisoning:sig(** [with_lock await t ~f] locks the mutex associated with [t] and calls [f] on
the protected value, returning the result. If [t] is locked, [with_lock] uses
[await] to wait until it is unlocked.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_lock:'a('b:value_or_null).Await.t@local->'at->f:('a->'b@contendedportable)@localonceportable->'b@contendedportable(** [with_lock_or_cancel await c t ~f] is [Completed (with_lock await t ~f)] if
[c] is not canceled, otherwise it is [Canceled].
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_lock_or_cancel:'a('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('a->'b@contendedportable)@localonceportable->'bOr_canceled.t@contendedportableend(** [iter await t ~f] is [with_lock await t ~f], specialised to a function that
returns [unit] *)valiter:Await.t@local->'at->f:('a->unit)@localonceportable->unit(** [map await t ~f] locks the mutex associated with [t] and calls [f] on the
protected value, returning a new [With_mutex.t] containing the result in the
same capsule and protected by the same mutex. *)valmap:Await.t@local->'at->f:('a->'b)@localonceportable->'bt(** [destroy await t] acquires and then poisons the mutex associated with [t],
merging the protected value into the current capsule and returning it. *)valdestroy:Await.t@local->'at->'aendmoduleRwlock:sigtype'kt='kAwait.Rwlock.t[@@@ocaml.warning"-incompatible-with-upstream"]typepacked=P:'kt->packed[@@unboxed](** Creates a reader-writer lock with a fresh existential key type. *)valcreate:unit->packed(** Like [create]. Useful in module definitions, where GADTs cannot be unpacked. *)moduleCreate():Module_with_rwlock(** [with_write await t ~f] acquires [t] for writing, runs [f] within the associated
capsule (providing it {{!Capsule.Access.t} access} to the capsule), then
releases [t]. If [t] is locked, [with_write] uses [await] to wait until it is
unlocked. *)valwith_write:'k'a('b:value_or_null).Await.t@local->'kt->f:('kCapsule.Access.t->'a@contendedportable)@localonceportable->'a@contendedportable(** [with_write_or_cancel await c t ~f] is [Completed (with_write await t ~f)] if
[c] is not canceled, otherwise it is [Canceled]. *)valwith_write_or_cancel:'k'a('b:value_or_null).Await.t@local->Cancellation.t@local->'kt->f:('kCapsule.Access.t->'a@contendedportable)@localonceportable->'aOr_canceled.t@contendedportable(** [with_read await t ~f] acquires [t] for reading, runs [f] with shared
{{!Capsule.Access.t} access} to the associated capsule, then releases [t]. If
[t] is locked for writing, [with_read] uses [await] to wait until it is
unlocked. *)valwith_read:'k'a('b:value_or_null).Await.t@local->'kt->f:('kCapsule.Access.t@shared->'a@contendedportable)@localonceportable->'a@contendedportable(** [with_read_or_cancel await c t ~f] is [Completed (with_read await t ~f)] if [c]
is not canceled, otherwise it is [Canceled]. *)valwith_read_or_cancel:'k'a('b:value_or_null).Await.t@local->Cancellation.t@local->'kt->f:('kCapsule.Access.t@shared->'a@contendedportable)@localonceportable->'aOr_canceled.t@contendedportable(** Functions that poison or freeze the lock if the provided callback raises an
exception. *)modulePoisoning:sig(** [with_write await t ~f] acquires [t] for writing, runs [f] within the
associated capsule (providing it {{!Capsule.Access.t} access} to the capsule),
then releases [t]. If [t] is locked, [with_write] uses [await] to wait until
it is unlocked.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_write:'k'a('b:value_or_null).Await.t@local->'kt->f:('kCapsule.Access.t->'a@contendedportable)@localonceportable->'a@contendedportable(** [with_write_or_cancel await c t ~f] is [Completed (with_write await t ~f)] if
[c] is not canceled, otherwise it is [Canceled]. *)valwith_write_or_cancel:'k'a('b:value_or_null).Await.t@local->Cancellation.t@local->'kt->f:('kCapsule.Access.t->'a@contendedportable)@localonceportable->'aOr_canceled.t@contendedportable(** [with_read await t ~f] acquires [t] for reading, runs [f] with shared
{{!Capsule.Access.t} access} to the associated capsule, then releases [t]. If
[t] is locked for writing, [with_read] uses [await] to wait until it is
unlocked.
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_read:'k'a('b:value_or_null).Await.t@local->'kt->f:('kCapsule.Access.t@shared->'a@contendedportable)@localonceportable->'a@contendedportable(** [with_read_or_cancel await c t ~f] is [Completed (with_read await t ~f)] if
[c] is not canceled, otherwise it is [Canceled].
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_read_or_cancel:'k'a('b:value_or_null).Await.t@local->Cancellation.t@local->'kt->f:('kCapsule.Access.t@shared->'a@contendedportable)@localonceportable->'aOr_canceled.t@contendedportableendmoduleExpert=Await.RwlockendmoduleWith_rwlock:sig(** An ['a Capsule.With_rwlock.t] is a value of type ['a] in its own capsule,
protected by a reader-writer lock *)type'at=|P:{data:('a,'k)Capsule.Data.t;rwlock:'kRwlock.t}->'at(** [create f] runs [f] within a fresh capsule, and creates a
[Capsule.With_rwlock.t] containing the result *)valcreate:(unit->'a)@localonceportable->'at(** [of_owned owned] creates a [Capsule.With_rwlock.t] from a value in an owned
capsule, consuming the owned capsule. *)valof_owned:'aCapsule.Owned.t@unique->'at(** [with_write await t ~f] locks the reader-writer lock associated with [t] for
writing and calls [f] on the protected value, returning the result. If [t] is
locked, [with_write] uses [await] to wait until it is unlocked. *)valwith_write:'a('b:value_or_null).Await.t@local->'at->f:('a->'b@contendedportable)@localonceportable->'b@contendedportable(** [with_write_or_cancel await c t ~f] is [Completed (with_write await t ~f)] if
[c] is not canceled, otherwise it is [Canceled]. *)valwith_write_or_cancel:'a('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('a->'b@contendedportable)@localonceportable->'bOr_canceled.t@contendedportable(** [with_scoped await t ~f] locks the reader-writer lock associated with [t] for
writing and calls [f] with a [Scoped.t] for the protected data, returning the
result. If [t] is locked, [with_scoped] uses [await] to wait until it is
unlocked.
Since the provided callback does not have to be [portable], this is useful when
you need to acquire two mutexes for different capsules at the same time and move
data between them. See {!With_mutex.with_guard} for an example. *)valwith_scoped:'a('b:value_or_null).Await.t@local->'at->f:('aScoped.t@local->'b)@localonce->'b(** [with_scoped_or_cancel await c t ~f] is [Completed (with_scoped await t ~f)] if
[c] is not canceled, otherwise it is [Canceled]. *)valwith_scoped_or_cancel:'a('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('aScoped.t@local->'b)@localonce->'bOr_canceled.t(** [with_read await t ~f] locks the reader-writer lock associated with [t] for
reading and calls [f] on the protected value, returning the result. If [t] is
locked for writing, [with_read] uses [await] to wait until it is unlocked. *)valwith_read:('a:valuemodportable)('b:value_or_null).Await.t@local->'at->f:('a@shared->'b@contendedportable)@localonceportable->'b@contendedportable(** [with_read_or_cancel await c t ~f] is [Completed (with_read await t ~f)] if [c]
is not canceled, otherwise it is [Canceled]. *)valwith_read_or_cancel:('a:valuemodportable)('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('a@shared->'b@contendedportable)@localonceportable->'bOr_canceled.t@contendedportable(** [with_scoped_shared await t ~f] locks the reader-writer lock associated with [t]
for reading and calls [f] with a [Scoped.Shared.t] for the protected data,
returning the result. If [t] is locked for writing, [with_scoped_shared] uses
[await] to wait until it is unlocked. *)valwith_scoped_shared:('a:valuemodportable)('b:value_or_null).Await.t@local->'at->f:('aScoped.Shared.t@forkablelocal->'b)@localonce->'b(** [with_scoped_shared_or_cancel await c t ~f] is
[Completed (with_scoped_shared await t ~f)] if [c] is not canceled, otherwise it
is [Canceled]. *)valwith_scoped_shared_or_cancel:('a:valuemodportable)('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('aScoped.Shared.t@forkablelocal->'b)@localonce->'bOr_canceled.t(** Functions that poison or freeze the lock if the provided callback raises an
exception. *)modulePoisoning:sig(** [with_write await t ~f] locks the reader-writer lock associated with [t] for
writing and calls [f] on the protected value, returning the result. If [t] is
locked, [with_write] uses [await] to wait until it is unlocked.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_write:'a('b:value_or_null).Await.t@local->'at->f:('a->'b@contendedportable)@localonceportable->'b@contendedportable(** [with_write_or_cancel await c t ~f] is [Completed (with_write await t ~f)] if
[c] is not canceled, otherwise it is [Canceled].
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_write_or_cancel:'a('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('a->'b@contendedportable)@localonceportable->'bOr_canceled.t@contendedportable(** [with_scoped await t ~f] locks the reader-writer lock associated with [t] for
writing and calls [f] with a [Scoped.t] for the protected value, returning the
result. If [t] is locked, [with_scoped] uses [await] to wait until it is
unlocked.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_scoped:'a('b:value_or_null).Await.t@local->'at->f:('aScoped.t@local->'b)@localonce->'b(** [with_scoped_or_cancel await c t ~f] is [Completed (with_scoped await t ~f)]
if [c] is not canceled, or [Canceled] otherwise.
If [f] raises, [t] will be poisoned, meaning all subsequent attempts to
acquire it will raise. *)valwith_scoped_or_cancel:'a('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('aScoped.t@local->'b)@localonce->'bOr_canceled.t(** [with_read await t ~f] locks the reader-writer lock associated with [t] for
reading and calls [f] on the protected value, returning the result. If [t] is
locked for writing, [with_read] uses [await] to wait until it is unlocked.
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_read:('a:valuemodportable)('b:value_or_null).Await.t@local->'at->f:('a@shared->'b@contendedportable)@localonceportable->'b@contendedportable(** [with_read_or_cancel await c t ~f] is [Completed (with_read await t ~f)] if
[c] is not canceled, otherwise it is [Canceled].
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_read_or_cancel:('a:valuemodportable)('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('a@shared->'b@contendedportable)@localonceportable->'bOr_canceled.t@contendedportable(** [with_scoped_shared await t ~f] locks the reader-writer lock associated with
[t] for reading and calls [f] with a [Scoped.Shared.t] for the protected data,
returning the result. If [t] is locked for writing, [with_scoped_shared] uses
[await] to wait until it is unlocked.
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_scoped_shared:('a:valuemodportable)('b:value_or_null).Await.t@local->'at->f:('aScoped.Shared.t@forkablelocal->'b)@localonce->'b(** [with_scoped_shared_or_cancel await c t ~f] is
[Completed (with_scoped_shared await t ~f)] if [c] is not canceled, otherwise
it is [Canceled].
If [f] raises, [t] will be frozen, meaning all subsequent attempts to acquire
it for writing will raise. *)valwith_scoped_shared_or_cancel:('a:valuemodportable)('b:value_or_null).Await.t@local->Cancellation.t@local->'at->f:('aScoped.Shared.t@forkablelocal->'b)@localonce->'bOr_canceled.tend(** [iter_write await t ~f] is [with_write await t ~f], specialised to a function
that returns [unit]. *)valiter_write:Await.t@local->'at->f:('a->unit)@localonceportable->unit(** [iter_read await t ~f] is [with_read await t ~f], specialised to a function that
returns [unit]. *)valiter_read:('a:valuemodportable).Await.t@local->'at->f:('a@shared->unit)@localonceportable->unitendendend