mirror of
https://github.com/c-cube/moonpool.git
synced 2025-12-08 20:25:31 -05:00
71 lines
12 KiB
HTML
71 lines
12 KiB
HTML
<!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> » 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">-></span></span> <span class="type-var">'b</span>)</span> <span class="arrow">-></span></span> <span><span class="type-var">'a</span> <span class="arrow">-></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 -> 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 -> 'a) -> '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">-></span></span> unit)</span> <span class="arrow">-></span></span> <span><span>(<span>unit <span class="arrow">-></span></span> <span class="type-var">'r</span>)</span> <span class="arrow">-></span></span> <span><span>(<span><span class="type-var">'r</span> <span class="arrow">-></span></span> <span class="type-var">'a</span>)</span> <span class="arrow">-></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">-></span></span> unit)</span> <span class="arrow">-></span></span> <span><span>(<span>unit <span class="arrow">-></span></span> <span class="type-var">'r</span>)</span> <span class="arrow">-></span></span> <span><span>(<span><span><span class="type-var">'r</span> <a href="#type-instance">instance</a></span> <span class="arrow">-></span></span> <span class="type-var">'a</span>)</span> <span class="arrow">-></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">-></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&">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">-></span></span> <span><span>(<span><span class="type-var">'r</span> <span class="arrow">-></span></span> <span class="type-var">'a</span>)</span> <span class="arrow">-></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">-></span></span> <span><span>(<span><span><span class="type-var">'r</span> <a href="#type-instance">instance</a></span> <span class="arrow">-></span></span> <span class="type-var">'a</span>)</span> <span class="arrow">-></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">-></span></span> <span><span>(<span><span class="type-var">'r</span> <span class="arrow">-></span></span> <span class="type-var">'a</span>)</span> <span class="arrow">-></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 -> 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 () ->
|
||
|
||
(* recursive server *)
|
||
let rec accept () =
|
||
let@ client_fd =
|
||
finally Unix.close @@ fun () ->
|
||
Unix.accept ~cloexec:true server_fd
|
||
|> 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 () ->
|
||
|
||
(* loop to accept clients *)
|
||
while true do
|
||
let@ client_fd =
|
||
instantiate Unix.close @@ fun () ->
|
||
Unix.accept ~cloexec:true server_fd
|
||
|> fst
|
||
in
|
||
|
||
(* fork to handle this client *)
|
||
Flock.fork @@ fun () ->
|
||
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 () ->
|
||
|
||
(* for communicating a resource *)
|
||
let shared_ivar = Ivar.create () in
|
||
|
||
(* fork a child that creates a resource *)
|
||
Flock.fork begin fun () ->
|
||
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 |> 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>
|