nanoev/picos/Picos/Computation/index.html
2025-05-05 14:16:16 +00:00

47 lines
34 KiB
HTML
Raw Permalink 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>Computation (picos.Picos.Computation)</title><meta charset="utf-8"/><link rel="stylesheet" href="../../../_odoc-theme/odoc.css"/><meta name="generator" content="odoc 3.0.0"/><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">Index</a> &#x00BB; <a href="../../index.html">picos</a> &#x00BB; <a href="../index.html">Picos</a> &#x00BB; Computation</nav><header class="odoc-preamble"><h1>Module <code><span>Picos.Computation</span></code></h1><p>A cancelable computation.</p><p>A computation basically holds the status, i.e.</p><ul><li>running,</li><li>returned, or</li><li>canceled,</li></ul><p>of some sort of computation and most importantly allows anyone to be <a href="#val-try_attach" title="try_attach">notified</a> when the status of the computation changes from <a href="#val-is_running" title="is_running">running to completed</a>.</p><p>A hopefully enlightening analogy is that a computation is a kind of single-shot atomic <span class="xref-unresolved" title="Picos_std_event.Event">event</span>.</p><p>Another hopefully helpful analogy is that a computation is basically like a <span class="xref-unresolved" title="Picos_std_structured.Promise">cancelable promise</span> and a basic non-cancelable promise can be implemented trivially on top of a computation.</p><p>To define a computation, one first <a href="#val-create" title="create">creates</a> it and then arranges for the computation to be completed by <a href="#val-return" title="return">returning</a> a value through it or by <a href="#val-cancel" title="cancel">canceling</a> it with an exception at some point in the future. There are no restrictions on what it means for a computation to be running. The cancelation status of a computation can be polled or <a href="#val-check" title="check">checked</a> explicitly. Observers can also <a href="#val-try_attach" title="try_attach">attach</a> <a href="../Trigger/index.html" title="Trigger">triggers</a> to a computation to get a signal when the computation is completed or <a href="#val-await" title="await">await</a> the computation.</p><p>Here is an example:</p><pre class="language-ocaml"><code> run begin fun () -&gt;
Flock.join_after @@ fun () -&gt;
let computation =
Computation.create ()
in
let canceler = Flock.fork_as_promise @@ fun () -&gt;
Fiber.sleep ~seconds:1.0;
Computation.cancel computation
Exit (Printexc.get_callstack 0)
in
Flock.fork begin fun () -&gt;
let rec fib i =
Computation.check
computation;
if i &lt;= 1 then
i
else
fib (i - 1) + fib (i - 2)
in
Computation.capture computation
fib 10;
Promise.terminate canceler
end;
Computation.await computation
end</code></pre><p>A fiber is always associated with <a href="../Fiber/index.html#val-get_computation" title="Fiber.get_computation">at least a single computation</a>. However, <a href="../Fiber/index.html#val-spawn" title="Fiber.spawn">it is possible for multiple fibers to share a single computation</a> and it is also possible for a single fiber to perform multiple computations. Furthermore, the computation associated with a fiber <a href="../Fiber/index.html#val-set_computation" title="Fiber.set_computation">can be changed</a> by the fiber.</p><p>Computations are not hierarchical. In other words, computations do not directly implement structured concurrency. However, it is possible to <a href="#val-canceler" title="canceler">propagate cancelation</a> to implement structured concurrency on top of computations.</p><p>Operations on computations are either wait-free or lock-free and designed to avoid starvation and complete in amortized constant time. The properties of operations to complete a computation depend on the properties of actions <a href="../Trigger/index.html#val-on_signal" title="Trigger.on_signal">attached</a> to the triggers.</p></header><div class="odoc-tocs"><nav class="odoc-toc odoc-local-toc"><ul><li><a href="#interface-for-creating">Interface for creating</a></li><li><a href="#interface-for-canceling">Interface for canceling</a></li><li><a href="#interface-for-timeouts">Interface for timeouts</a></li><li><a href="#interface-for-polling">Interface for polling</a></li><li><a href="#interface-for-awaiting">Interface for awaiting</a></li><li><a href="#interface-for-propagating-cancelation">Interface for propagating cancelation</a></li><li><a href="#interface-for-schedulers">Interface for schedulers</a></li><li><a href="#design-rationale">Design rationale</a></li></ul></nav></div><div class="odoc-content"><h3 id="interface-for-creating"><a href="#interface-for-creating" class="anchor"></a>Interface for creating</h3><div class="odoc-spec"><div class="spec type anchored" id="type-t"><a href="#type-t" class="anchor"></a><code><span><span class="keyword">type</span> <span>!'a t</span></span></code></div><div class="spec-doc"><p>Represents a cancelable computation. A computation is either <i>running</i> or has been <i>completed</i> either with a return value or with canceling exception with a backtrace.</p><p> Once a computation becomes completed it no longer changes state.</p><p>🏎️ A computation that has been completed is a small object that only holds onto the return value or the canceling exception with a backtrace.</p><p>⚠️ In the running state a computation may refer to any number of <a href="../Trigger/index.html" title="Trigger">triggers</a> and it is important to make sure that any triggers <a href="#val-try_attach" title="try_attach">attached</a> to a computation are <a href="#val-detach" title="detach">detached</a> when they are no longer needed unless the computation has been completed.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-create"><a href="#val-create" class="anchor"></a><code><span><span class="keyword">val</span> create : <span><span class="optlabel">?mode</span>:<span>[ `FIFO <span>| `LIFO</span> ]</span> <span class="arrow">&#45;&gt;</span></span> <span>unit <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-t">t</a></span></span></code></div><div class="spec-doc"><p><code>create ()</code> creates a new computation in the running state.</p><p>The optional <code>mode</code> specifies the order in which <a href="../Trigger/index.html" title="Trigger">triggers</a> <a href="#val-try_attach" title="try_attach">attached</a> to the computation will be <a href="../Trigger/index.html#val-signal" title="Trigger.signal">signaled</a> after the computation has been completed. <code>`FIFO</code> ordering may reduce latency of IO bound computations and is the default. <code>`LIFO</code> may improve thruput of CPU bound computations and be preferable on a work-stealing scheduler, for example.</p><p> Typically the creator of a computation object arranges for the computation to be completed by using the <a href="#val-capture"><code>capture</code></a> helper, for example. However, it is possible and safe to race multiple threads of execution to complete a computation.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-returned"><a href="#val-returned" class="anchor"></a><code><span><span class="keyword">val</span> returned : <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-t">t</a></span></span></code></div><div class="spec-doc"><p><code>returned value</code> returns a constant computation that has returned the given <code>value</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-finished"><a href="#val-finished" class="anchor"></a><code><span><span class="keyword">val</span> finished : <span>unit <a href="#type-t">t</a></span></span></code></div><div class="spec-doc"><p><code>finished</code> is a constant finished computation.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_return"><a href="#val-try_return" class="anchor"></a><code><span><span class="keyword">val</span> try_return : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_return computation value</code> attempts to complete the computation with the specified <code>value</code> and returns <code>true</code> on success. Otherwise returns <code>false</code>, which means that the computation had already been completed before.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-return"><a href="#val-return" class="anchor"></a><code><span><span class="keyword">val</span> return : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>return computation value</code> is equivalent to <a href="#val-try_return" title="try_return"><code>try_return computation value |&gt; ignore</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_finish"><a href="#val-try_finish" class="anchor"></a><code><span><span class="keyword">val</span> try_finish : <span><span>unit <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_finish computation</code> is equivalent to <a href="#val-try_return" title="try_return"><code>try_return computation ()</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-finish"><a href="#val-finish" class="anchor"></a><code><span><span class="keyword">val</span> finish : <span><span>unit <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>finish computation</code> is equivalent to <a href="#val-try_finish" title="try_finish"><code>try_finish computation |&gt; ignore</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_capture"><a href="#val-try_capture" class="anchor"></a><code><span><span class="keyword">val</span> try_capture : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'b</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'b</span> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_capture computation fn x</code> calls <code>fn x</code> and tries to complete the computation with the value returned or the exception raised by the call and returns <code>true</code> on success. Otherwise returns <code>false</code>, which means that the computation had already been completed before.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-capture"><a href="#val-capture" class="anchor"></a><code><span><span class="keyword">val</span> capture : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><span class="type-var">'b</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'b</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>capture computation fn x</code> is equivalent to <a href="#val-try_capture" title="try_capture"><code>try_capture computation fn x |&gt; ignore</code></a>.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Tx"><a href="#module-Tx" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Tx/index.html">Tx</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Transactional interface for atomically completing multiple computations.</p></div></div><h3 id="interface-for-canceling"><a href="#interface-for-canceling" class="anchor"></a>Interface for canceling</h3><div class="odoc-spec"><div class="spec type anchored" id="type-packed"><a href="#type-packed" class="anchor"></a><code><span><span class="keyword">type</span> packed</span><span> = </span></code><ol><li id="type-packed.Packed" class="def variant constructor anchored"><a href="#type-packed.Packed" class="anchor"></a><code><span>| </span><span><span class="constructor">Packed</span> : <span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span> <a href="#type-packed">packed</a></span></code></li></ol></div><div class="spec-doc"><p>An existential wrapper for computations.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_cancel"><a href="#val-try_cancel" class="anchor"></a><code><span><span class="keyword">val</span> try_cancel : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span>exn <span class="arrow">&#45;&gt;</span></span> <span><a href="../../../ocaml/Stdlib/Printexc/index.html#type-raw_backtrace">Stdlib.Printexc.raw_backtrace</a> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_cancel computation exn bt</code> attempts to mark the computation as canceled with the specified exception and backtrace and returns <code>true</code> on success. Otherwise returns <code>false</code>, which means that the computation had already been completed before.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-cancel"><a href="#val-cancel" class="anchor"></a><code><span><span class="keyword">val</span> cancel : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span>exn <span class="arrow">&#45;&gt;</span></span> <span><a href="../../../ocaml/Stdlib/Printexc/index.html#type-raw_backtrace">Stdlib.Printexc.raw_backtrace</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>cancel computation exn bt</code> is equivalent to <a href="#val-try_cancel" title="try_cancel"><code>try_cancel computation exn bt |&gt; ignore</code></a>.</p></div></div><h3 id="interface-for-timeouts"><a href="#interface-for-timeouts" class="anchor"></a>Interface for timeouts</h3><div class="odoc-spec"><div class="spec value anchored" id="val-cancel_after"><a href="#val-cancel_after" class="anchor"></a><code><span><span class="keyword">val</span> cancel_after :
<span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">seconds</span>:float <span class="arrow">&#45;&gt;</span></span>
<span>exn <span class="arrow">&#45;&gt;</span></span>
<span><a href="../../../ocaml/Stdlib/Printexc/index.html#type-raw_backtrace">Stdlib.Printexc.raw_backtrace</a> <span class="arrow">&#45;&gt;</span></span>
unit</span></code></div><div class="spec-doc"><p><code>cancel_after ~seconds computation exn bt</code> arranges to <a href="#val-cancel"><code>cancel</code></a> the computation after the specified time with the specified exception and backtrace. Completion of the computation before the specified time effectively cancels the timeout.</p><p> The behavior is that <code>cancel_after</code> first checks that <code>seconds</code> is not negative, and then</p><ul><li>on OCaml 5, <code>cancel_after</code> will perform the <a href="#extension-Cancel_after"><code>Cancel_after</code></a> effect, and</li><li>on OCaml 4, <code>cancel_after</code> will call the <code>cancel_after</code> operation of the <a href="../Handler/index.html" title="Handler">current handler</a>.</li></ul><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if <code>seconds</code> is negative or too large as determined by the scheduler.</p></li></ul></div></div><h3 id="interface-for-polling"><a href="#interface-for-polling" class="anchor"></a>Interface for polling</h3><div class="odoc-spec"><div class="spec value anchored" id="val-is_running"><a href="#val-is_running" class="anchor"></a><code><span><span class="keyword">val</span> is_running : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>is_running computation</code> determines whether the computation is in the running state meaning that it has not yet been completed.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-is_canceled"><a href="#val-is_canceled" class="anchor"></a><code><span><span class="keyword">val</span> is_canceled : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>is_canceled computation</code> determines whether the computation is in the canceled state.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-canceled"><a href="#val-canceled" class="anchor"></a><code><span><span class="keyword">val</span> canceled : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span>(exn * <a href="../../../ocaml/Stdlib/Printexc/index.html#type-raw_backtrace">Stdlib.Printexc.raw_backtrace</a>)</span> option</span></span></code></div><div class="spec-doc"><p><code>canceled computation</code> returns the exception that the computation has been canceled with or returns <code>None</code> in case the computation has not been canceled.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-check"><a href="#val-check" class="anchor"></a><code><span><span class="keyword">val</span> check : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>check computation</code> is equivalent to <a href="#val-canceled" title="canceled"><code>Option.iter (fun (exn, bt) -&gt; Printexc.raise_with_backtrace exn bt) (canceled computation)</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-peek"><a href="#val-peek" class="anchor"></a><code><span><span class="keyword">val</span> peek : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, exn * <a href="../../../ocaml/Stdlib/Printexc/index.html#type-raw_backtrace">Stdlib.Printexc.raw_backtrace</a>)</span> <a href="../../../ocaml/Stdlib/index.html#type-result">result</a></span> option</span></span></code></div><div class="spec-doc"><p><code>peek computation</code> returns the result of the computation or <code>None</code> in case the computation has not completed.</p></div></div><div class="odoc-spec"><div class="spec exception anchored" id="exception-Running"><a href="#exception-Running" class="anchor"></a><code><span><span class="keyword">exception</span> </span><span><span class="exception">Running</span></span></code></div><div class="spec-doc"><p>Exception raised by <a href="#val-peek_exn"><code>peek_exn</code></a> when it's used on a still running computation. This should never be surfaced to the user.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-peek_exn"><a href="#val-peek_exn" class="anchor"></a><code><span><span class="keyword">val</span> peek_exn : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>peek_exn computation</code> returns the result of the computation or raises an exception. It is important to catch the exception. If the computation was cancelled with exception <code>exn</code> then <code>exn</code> is re-raised with its original backtrace.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <a href="#exception-Running"><code>Running</code></a> <p>if the computation has not completed.</p></li></ul></div></div><h3 id="interface-for-awaiting"><a href="#interface-for-awaiting" class="anchor"></a>Interface for awaiting</h3><div class="odoc-spec"><div class="spec value anchored" id="val-try_attach"><a href="#val-try_attach" class="anchor"></a><code><span><span class="keyword">val</span> try_attach : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><a href="../Trigger/index.html#type-t">Trigger.t</a> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_attach computation trigger</code> tries to attach the trigger to be signaled on completion of the computation and returns <code>true</code> on success. Otherwise returns <code>false</code>, which means that the computation has already been completed or the trigger has already been signaled.</p><p>⚠️ Always <a href="#val-detach"><code>detach</code></a> a trigger after it is no longer needed unless the computation is known to have been completed.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-detach"><a href="#val-detach" class="anchor"></a><code><span><span class="keyword">val</span> detach : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><a href="../Trigger/index.html#type-t">Trigger.t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>detach computation trigger</code> <a href="../Trigger/index.html#val-signal" title="Trigger.signal">signals</a> the trigger and detaches it from the computation.</p><p>🏎️ The <a href="#val-try_attach"><code>try_attach</code></a> and <code>detach</code> operations essentially implement a lock-free bag. While not formally wait-free, the implementation is designed to avoid starvation by making sure that any potentially expensive operations are performed cooperatively.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-await"><a href="#val-await" class="anchor"></a><code><span><span class="keyword">val</span> await : <span><span><span class="type-var">'a</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>await computation</code> waits for the computation to complete and either returns the value of the completed computation or raises the exception the computation was canceled with.</p><p> If the computation has already completed, then <code>await</code> returns or raises immediately without performing any effects.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-wait"><a href="#val-wait" class="anchor"></a><code><span><span class="keyword">val</span> wait : <span><span><span class="type-var">_</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>wait computation</code> waits for the computation to complete.</p></div></div><h3 id="interface-for-propagating-cancelation"><a href="#interface-for-propagating-cancelation" class="anchor"></a>Interface for propagating cancelation</h3><div class="odoc-spec"><div class="spec value anchored" id="val-canceler"><a href="#val-canceler" class="anchor"></a><code><span><span class="keyword">val</span> canceler : <span><span class="label">from</span>:<span><span class="type-var">_</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span class="label">into</span>:<span><span class="type-var">_</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <a href="../Trigger/index.html#type-t">Trigger.t</a></span></code></div><div class="spec-doc"><p><code>canceler ~from ~into</code> creates a trigger that propagates cancelation <code>from</code> one computation <code>into</code> another on <a href="Trigger.signal">signal</a>. The returned trigger is not attached to any computation.</p><p>The caller usually attaches the returned trigger to the computation <code>from</code> which cancelation is to be propagated and the trigger should usually also be detached after it is no longer needed. See also <a href="#val-attach_canceler"><code>attach_canceler</code></a>.</p><p>The intended use case of <code>canceler</code> is as a low level building block of structured concurrency mechanisms. Picos does not require concurrent programming models to be hierarchical or structured.</p><p>⚠️ The returned trigger will be in the awaiting state, which means that it is an error to call <a href="../Trigger/index.html#val-await"><code>Trigger.await</code></a> or <a href="../Trigger/index.html#val-on_signal"><code>Trigger.on_signal</code></a> on it.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-attach_canceler"><a href="#val-attach_canceler" class="anchor"></a><code><span><span class="keyword">val</span> attach_canceler : <span><span class="label">from</span>:<span><span class="type-var">_</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span class="label">into</span>:<span><span class="type-var">_</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <a href="../Trigger/index.html#type-t">Trigger.t</a></span></code></div><div class="spec-doc"><p><code>attach_canceler ~from ~into</code> tries to attach a <a href="#val-canceler"><code>canceler</code></a> to the computation <code>from</code> to propagate cancelation to the computation <code>into</code> and returns the <a href="#val-canceler"><code>canceler</code></a> when successful. If the computation <code>from</code> has already been canceled, the exception that <code>from</code> was canceled with will be raised.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if the <code>from</code> computation has already returned.</p></li></ul></div></div><h3 id="interface-for-schedulers"><a href="#interface-for-schedulers" class="anchor"></a>Interface for schedulers</h3><div class="odoc-spec"><div class="spec type extension anchored" id="extension-decl-Cancel_after"><a href="#extension-decl-Cancel_after" class="anchor"></a><code><span><span class="keyword">type</span> <a href="../../../ocaml/Stdlib/Effect/index.html#type-t">Stdlib.Effect.t</a> += <span class="keyword">private</span> </span></code><ol><li id="extension-Cancel_after" class="def variant extension anchored"><a href="#extension-Cancel_after" class="anchor"></a><code><span>| </span><span><span class="extension">Cancel_after</span> : </span><span>{</span></code><ol><li id="module-Computation.seconds" class="def record field anchored"><a href="#module-Computation.seconds" class="anchor"></a><code><span>seconds : float;</span></code><div class="def-doc"><span class="comment-delim">(*</span><p>Guaranteed to be non-negative.</p><span class="comment-delim">*)</span></div></li><li id="module-Computation.exn" class="def record field anchored"><a href="#module-Computation.exn" class="anchor"></a><code><span>exn : exn;</span></code></li><li id="module-Computation.bt" class="def record field anchored"><a href="#module-Computation.bt" class="anchor"></a><code><span>bt : <a href="../../../ocaml/Stdlib/Printexc/index.html#type-raw_backtrace">Stdlib.Printexc.raw_backtrace</a>;</span></code></li><li id="module-Computation.computation" class="def record field anchored"><a href="#module-Computation.computation" class="anchor"></a><code><span>computation : <span><span class="type-var">'a</span> <a href="#type-t">t</a></span>;</span></code></li></ol><code><span>}</span><span> <span class="arrow">&#45;&gt;</span> <span>unit <a href="../../../ocaml/Stdlib/Effect/index.html#type-t">Stdlib.Effect.t</a></span></span></code></li></ol></div><div class="spec-doc"><p>Schedulers must handle the <a href="#extension-Cancel_after"><code>Cancel_after</code></a> effect to implement the behavior of <a href="#val-cancel_after"><code>cancel_after</code></a>.</p><p>The scheduler should typically <a href="#val-try_attach" title="try_attach">attach</a> a <a href="../Trigger/index.html" title="Trigger">trigger</a> to the computation passed with the effect and arrange the timeout to be canceled upon signal to avoid space leaks.</p><p>The scheduler should measure time using a monotonic clock.</p><p>In case the fiber permits propagation of cancelation and the computation associated with the fiber has been canceled the scheduler is free to discontinue the fiber before setting up the timeout.</p><p>If the fiber is continued normally, i.e. without raising an exception, the scheduler should guarantee that the cancelation will be delivered eventually.</p><p>The scheduler is free to choose which ready fiber to resume next.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-with_action"><a href="#val-with_action" class="anchor"></a><code><span><span class="keyword">val</span> with_action :
<span><span class="optlabel">?mode</span>:<span>[ `FIFO <span>| `LIFO</span> ]</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="type-var">'x</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="type-var">'y</span> <span class="arrow">&#45;&gt;</span></span>
<span><span>(<span><a href="../Trigger/index.html#type-t">Trigger.t</a> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'x</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'y</span> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="type-var">'a</span> <a href="#type-t">t</a></span></span></code></div><div class="spec-doc"><p><code>with_action x y resume</code> is equivalent to</p><pre class="language-ocaml"><code> let computation = create () in
let trigger =
Trigger.from_action x y resume in
let _ : bool =
try_attach computation trigger in
computation</code></pre><p>⚠️ The same warnings as with <a href="../Trigger/index.html#val-from_action"><code>Trigger.from_action</code></a> apply.</p><ul class="at-tags"><li class="alert"><span class="at-tag">alert</span> handler This is an escape hatch for experts implementing schedulers or structured concurrency mechanisms. If you know what you are doing, use [@alert &quot;-handler&quot;].</li></ul></div></div><h3 id="design-rationale"><a href="#design-rationale" class="anchor"></a>Design rationale</h3><p>The main feature of the computation concept is that anyone can efficiently <a href="#val-try_attach" title="try_attach">attach</a> <a href="../Trigger/index.html" title="Trigger">triggers</a> to a computation to get notified when the status of the computation changes from running to completed and can also efficiently <a href="#val-detach" title="detach">detach</a> such triggers in case getting a notification is no longer necessary. This allows the status change to be propagated omnidirectionally and is what makes computations able to support a variety of purposes such as the implementation of <span class="xref-unresolved" title="Picos_std_structured">structured concurrency</span>.</p><p>The computation concept can be seen as a kind of single-shot atomic <span class="xref-unresolved" title="Picos_std_event.Event">event</span> that is a generalization of both a cancelation Context or token and of a <span class="xref-unresolved" title="Picos_std_structured.Promise">promise</span>. Unlike a typical promise mechanism, a computation can be canceled. Unlike a typical cancelation mechanism, a computation can and should also be completed in case it is not canceled. This promotes proper scoping of computations and resource cleanup at completion, which is how the design evolved from a more traditional cancelation context design.</p><p>Every fiber is <a href="../Fiber/index.html#val-get_computation" title="Fiber.get_computation">associated with a computation</a>. Being able to return a value through the computation means that no separate promise is necessarily required to hold the result of a fiber. On the other hand, <a href="../Fiber/index.html#val-spawn" title="Fiber.spawn">multiple fibers may share a single computation</a>. This allows multiple fibers to be canceled efficiently through a single atomic update. In other words, the design allows various higher level patterns to be implemented efficiently.</p><p>Instead of directly implementing a hierarchy of computations, the design allows <a href="#val-try_attach" title="try_attach">attach</a>ing triggers to computations and <a href="#val-canceler" title="canceler">a special trigger constructor</a> is provided for propagating cancelation. This helps to keep the implementation lean, i.e. not substantially heavier than a typical promise implementation.</p><p>Finally, just like with <a href="../Trigger/index.html#extension-Await"><code>Trigger.Await</code></a>, a key idea is that the handler of <a href="#extension-Cancel_after"><code>Computation.Cancel_after</code></a> does not need to run arbitrary user defined code. The action of any trigger attached to a computation either comes from some scheduler calling <a href="../Trigger/index.html#val-on_signal"><code>Trigger.on_signal</code></a> or from <a href="#val-canceler"><code>Computation.canceler</code></a>.</p></div></body></html>