Module Miou.Ownership

Ownership of resources.

La propriété, c'est le vol!

Beyond the capitalist idea (even if certain libertarians would qualify the notion of private property), it is often useful to associate resources with the execution of a task in order to free them as soon as the said task is completed (abnormally or not).

Miou offers such a mechanism where the user can associate a resource 'a with a promise (with own). When the task associated with this promise is terminated, Miou will check that all the resources have been released (using disown). If this is not the case, Miou will call the "finaliser" specified by the user and fail with an "uncatchable" exception: Resource_leaked.

Note that the user must release these resources and disown. In fact, disown does not call the finaliser (which is only executed in an abnormal situation: when the task has raised an exception, when the task has been cancelled or when a resource has not been released).

The aim of this module is to ensure that when a task is completed, all resources have been released.

type t

The type of resources.

val create : finally:('a -> unit) -> 'a -> t

create ~finally v associates a value v and a finaliser to return a resource.

val check : t -> unit

check t verifies that the given resource t is owned by the current task. If a task tries to use a resource that does not belong to it, check will raise an uncatchable exception Not_owner.

val own : t -> unit

own t associates the given resource t to the current task. This way, if the current task fails abnormally, the finally function will be called.

# let show () = print_endline "Resource released!"
# @@ fun () ->
  let p = Miou.async @@ fun () ->
    let t = Miou.Ownership.create ~finally:show () in
    Miou.Ownership.own t;
    failwith "p" in
  await_exn p ;;
Resource released!
Exception: Failure "p".

NOTE: Finaliser can not perform OCaml's effects. This is because it is not "ordered" like an usual task. Using Miou functions (such as await or cancel) in the finaliser will raise an exception: Effect.Unhandled.

It is also important to note that if a task finishes abnormally, as well as freeing up the resources of that task, the resources owned by the children will also be freed up (hence the uselessness of using await or cancel).

val disown : t -> unit

disown t informs Miou that you have properly released the resource. If the current task ends well and the user has not disown the resource, Miou raises the uncatchable exception: Resource_leaked

# let show () = print_endline "Resource released!" ;;
# @@ fun () ->
  let p = Miou.async @@ fun () ->
    let t = Miou.Ownership.create ~finally:show () in
    Miou.Ownership.own t in
  await_exn p ;;
Resource released!
Exception: Miou.Resource_leak.

Note that even in this situation, Miou calls the finaliser.

val transfer : t -> unit

transfer t transfers the ownership of a resource to the parent task. It is useful when a sub-task operates to the resource owned by its parent and would like to retransfer it at the end:

exception Timeout

let with_timeout ~give sec fn =
    [ Miou.async @@ fun () -> Miou_unix.sleep sec; raise Timeout
    ; Miou.async ~give fn ] ;;

let connect socket sockaddr =
  let t = Miou_unix.Ownership.resource socket in
  with_timeout ~give:[ t ] 1.0 @@ fun () ->
  Miou_unix.Ownership.connect socket sockaddr;
  Miou.Ownership.transfer t