moonpool/picos_std/Picos_std_finally/index.html
2024-09-04 16:10:21 +00:00

71 lines
12 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_finally (picos_std.Picos_std_finally)</title><meta charset="utf-8"/><link rel="stylesheet" href="../../_odoc-theme/odoc.css"/><meta name="generator" content="odoc 2.4.2"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="../index.html">Up</a> <a href="../index.html">picos_std</a> &#x00BB; Picos_std_finally</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_finally</span></code></h1><p>Syntax for avoiding resource leaks for <a href="../../picos/Picos/index.html"><code>Picos</code></a>.</p><p>A resource is something that is <i>acquired</i> and must be <i>released</i> after it is no longer needed.</p><p>We open both this library and a few other libraries</p><pre class="language-ocaml"><code>open Picos_io
open Picos_std_finally
open Picos_std_structured
open Picos_std_sync</code></pre><p>for the examples.</p></header><nav class="odoc-toc"><ul><li><a href="#api">API</a><ul><li><a href="#basics">Basics</a></li><li><a href="#instances">Instances</a></li></ul></li><li><a href="#examples">Examples</a><ul><li><a href="#recursive-server">Recursive server</a></li><li><a href="#looping-server">Looping server</a></li><li><a href="#move-resource-from-child-to-parent">Move resource from child to parent</a></li></ul></li></ul></nav><div class="odoc-content"><h2 id="api"><a href="#api" class="anchor"></a>API</h2><h3 id="basics"><a href="#basics" class="anchor"></a>Basics</h3><div class="odoc-spec"><div class="spec value anchored" id="val-let@"><a href="#val-let@" class="anchor"></a><code><span><span class="keyword">val</span> let@ : <span><span>(<span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'b</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'b</span></span></code></div><div class="spec-doc"><p><code>let@ resource = template in scope</code> is equivalent to <code>template (fun resource -&gt; scope)</code>.</p><p> You can use this binding operator with any <code>template</code> function that has a type of the form <code>('r -&gt; 'a) -&gt; 'a</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-finally"><a href="#val-finally" class="anchor"></a><code><span><span class="keyword">val</span> finally : <span><span>(<span><span class="type-var">'r</span> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>unit <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'r</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'r</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>finally release acquire scope</code> calls <code>acquire ()</code> to obtain a <code>resource</code>, calls <code>scope resource</code>, and then calls <code>release resource</code> after the scope exits.</p></div></div><h3 id="instances"><a href="#instances" class="anchor"></a>Instances</h3><div class="odoc-spec"><div class="spec type anchored" id="type-instance"><a href="#type-instance" class="anchor"></a><code><span><span class="keyword">type</span> <span>'r instance</span></span></code></div><div class="spec-doc"><p>Either contains a resource or is empty as the resource has been <a href="#val-transfer" title="transfer">transferred</a>, <a href="#val-drop" title="drop">dropped</a>, or has been <a href="#val-borrow" title="borrow">borrowed</a> temporarily.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-instantiate"><a href="#val-instantiate" class="anchor"></a><code><span><span class="keyword">val</span> instantiate : <span><span>(<span><span class="type-var">'r</span> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span>unit <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'r</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span><span class="type-var">'r</span> <a href="#type-instance">instance</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>instantiate release acquire scope</code> calls <code>acquire ()</code> to obtain a resource and stores it as an <a href="#type-instance"><code>instance</code></a>, calls <code>scope instance</code>. Then, if <code>scope</code> returns normally, awaits until the <a href="#type-instance"><code>instance</code></a> becomes empty. In case <code>scope</code> raises an exception or the fiber is canceled, the instance will be <a href="#val-drop" title="drop">dropped</a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-drop"><a href="#val-drop" class="anchor"></a><code><span><span class="keyword">val</span> drop : <span><span><span class="type-var">'r</span> <a href="#type-instance">instance</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>drop instance</code> releases the resource, if any, contained by the <a href="#type-instance"><code>instance</code></a>.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if the resource has been <span class="xref-unresolved" title="let&amp;">borrowed</span> and hasn't yet been returned.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-borrow"><a href="#val-borrow" class="anchor"></a><code><span><span class="keyword">val</span> borrow : <span><span><span class="type-var">'r</span> <a href="#type-instance">instance</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'r</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>borrow instance scope</code> borrows the <code>resource</code> stored in the <code>instance</code>, calls <code>scope resource</code>, and then returns the <code>resource</code> to the <code>instance</code> after scope exits.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if the resource has already been <a href="#val-borrow" title="borrow">borrowed</a> and hasn't yet been returned, has already been <a href="#val-drop" title="drop">dropped</a>, or has already been <a href="#val-transfer" title="transfer">transferred</a>.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-transfer"><a href="#val-transfer" class="anchor"></a><code><span><span class="keyword">val</span> transfer : <span><span><span class="type-var">'r</span> <a href="#type-instance">instance</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span><span class="type-var">'r</span> <a href="#type-instance">instance</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>transfer source</code> transfers the <code>resource</code> stored in the <code>source</code> instance into a new <code>target</code> instance, calls <code>scope target</code>. Then, if <code>scope</code> returns normally, awaits until the <code>target</code> instance becomes empty. In case <code>scope</code> raises an exception or the fiber is canceled, the <code>target</code> instance will be <a href="#val-drop" title="drop">dropped</a>.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if the resource has been <a href="#val-borrow" title="borrow">borrowed</a> and hasn't yet been returned, has already been <a href="#val-transfer" title="transfer">transferred</a>, or has been <a href="#val-drop" title="drop">dropped</a> unless the current fiber has been canceled, in which case the exception that the fiber was canceled with will be raised.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-move"><a href="#val-move" class="anchor"></a><code><span><span class="keyword">val</span> move : <span><span><span class="type-var">'r</span> <a href="#type-instance">instance</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'r</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>move instance scope</code> is equivalent to <a href="#val-transfer" title="transfer"><code>transfer instance (fun instance -&gt; borrow instance scope)</code></a>.</p></div></div><h2 id="examples"><a href="#examples" class="anchor"></a>Examples</h2><h3 id="recursive-server"><a href="#recursive-server" class="anchor"></a>Recursive server</h3><p>Here is a sketch of a server that recursively forks a fiber to accept and handle a client:</p><pre class="language-ocaml"><code>let recursive_server server_fd =
Flock.join_after @@ fun () -&gt;
(* recursive server *)
let rec accept () =
let@ client_fd =
finally Unix.close @@ fun () -&gt;
Unix.accept ~cloexec:true server_fd
|&gt; fst
in
(* fork to accept other clients *)
Flock.fork accept;
(* handle this client... omitted *)
()
in
Flock.fork accept</code></pre><h3 id="looping-server"><a href="#looping-server" class="anchor"></a>Looping server</h3><p>There is also a way to <a href="#val-move" title="move">move</a> <a href="#val-instantiate" title="instantiate">instantiated</a> resources to allow forking fibers to handle clients without leaks.</p><p>Here is a sketch of a server that accepts in a loop and forks fibers to handle clients:</p><pre class="language-ocaml"><code>let looping_server server_fd =
Flock.join_after @@ fun () -&gt;
(* loop to accept clients *)
while true do
let@ client_fd =
instantiate Unix.close @@ fun () -&gt;
Unix.accept ~cloexec:true server_fd
|&gt; fst
in
(* fork to handle this client *)
Flock.fork @@ fun () -&gt;
let@ client_fd = move client_fd in
(* handle client... omitted *)
()
done</code></pre><h3 id="move-resource-from-child-to-parent"><a href="#move-resource-from-child-to-parent" class="anchor"></a>Move resource from child to parent</h3><p>You can <a href="#val-move" title="move">move</a> an <a href="#val-instantiate" title="instantiate">instantiated</a> resource between any two fibers and <a href="#val-borrow" title="borrow">borrow</a> it before moving it. For example, you can create a resource in a child fiber, use it there, and then move it to the parent fiber:</p><pre class="language-ocaml"><code>let move_from_child_to_parent () =
Flock.join_after @@ fun () -&gt;
(* for communicating a resource *)
let shared_ivar = Ivar.create () in
(* fork a child that creates a resource *)
Flock.fork begin fun () -&gt;
let pretend_release () = ()
and pretend_acquire () = () in
(* allocate a resource *)
let@ instance =
instantiate pretend_release pretend_acquire
in
begin
(* borrow the resource *)
let@ resource = borrow instance in
(* use the resource... omitted *)
()
end;
(* send the resource to the parent *)
Ivar.fill shared_ivar instance
end;
(* await for a resource from the child and own it *)
let@ resource = Ivar.read shared_ivar |&gt; move in
(* use the resource... omitted *)
()</code></pre><p>The above uses an <a href="../Picos_std_sync/Ivar/index.html" title="Picos_std_sync.Ivar"><code>Ivar</code></a> to communicate the movable resource from the child fiber to the parent fiber. Any concurrency safe mechanism could be used.</p></div></body></html>