Module Parallel_capsule.With_mutexSource

Sourceval with_lock : 'a ('b : value_or_null). Parallel_kernel.t @ local -> 'a t -> f: (Parallel_kernel.t @ local -> ('a -> 'b @ portable contended) @ local once) @ local once portable unyielding -> 'b @ portable contended

with_lock parallel t ~f locks the mutex associated with t and calls f on the protected value with access to parallel for doing parallel work, returning the result.

Sourceval with_lock_or_cancel : 'a ('b : value_or_null). Parallel_kernel.t @ local -> Await.Cancellation.t @ local -> 'a t -> f: (Parallel_kernel.t @ local -> ('a -> 'b @ portable contended) @ local once) @ local once portable unyielding -> 'b Await.Or_canceled.t @ portable contended

with_lock_or_cancel parallel c t ~f is Completed (with_lock parallel t ~f) if c is not canceled, otherwise it is Canceled.

Sourceval with_scoped : 'a ('b : value_or_null). Parallel_kernel.t @ local -> 'a t -> f: (Parallel_kernel.t @ local -> ('a Await.Capsule.Scoped.t @ local -> 'b) @ local once) @ local once unyielding -> 'b

with_scoped parallel t ~f locks the mutex associated with t and calls f with parallel 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
    :  Parallel.t @ local -> int ref Capsule.Sync.With_mutex.t
    -> int ref Capsule.Sync.With_mutex.t -> unit
    =
    fun par ref1 ref2 ->
    Parallel.Capsule.With_mutex.with_scoped par ref1 ~f:(fun par scope1 ->
      Parallel.Capsule.With_mutex.with_scoped par ref2 ~f:(fun _par 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]
  ;;
Sourceval with_scoped_or_cancel : 'a ('b : value_or_null). Parallel_kernel.t @ local -> Await.Cancellation.t @ local -> 'a t -> f: (Parallel_kernel.t @ local -> ('a Await.Capsule.Scoped.t @ local -> 'b) @ local once) @ local once unyielding -> 'b Await.Or_canceled.t

with_scoped_or_cancel parallel c t ~f is Completed (with_scoped parallel t ~f) if c is not canceled, otherwise it is Canceled.

Sourcemodule Poisoning : sig ... end

Functions that poison the mutex if the provided callback raises an exception.