package picos

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Module Picos_structured.FinallySource

Syntax for avoiding resource leaks.

Sourcetype 'a finally = ('a -> unit) * (unit -> 'a)

A pair of release and acquire functions.

Sourceval finally : ('a -> unit) -> (unit -> 'a) -> 'a finally

finally release acquire is equivalent to (release, acquire).

Sourceval (let@) : 'a finally -> ('a -> 'b) -> 'b

let@ resource = finally release acquire in scope calls acquire () to obtain a resource, evaluates scope, and calls release resource whether scope returns normally or raises an exception.

Here is a sketch of a server that recursively forks a fiber to accept and handle a client:

  Bundle.join_after @@ fun bundle ->
  let rec accept () =
    let@ client =
      finally Unix.close @@ fun () ->
      Unix.accept ~cloexec:true socket |> fst
    in
    (* fork to accept other clients *)
    Bundle.fork bundle accept;
    (* handle this client... omitted *)
  in
  Bundle.fork bundle accept

There is also a way to move resources to allow forking fibers to handle clients without leaks.

Sourcetype 'a moveable

A moveable either contains a resource or is empty as the resource has been moved.

Sourceval (let^) : 'a finally -> ('a moveable -> 'b) -> 'b

let^ moveable = finally release acquire in scope calls acquire () to obtain a resource and stores it as a moveable resource. Then, at the end of scope, awaits that the resource is moved out of the moveable or releases the resource in case of cancelation.

Sourceval move : 'a moveable -> 'a finally

move moveable creates a pair of release and acquire functions where the acquire operation takes the resource from the moveable and the release operation releases the resource.

Here is a sketch of a server that accepts in a loop and forks fibers to handle clients:

  Bundle.join_after @@ fun bundle ->
  while true do
    (* loop to accept clients *)
    let^ client =
      finally Unix.close @@ fun () ->
      Unix.accept ~closexec:true socket |> fst
    in
    (* fork to handle this client *)
    Bundle.fork bundle @@ fun () ->
      let@ client = move client in
      (* handle client... omitted *)
  done

Another alternative to avoiding leaks is to recursively fork fibers to accept and handle a client.

  • raises Invalid_argument

    if the resource has already been moved (or released) unless the fiber has been canceled.

OCaml

Innovation. Community. Security.