This commit is contained in:
c-cube 2024-09-04 16:10:21 +00:00
parent 08b446de14
commit c519fa45b8
118 changed files with 3059 additions and 43 deletions

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Backoff (backoff.Backoff)</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">backoff</a> &#x00BB; Backoff</nav><header class="odoc-preamble"><h1>Module <code><span>Backoff</span></code></h1><p>Randomized exponential backoff mechanism.</p></header><div class="odoc-content"><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> t</span></code></div><div class="spec-doc"><p>Type of backoff values.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-max_wait_log"><a href="#val-max_wait_log" class="anchor"></a><code><span><span class="keyword">val</span> max_wait_log : int</span></code></div><div class="spec-doc"><p>Logarithm of the maximum allowed value for wait.</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">?lower_wait_log</span>:int <span class="arrow">&#45;&gt;</span></span> <span><span class="optlabel">?upper_wait_log</span>:int <span class="arrow">&#45;&gt;</span></span> <span>unit <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>create</code> creates a backoff value. <code>upper_wait_log</code>, <code>lower_wait_log</code> override the logarithmic upper and lower bound on the number of spins executed by <a href="#val-once"><code>once</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-default"><a href="#val-default" class="anchor"></a><code><span><span class="keyword">val</span> default : <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>default</code> is equivalent to <code>create ()</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-once"><a href="#val-once" class="anchor"></a><code><span><span class="keyword">val</span> once : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>once b</code> executes one random wait and returns a new backoff with logarithm of the current maximum value incremented unless it is already at <code>upper_wait_log</code> of <code>b</code>.</p><p>Note that this uses the default Stdlib <code>Random</code> per-domain generator.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-reset"><a href="#val-reset" class="anchor"></a><code><span><span class="keyword">val</span> reset : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>reset b</code> returns a backoff equivalent to <code>b</code> except with current value set to the <code>lower_wait_log</code> of <code>b</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-get_wait_log"><a href="#val-get_wait_log" class="anchor"></a><code><span><span class="keyword">val</span> get_wait_log : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> int</span></code></div><div class="spec-doc"><p><code>get_wait_log b</code> returns logarithm of the maximum value of wait for next <a href="#val-once"><code>once</code></a>.</p></div></div></div></body></html>

View file

@ -0,0 +1,7 @@
# Release notes
All notable changes to this project will be documented in this file.
## 0.1.0
- Initial version based on backoff from kcas (@lyrm, @polytypic)

View file

@ -0,0 +1,16 @@
Copyright (c) 2015, Théo Laurent <theo.laurent@ens.fr>
Copyright (c) 2016, KC Sivaramakrishnan <kc@kcsrk.info>
Copyright (c) 2021, Sudha Parimala <sudharg247@gmail.com>
Copyright (c) 2023, Vesa Karvonen <vesa.a.j.k@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View file

@ -0,0 +1,94 @@
[API reference](https://ocaml-multicore.github.io/backoff/doc/backoff/Backoff/index.html)
# backoff - exponential backoff mechanism
**backoff** provides an
[exponential backoff mechanism](https://en.wikipedia.org/wiki/Exponential_backoff)
[1]. It reduces contention by making a domain back off after failing an
operation contested by another domain, like acquiring a lock or performing a
`CAS` operation.
## About contention
Contention is what happens when multiple CPU cores try to access the same
location(s) in parallel. Let's take the example of multiple CPU cores trying to
perform a `CAS` on the same location at the same time. Only one is going to
success at each round of retries. By writing on a shared location, it
invalidates all other CPUs' caches. So at each round each CPU will have to read
the memory location again, leading to quadratic O(n²) bus traffic.
## Exponential backoff
Failing to access a shared resource means there is contention: some other CPU
cores are trying to access it at the same time. To avoid quadratic bus traffic,
the idea exploited by exponential backoff is to make each CPU core wait (spin) a
random bit before retrying. This way, they will try to access the resource at a
different time: that not only strongly decreases bus traffic but that also gets
them a better chance to get the resource, at they probably will compete for it
against less other CPU cores. Failing again probably means contention is high,
and they need to wait longer. In fact, each consecutive fail of a single CPU
core will make it wait twice longer (_exponential_ backoff !).
Obviously, they cannot wait forever: there is an upper limit on the number of
times the initial waiting time can be doubled (see [Tuning](#tuning)), but
intuitively, a good waiting time should be at least around the time the
contested operation takes (in our example, the operation is a CAS) and at most a
few times that amount.
## Tuning
For better performance, backoff can be tuned. `Backoff.create` function has two
optional arguments for that: `upper_wait_log` and `lower_wait_log` that defines
the logarithmic upper and lower bound on the number of spins executed by
{!once}.
## Drawbacks
This mechanism has some drawbacks. First, it adds some delays: for example, when
a domain releases a contended lock, another domain, that has backed off after
failing acquiring it, will still have to finish its back-off loop before
retrying. Second, this increases any unfairness: any other thread that arrives
at that time or that has failed acquiring the lock for a lesser number of times
is more likely to acquire it as it will probably have a shorter waiting time.
## Example
To illustrate how to use backoff, here is a small implementation of
`test and test-and-set` spin lock [2].
```ocaml
type t = bool Atomic.t
let create () = Atomic.make false
let rec acquire ?(backoff = Backoff.detault) t =
if Atomic.get t then begin
Domain.cpu_relax ();
acquire ~backoff t
end
else if not (Atomic.compare_and_set t false true) then
acquire ~backoff:(Backoff.once backoff) t
let release t = Atomic.set t false
```
This implementation can also be found [here](bench/taslock.ml), as well as a
small [benchmark](bench/test_tas.ml) to compare it to the same TAS lock but
without backoff. It can be launched with:
```sh
dune exec ./bench/test_tas.exe > bench.data
```
and displayed (on linux) with:
```sh
gnuplot -p -e 'plot for [col=2:4] "bench.data" using 1:col with lines title columnheader'
```
## References
[1] Adaptive backoff synchronization techniques, A. Agarwal, M. Cherian (1989)
[2] Dynamic Decentralized Cache Schemes for MIMD Parallel Processors, L.Rudolf,
Z.Segall (1984)

2
backoff/index.html Normal file
View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>index (backoff.index)</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> backoff</nav><header class="odoc-preamble"><h1 id="package-backoff"><a href="#package-backoff" class="anchor"></a>Package backoff <nav><a type="text/plain; charset=UTF-8" href="_doc-dir/CHANGES.md">changes</a> <a href="#package_info">more…</a></nav></h1><ul class="modules"><li><a href="Backoff/index.html"><code>Backoff</code></a> <span class="synopsis">Randomized exponential backoff mechanism.</span></li></ul></header><nav class="odoc-toc"><ul><li><a href="#package_info">Package info</a></li></ul></nav><div class="odoc-content"><h2 id="package_info"><a href="#package_info" class="anchor"></a>Package info</h2><table class="package info"><tr id="info-changes-files"><td><a href="#info-changes-files" aria-hidden="true" class="anchor"></a>changes-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/CHANGES.md">CHANGES.md</a></li></ul></td></tr><tr id="info-license-files"><td><a href="#info-license-files" aria-hidden="true" class="anchor"></a>license-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/LICENSE.md">LICENSE.md</a></li></ul></td></tr><tr id="info-readme-files"><td><a href="#info-readme-files" aria-hidden="true" class="anchor"></a>readme-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/README.md">README.md</a></li></ul></td></tr></table></div></body></html>

View file

@ -1,2 +1,2 @@
<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="generator" content="odig v0.0.9"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" type="text/css" media="screen, print" href="_odoc-theme/odoc.css"><title>_opam</title></head><body class="odoc"><nav class="odoc-nav">🐫</nav><header class="odoc-preamble"><h1>OCaml package documentation</h1><p>Browse <a href="#by-name">by name</a>, <a href="#by-tag">by tag</a>, the <a href="ocaml/Stdlib/index.html#modules">standard library</a> and the <a href="https://ocaml.org/manual/">OCaml manual</a> (online, latest version).</p><p><small>Generated for <code>/home/runner/work/moonpool/moonpool/_opam/lib</code></small></p></header><nav class="odoc-toc"><ul><li><a href="ocaml/Stdlib/index.html#modules">OCaml standard library</a></li><li><a href="https://ocaml.org/manual/">OCaml manual</a></li><li><a href="#by-name">Packages by name</a></li><li><a href="#by-tag">Packages by tag</a></li></ul></nav><div class="odoc-content"><h2 id="by-name"><a href="#by-name" aria-hidden="true" class="anchor"></a>Packages by name</h2><div class="by-name"><nav><a href="#name-e">e</a><a href="#name-l">l</a><a href="#name-m">m</a><a href="#name-o">o</a></nav><h3 id="name-e"><a href="#name-e" aria-hidden="true" class="anchor"></a>e</h3><ol class="packages"><li id="package-either"><a href="#package-either" aria-hidden="true" class="anchor"></a><a href="either/index.html">either</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-l"><a href="#name-l" aria-hidden="true" class="anchor"></a>l</h3><ol class="packages"><li id="package-lwt"><a href="#package-lwt" aria-hidden="true" class="anchor"></a><a href="lwt/index.html">lwt</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-m"><a href="#name-m" aria-hidden="true" class="anchor"></a>m</h3><ol class="packages"><li id="package-moonpool"><a href="#package-moonpool" aria-hidden="true" class="anchor"></a><a href="moonpool/index.html">moonpool</a> <span class="version"></span> <span class="synopsis"></span></li><li id="package-moonpool-lwt"><a href="#package-moonpool-lwt" aria-hidden="true" class="anchor"></a><a href="moonpool-lwt/index.html">moonpool-lwt</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-o"><a href="#name-o" aria-hidden="true" class="anchor"></a>o</h3><ol class="packages"><li id="package-ocaml"><a href="#package-ocaml" aria-hidden="true" class="anchor"></a><a href="ocaml/index.html">ocaml</a> <span class="version"></span> <span class="synopsis"></span></li></ol></div><h2 id="by-tag"><a href="#by-tag" aria-hidden="true" class="anchor"></a>Packages by tag</h2><div class="by-tag"><nav><table></table></nav></div></div></body></html>
<html><head><meta charset="utf-8"><meta name="generator" content="odig v0.0.9"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" type="text/css" media="screen, print" href="_odoc-theme/odoc.css"><title>_opam</title></head><body class="odoc"><nav class="odoc-nav">🐫</nav><header class="odoc-preamble"><h1>OCaml package documentation</h1><p>Browse <a href="#by-name">by name</a>, <a href="#by-tag">by tag</a>, the <a href="ocaml/Stdlib/index.html#modules">standard library</a> and the <a href="https://ocaml.org/manual/">OCaml manual</a> (online, latest version).</p><p><small>Generated for <code>/home/runner/work/moonpool/moonpool/_opam/lib</code></small></p></header><nav class="odoc-toc"><ul><li><a href="ocaml/Stdlib/index.html#modules">OCaml standard library</a></li><li><a href="https://ocaml.org/manual/">OCaml manual</a></li><li><a href="#by-name">Packages by name</a></li><li><a href="#by-tag">Packages by tag</a></li></ul></nav><div class="odoc-content"><h2 id="by-name"><a href="#by-name" aria-hidden="true" class="anchor"></a>Packages by name</h2><div class="by-name"><nav><a href="#name-b">b</a><a href="#name-e">e</a><a href="#name-l">l</a><a href="#name-m">m</a><a href="#name-o">o</a><a href="#name-p">p</a><a href="#name-t">t</a></nav><h3 id="name-b"><a href="#name-b" aria-hidden="true" class="anchor"></a>b</h3><ol class="packages"><li id="package-backoff"><a href="#package-backoff" aria-hidden="true" class="anchor"></a><a href="backoff/index.html">backoff</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-e"><a href="#name-e" aria-hidden="true" class="anchor"></a>e</h3><ol class="packages"><li id="package-either"><a href="#package-either" aria-hidden="true" class="anchor"></a><a href="either/index.html">either</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-l"><a href="#name-l" aria-hidden="true" class="anchor"></a>l</h3><ol class="packages"><li id="package-lwt"><a href="#package-lwt" aria-hidden="true" class="anchor"></a><a href="lwt/index.html">lwt</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-m"><a href="#name-m" aria-hidden="true" class="anchor"></a>m</h3><ol class="packages"><li id="package-moonpool"><a href="#package-moonpool" aria-hidden="true" class="anchor"></a><a href="moonpool/index.html">moonpool</a> <span class="version"></span> <span class="synopsis"></span></li><li id="package-moonpool-lwt"><a href="#package-moonpool-lwt" aria-hidden="true" class="anchor"></a><a href="moonpool-lwt/index.html">moonpool-lwt</a> <span class="version"></span> <span class="synopsis"></span></li><li id="package-multicore-magic"><a href="#package-multicore-magic" aria-hidden="true" class="anchor"></a><a href="multicore-magic/index.html">multicore-magic</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-o"><a href="#name-o" aria-hidden="true" class="anchor"></a>o</h3><ol class="packages"><li id="package-ocaml"><a href="#package-ocaml" aria-hidden="true" class="anchor"></a><a href="ocaml/index.html">ocaml</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-p"><a href="#name-p" aria-hidden="true" class="anchor"></a>p</h3><ol class="packages"><li id="package-picos"><a href="#package-picos" aria-hidden="true" class="anchor"></a><a href="picos/index.html">picos</a> <span class="version"></span> <span class="synopsis"></span></li><li id="package-picos_std"><a href="#package-picos_std" aria-hidden="true" class="anchor"></a><a href="picos_std/index.html">picos_std</a> <span class="version"></span> <span class="synopsis"></span></li></ol><h3 id="name-t"><a href="#name-t" aria-hidden="true" class="anchor"></a>t</h3><ol class="packages"><li id="package-thread-local-storage"><a href="#package-thread-local-storage" aria-hidden="true" class="anchor"></a><a href="thread-local-storage/index.html">thread-local-storage</a> <span class="version"></span> <span class="synopsis"></span></li></ol></div><h2 id="by-tag"><a href="#by-tag" aria-hidden="true" class="anchor"></a>Packages by tag</h2><div class="by-tag"><nav><table></table></nav></div></div></body></html>

View file

@ -3,6 +3,6 @@
<span><span class="label">size</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> int)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">num_tasks</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> int)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">shutdown</span>:<span>(<span><span class="label">wait</span>:bool <span class="arrow">&#45;&gt;</span></span> <span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">run_async</span>:<span>(<span><span class="label">ls</span>:<a href="../../Task_local_storage/index.html#type-t">Task_local_storage.t</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../index.html#type-task">task</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">run_async</span>:<span>(<span><span class="label">fiber</span>:<a href="../index.html#type-fiber">fiber</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../index.html#type-task">task</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span>unit <span class="arrow">&#45;&gt;</span></span>
<a href="../index.html#type-t">t</a></span></code></div><div class="spec-doc"><p>Create a new runner.</p><p><b>NOTE</b>: the runner should support DLA and <code>Suspend_</code> on OCaml 5.x, so that <code>Fork_join</code> and other 5.x features work properly.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-k_cur_runner"><a href="#val-k_cur_runner" class="anchor"></a><code><span><span class="keyword">val</span> k_cur_runner : <span><a href="../index.html#type-t">t</a> <a href="../../../Moonpool_private/Thread_local_storage_/index.html#type-t">Moonpool_private.Thread_local_storage_.t</a></span></span></code></div><div class="spec-doc"><p>Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for <a href="../index.html#val-get_current_runner"><code>get_current_runner</code></a> to work.</p></div></div></div></body></html>
<a href="../index.html#type-t">t</a></span></code></div><div class="spec-doc"><p>Create a new runner.</p><p><b>NOTE</b>: the runner should support DLA and <code>Suspend_</code> on OCaml 5.x, so that <code>Fork_join</code> and other 5.x features work properly.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-k_cur_runner"><a href="#val-k_cur_runner" class="anchor"></a><code><span><span class="keyword">val</span> k_cur_runner : <span><a href="../index.html#type-t">t</a> <a href="../../../../thread-local-storage/Thread_local_storage/index.html#type-t">Thread_local_storage.t</a></span></span></code></div><div class="spec-doc"><p>Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for <a href="../index.html#val-get_current_runner"><code>get_current_runner</code></a> to work.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,6 +3,6 @@
<span><span class="label">size</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> int)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">num_tasks</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> int)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">shutdown</span>:<span>(<span><span class="label">wait</span>:bool <span class="arrow">&#45;&gt;</span></span> <span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">run_async</span>:<span>(<span><span class="label">ls</span>:<a href="../../Task_local_storage/index.html#type-t">Task_local_storage.t</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../index.html#type-task">task</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">run_async</span>:<span>(<span><span class="label">fiber</span>:<a href="../index.html#type-fiber">fiber</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../index.html#type-task">task</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span>unit <span class="arrow">&#45;&gt;</span></span>
<a href="../index.html#type-t">t</a></span></code></div><div class="spec-doc"><p>Create a new runner.</p><p><b>NOTE</b>: the runner should support DLA and <code>Suspend_</code> on OCaml 5.x, so that <code>Fork_join</code> and other 5.x features work properly.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-k_cur_runner"><a href="#val-k_cur_runner" class="anchor"></a><code><span><span class="keyword">val</span> k_cur_runner : <span><a href="../index.html#type-t">t</a> <a href="../../../Moonpool_private/Thread_local_storage_/index.html#type-t">Moonpool_private.Thread_local_storage_.t</a></span></span></code></div><div class="spec-doc"><p>Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for <a href="../index.html#val-get_current_runner"><code>get_current_runner</code></a> to work.</p></div></div></div></body></html>
<a href="../index.html#type-t">t</a></span></code></div><div class="spec-doc"><p>Create a new runner.</p><p><b>NOTE</b>: the runner should support DLA and <code>Suspend_</code> on OCaml 5.x, so that <code>Fork_join</code> and other 5.x features work properly.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-k_cur_runner"><a href="#val-k_cur_runner" class="anchor"></a><code><span><span class="keyword">val</span> k_cur_runner : <span><a href="../index.html#type-t">t</a> <a href="../../../../thread-local-storage/Thread_local_storage/index.html#type-t">Thread_local_storage.t</a></span></span></code></div><div class="spec-doc"><p>Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for <a href="../index.html#val-get_current_runner"><code>get_current_runner</code></a> to work.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,6 +3,6 @@
<span><span class="label">size</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> int)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">num_tasks</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> int)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">shutdown</span>:<span>(<span><span class="label">wait</span>:bool <span class="arrow">&#45;&gt;</span></span> <span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">run_async</span>:<span>(<span><span class="label">ls</span>:<a href="../../Task_local_storage/index.html#type-t">Task_local_storage.t</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../index.html#type-task">task</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">run_async</span>:<span>(<span><span class="label">fiber</span>:<a href="../index.html#type-fiber">fiber</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../index.html#type-task">task</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span>unit <span class="arrow">&#45;&gt;</span></span>
<a href="../index.html#type-t">t</a></span></code></div><div class="spec-doc"><p>Create a new runner.</p><p><b>NOTE</b>: the runner should support DLA and <code>Suspend_</code> on OCaml 5.x, so that <code>Fork_join</code> and other 5.x features work properly.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-k_cur_runner"><a href="#val-k_cur_runner" class="anchor"></a><code><span><span class="keyword">val</span> k_cur_runner : <span><a href="../index.html#type-t">t</a> <a href="../../../Moonpool_private/Thread_local_storage_/index.html#type-t">Moonpool_private.Thread_local_storage_.t</a></span></span></code></div><div class="spec-doc"><p>Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for <a href="../index.html#val-get_current_runner"><code>get_current_runner</code></a> to work.</p></div></div></div></body></html>
<a href="../index.html#type-t">t</a></span></code></div><div class="spec-doc"><p>Create a new runner.</p><p><b>NOTE</b>: the runner should support DLA and <code>Suspend_</code> on OCaml 5.x, so that <code>Fork_join</code> and other 5.x features work properly.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-k_cur_runner"><a href="#val-k_cur_runner" class="anchor"></a><code><span><span class="keyword">val</span> k_cur_runner : <span><a href="../index.html#type-t">t</a> <a href="../../../../thread-local-storage/Thread_local_storage/index.html#type-t">Thread_local_storage.t</a></span></span></code></div><div class="spec-doc"><p>Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for <a href="../index.html#val-get_current_runner"><code>get_current_runner</code></a> to work.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Direct (moonpool.Moonpool.Task_local_storage.Direct)</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">moonpool</a> &#x00BB; <a href="../../index.html">Moonpool</a> &#x00BB; <a href="../index.html">Task_local_storage</a> &#x00BB; Direct</nav><header class="odoc-preamble"><h1>Module <code><span>Task_local_storage.Direct</span></code></h1><p>Direct access to values from a storage handle</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec value anchored" id="val-get"><a href="#val-get" class="anchor"></a><code><span><span class="keyword">val</span> get : <span><a href="../index.html#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> <span><span><span class="type-var">'a</span> <a href="../index.html#type-key">key</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p>Access a key</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-set"><a href="#val-set" class="anchor"></a><code><span><span class="keyword">val</span> set : <span><a href="../index.html#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> <span><span><span class="type-var">'a</span> <a href="../index.html#type-key">key</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><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>unit <span class="arrow">&#45;&gt;</span></span> <a href="../index.html#type-t">t</a></span></code></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-copy"><a href="#val-copy" class="anchor"></a><code><span><span class="keyword">val</span> copy : <span><a href="../index.html#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> <a href="../index.html#type-t">t</a></span></code></div></div></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,6 +3,6 @@
<span><span class="label">size</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> int)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">num_tasks</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> int)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">shutdown</span>:<span>(<span><span class="label">wait</span>:bool <span class="arrow">&#45;&gt;</span></span> <span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">run_async</span>:<span>(<span><span class="label">ls</span>:<a href="../../Task_local_storage/index.html#type-t">Task_local_storage.t</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../index.html#type-task">task</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">run_async</span>:<span>(<span><span class="label">fiber</span>:<a href="../index.html#type-fiber">fiber</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../index.html#type-task">task</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span>unit <span class="arrow">&#45;&gt;</span></span>
<a href="../index.html#type-t">t</a></span></code></div><div class="spec-doc"><p>Create a new runner.</p><p><b>NOTE</b>: the runner should support DLA and <code>Suspend_</code> on OCaml 5.x, so that <code>Fork_join</code> and other 5.x features work properly.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-k_cur_runner"><a href="#val-k_cur_runner" class="anchor"></a><code><span><span class="keyword">val</span> k_cur_runner : <span><a href="../index.html#type-t">t</a> <a href="../../../Moonpool_private/Thread_local_storage_/index.html#type-t">Moonpool_private.Thread_local_storage_.t</a></span></span></code></div><div class="spec-doc"><p>Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for <a href="../index.html#val-get_current_runner"><code>get_current_runner</code></a> to work.</p></div></div></div></body></html>
<a href="../index.html#type-t">t</a></span></code></div><div class="spec-doc"><p>Create a new runner.</p><p><b>NOTE</b>: the runner should support DLA and <code>Suspend_</code> on OCaml 5.x, so that <code>Fork_join</code> and other 5.x features work properly.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-k_cur_runner"><a href="#val-k_cur_runner" class="anchor"></a><code><span><span class="keyword">val</span> k_cur_runner : <span><a href="../index.html#type-t">t</a> <a href="../../../../thread-local-storage/Thread_local_storage/index.html#type-t">Thread_local_storage.t</a></span></span></code></div><div class="spec-doc"><p>Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for <a href="../index.html#val-get_current_runner"><code>get_current_runner</code></a> to work.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,2 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool__Suspend_ (moonpool.Moonpool__Suspend_)</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">moonpool</a> &#x00BB; Moonpool__Suspend_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool__Suspend_</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool__Hmap_ls_ (moonpool.Moonpool__Hmap_ls_)</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">moonpool</a> &#x00BB; Moonpool__Hmap_ls_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool__Hmap_ls_</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool__Trigger (moonpool.Moonpool__Trigger)</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">moonpool</a> &#x00BB; Moonpool__Trigger</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool__Trigger</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool__Types_ (moonpool.Moonpool__Types_)</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">moonpool</a> &#x00BB; Moonpool__Types_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool__Types_</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -1,2 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool_private__Dla_ (moonpool.Moonpool_private__Dla_)</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">moonpool</a> &#x00BB; Moonpool_private__Dla_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_private__Dla_</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool__Worker_loop_ (moonpool.Moonpool__Worker_loop_)</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">moonpool</a> &#x00BB; Moonpool__Worker_loop_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool__Worker_loop_</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Dla_ (moonpool.Moonpool_private.Dla_)</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">moonpool</a> &#x00BB; <a href="../index.html">Moonpool_private</a> &#x00BB; Dla_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_private.Dla_</span></code></h1><p>Interface to Domain-local-await.</p><p>This is used to handle the presence or absence of DLA.</p></header><div class="odoc-content"><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> t</span><span> = </span><span>{</span></code><ol><li id="type-t.release" class="def record field anchored"><a href="#type-t.release" class="anchor"></a><code><span>release : <span>unit <span class="arrow">&#45;&gt;</span></span> unit;</span></code></li><li id="type-t.await" class="def record field anchored"><a href="#type-t.await" class="anchor"></a><code><span>await : <span>unit <span class="arrow">&#45;&gt;</span></span> unit;</span></code></li></ol><code><span>}</span></code></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-using"><a href="#val-using" class="anchor"></a><code><span><span class="keyword">val</span> using : <span><span class="label">prepare_for_await</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="label">while_running</span>:<span>(<span>unit <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><div class="odoc-spec"><div class="spec value anchored" id="val-setup_domain"><a href="#val-setup_domain" class="anchor"></a><code><span><span class="keyword">val</span> setup_domain : <span>unit <span class="arrow">&#45;&gt;</span></span> unit</span></code></div></div></div></body></html>

View file

@ -1,2 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Thread_local_storage_ (moonpool.Moonpool_private.Thread_local_storage_)</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">moonpool</a> &#x00BB; <a href="../index.html">Moonpool_private</a> &#x00BB; Thread_local_storage_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_private.Thread_local_storage_</span></code></h1><p>Thread local storage</p></header><div class="odoc-content"><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>A TLS slot for values of type <code>'a</code>. This allows the storage of a single value of type <code>'a</code> per thread.</p></div></div><div class="odoc-spec"><div class="spec exception anchored" id="exception-Not_set"><a href="#exception-Not_set" class="anchor"></a><code><span><span class="keyword">exception</span> </span><span><span class="exception">Not_set</span></span></code></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>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><div class="odoc-spec"><div class="spec value anchored" id="val-get_exn"><a href="#val-get_exn" class="anchor"></a><code><span><span class="keyword">val</span> get_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"><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <a href="#exception-Not_set"><code>Not_set</code></a> <p>if not present</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-get_opt"><a href="#val-get_opt" class="anchor"></a><code><span><span class="keyword">val</span> get_opt : <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> option</span></span></code></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-set"><a href="#val-set" class="anchor"></a><code><span><span class="keyword">val</span> set : <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></div></body></html>

View file

@ -1,2 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Ws_deque_ (moonpool.Moonpool_private.Ws_deque_)</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">moonpool</a> &#x00BB; <a href="../index.html">Moonpool_private</a> &#x00BB; Ws_deque_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_private.Ws_deque_</span></code></h1><p>Work-stealing deque.</p><p>Adapted from &quot;Dynamic circular work stealing deque&quot;, Chase &amp; Lev.</p><p>However note that this one is not dynamic in the sense that there is no resizing. Instead we return <code>false</code> when <code>push</code> fails, which keeps the implementation fairly lightweight.</p></header><div class="odoc-content"><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>Deque containing values of type <code>'a</code></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="label">dummy</span>:<span class="type-var">'a</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>Create a new deque.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-push"><a href="#val-push" class="anchor"></a><code><span><span class="keyword">val</span> push : <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>Push value at the bottom of deque. returns <code>true</code> if it succeeds. This must be called only by the owner thread.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-pop"><a href="#val-pop" class="anchor"></a><code><span><span class="keyword">val</span> pop : <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> option</span></span></code></div><div class="spec-doc"><p>Pop value from the bottom of deque. This must be called only by the owner thread.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-steal"><a href="#val-steal" class="anchor"></a><code><span><span class="keyword">val</span> steal : <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> option</span></span></code></div><div class="spec-doc"><p>Try to steal from the top of deque. This is thread-safe.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-size"><a href="#val-size" class="anchor"></a><code><span><span class="keyword">val</span> size : <span><span><span class="type-var">_</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> int</span></code></div></div></div></body></html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Ws_deque_ (moonpool.Moonpool_private.Ws_deque_)</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">moonpool</a> &#x00BB; <a href="../index.html">Moonpool_private</a> &#x00BB; Ws_deque_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_private.Ws_deque_</span></code></h1><p>Work-stealing deque.</p><p>Adapted from &quot;Dynamic circular work stealing deque&quot;, Chase &amp; Lev.</p><p>However note that this one is not dynamic in the sense that there is no resizing. Instead we return <code>false</code> when <code>push</code> fails, which keeps the implementation fairly lightweight.</p></header><div class="odoc-content"><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>Deque containing values of type <code>'a</code></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="label">dummy</span>:<span class="type-var">'a</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>Create a new deque.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-push"><a href="#val-push" class="anchor"></a><code><span><span class="keyword">val</span> push : <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>Push value at the bottom of deque. returns <code>true</code> if it succeeds. This must be called only by the owner thread.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-pop"><a href="#val-pop" class="anchor"></a><code><span><span class="keyword">val</span> pop : <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> option</span></span></code></div><div class="spec-doc"><p>Pop value from the bottom of deque. This must be called only by the owner thread.</p></div></div><div class="odoc-spec"><div class="spec exception anchored" id="exception-Empty"><a href="#exception-Empty" class="anchor"></a><code><span><span class="keyword">exception</span> </span><span><span class="exception">Empty</span></span></code></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-pop_exn"><a href="#val-pop_exn" class="anchor"></a><code><span><span class="keyword">val</span> pop_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><div class="odoc-spec"><div class="spec value anchored" id="val-steal"><a href="#val-steal" class="anchor"></a><code><span><span class="keyword">val</span> steal : <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> option</span></span></code></div><div class="spec-doc"><p>Try to steal from the top of deque. This is thread-safe.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-size"><a href="#val-size" class="anchor"></a><code><span><span class="keyword">val</span> size : <span><span><span class="type-var">_</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> int</span></code></div></div></div></body></html>

View file

@ -1,2 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool_private (moonpool.Moonpool_private)</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">moonpool</a> &#x00BB; Moonpool_private</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_private</span></code></h1></header><div class="odoc-content"><div class="odoc-spec"><div class="spec module anchored" id="module-Atomic_"><a href="#module-Atomic_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Atomic_/index.html">Atomic_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Dla_"><a href="#module-Dla_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Dla_/index.html">Dla_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Interface to Domain-local-await.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Domain_"><a href="#module-Domain_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Domain_/index.html">Domain_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Thread_local_storage_"><a href="#module-Thread_local_storage_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Thread_local_storage_/index.html">Thread_local_storage_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Thread local storage</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Tracing_"><a href="#module-Tracing_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Tracing_/index.html">Tracing_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Ws_deque_"><a href="#module-Ws_deque_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Ws_deque_/index.html">Ws_deque_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Work-stealing deque.</p></div></div></div></body></html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool_private (moonpool.Moonpool_private)</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">moonpool</a> &#x00BB; Moonpool_private</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_private</span></code></h1></header><div class="odoc-content"><div class="odoc-spec"><div class="spec module anchored" id="module-Atomic_"><a href="#module-Atomic_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Atomic_/index.html">Atomic_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Domain_"><a href="#module-Domain_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Domain_/index.html">Domain_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Tracing_"><a href="#module-Tracing_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Tracing_/index.html">Tracing_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Ws_deque_"><a href="#module-Ws_deque_" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Ws_deque_/index.html">Ws_deque_</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Work-stealing deque.</p></div></div></div></body></html>

View file

@ -1,2 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool_private__Thread_local_storage_ (moonpool.Moonpool_private__Thread_local_storage_)</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">moonpool</a> &#x00BB; Moonpool_private__Thread_local_storage_</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_private__Thread_local_storage_</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Infix (moonpool.Moonpool_sync.Event.Infix)</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">moonpool</a> &#x00BB; <a href="../../index.html">Moonpool_sync</a> &#x00BB; <a href="../index.html">Event</a> &#x00BB; Infix</nav><header class="odoc-preamble"><h1>Module <code><span>Event.Infix</span></code></h1></header><div class="odoc-content"><div class="odoc-spec"><div class="spec value anchored" id="val-(&gt;|=)"><a href="#val-(&gt;|=)" class="anchor"></a><code><span><span class="keyword">val</span> (&gt;|=) : <span><span><span class="type-var">'a</span> <a href="../index.html#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <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">'b</span> <a href="../index.html#type-t">t</a></span></span></code></div></div><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 class="type-var">'a</span> <a href="../index.html#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <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">'b</span> <a href="../index.html#type-t">t</a></span></span></code></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Lock (moonpool.Moonpool_sync.Lock)</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">moonpool</a> &#x00BB; <a href="../index.html">Moonpool_sync</a> &#x00BB; Lock</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_sync.Lock</span></code></h1><p>Mutex-protected resource.</p><p>This lock is a synchronous concurrency primitive, as a thin wrapper around <a href="../../../picos_std/Picos_std_sync/Mutex/index.html"><code>Mutex</code></a> that encourages proper management of the critical section in RAII style:</p><pre class="language-ocaml"><code>let (let@) = (@@)
let compute_foo =
(* enter critical section *)
let@ x = Lock.with_ protected_resource in
use_x;
return_foo ()
(* exit critical section *)
in
</code></pre><p>This lock is based on <code>Picos_sync.Mutex</code> so it is <code>await</code>-safe.</p><ul class="at-tags"><li class="since"><span class="at-tag">since</span> NEXT_RELEASE</li></ul></header><div class="odoc-content"><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>A value protected by a cooperative mutex</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="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>Create a new protected value.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-with_"><a href="#val-with_" class="anchor"></a><code><span><span class="keyword">val</span> with_ : <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> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'b</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'b</span></span></code></div><div class="spec-doc"><p><code>with_ l f</code> runs <code>f x</code> where <code>x</code> is the value protected with the lock <code>l</code>, in a critical section. If <code>f x</code> fails, <code>with_lock l f</code> fails too but the lock is released.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-update"><a href="#val-update" class="anchor"></a><code><span><span class="keyword">val</span> update : <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> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>update l f</code> replaces the content <code>x</code> of <code>l</code> with <code>f x</code>, while protected by the mutex.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-update_map"><a href="#val-update_map" class="anchor"></a><code><span><span class="keyword">val</span> update_map : <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> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span> * <span class="type-var">'b</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'b</span></span></code></div><div class="spec-doc"><p><code>update_map l f</code> computes <code>x', y = f (get l)</code>, then puts <code>x'</code> in <code>l</code> and returns <code>y</code>, while protected by the mutex.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-mutex"><a href="#val-mutex" class="anchor"></a><code><span><span class="keyword">val</span> mutex : <span><span><span class="type-var">_</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <a href="../../../picos_std/Picos_std_sync/Mutex/index.html#type-t">Picos_std_sync.Mutex.t</a></span></code></div><div class="spec-doc"><p>Underlying mutex.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-get"><a href="#val-get" class="anchor"></a><code><span><span class="keyword">val</span> get : <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>Atomically get the value in the lock. The value that is returned isn't protected!</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-set"><a href="#val-set" class="anchor"></a><code><span><span class="keyword">val</span> set : <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>Atomically set the value.</p><p><b>NOTE</b> caution: using <a href="#val-get"><code>get</code></a> and <a href="#val-set"><code>set</code></a> as if this were a <code>ref</code> is an anti pattern and will not protect data against some race conditions.</p></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool_sync (moonpool.Moonpool_sync)</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">moonpool</a> &#x00BB; Moonpool_sync</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_sync</span></code></h1></header><div class="odoc-content"><div class="odoc-spec"><div class="spec module anchored" id="module-Mutex"><a href="#module-Mutex" class="anchor"></a><code><span><span class="keyword">module</span> Mutex</span><span> = <a href="../../picos_std/Picos_std_sync/Mutex/index.html">Picos_std_sync.Mutex</a></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Condition"><a href="#module-Condition" class="anchor"></a><code><span><span class="keyword">module</span> Condition</span><span> = <a href="../../picos_std/Picos_std_sync/Condition/index.html">Picos_std_sync.Condition</a></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Lock"><a href="#module-Lock" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Lock/index.html">Lock</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Mutex-protected resource.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Event"><a href="#module-Event" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Event/index.html">Event</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Semaphore"><a href="#module-Semaphore" class="anchor"></a><code><span><span class="keyword">module</span> Semaphore</span><span> = <a href="../../picos_std/Picos_std_sync/Semaphore/index.html">Picos_std_sync.Semaphore</a></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Lazy"><a href="#module-Lazy" class="anchor"></a><code><span><span class="keyword">module</span> Lazy</span><span> = <a href="../../picos_std/Picos_std_sync/Lazy/index.html">Picos_std_sync.Lazy</a></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Latch"><a href="#module-Latch" class="anchor"></a><code><span><span class="keyword">module</span> Latch</span><span> = <a href="../../picos_std/Picos_std_sync/Latch/index.html">Picos_std_sync.Latch</a></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Ivar"><a href="#module-Ivar" class="anchor"></a><code><span><span class="keyword">module</span> Ivar</span><span> = <a href="../../picos_std/Picos_std_sync/Ivar/index.html">Picos_std_sync.Ivar</a></span></code></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Stream"><a href="#module-Stream" class="anchor"></a><code><span><span class="keyword">module</span> Stream</span><span> = <a href="../../picos_std/Picos_std_sync/Stream/index.html">Picos_std_sync.Stream</a></span></code></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool_sync__ (moonpool.Moonpool_sync__)</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">moonpool</a> &#x00BB; Moonpool_sync__</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_sync__</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool_sync__Event (moonpool.Moonpool_sync__Event)</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">moonpool</a> &#x00BB; Moonpool_sync__Event</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_sync__Event</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Moonpool_sync__Lock (moonpool.Moonpool_sync__Lock)</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">moonpool</a> &#x00BB; Moonpool_sync__Lock</nav><header class="odoc-preamble"><h1>Module <code><span>Moonpool_sync__Lock</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -1,2 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>index (moonpool.index)</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> moonpool</nav><header class="odoc-preamble"><h1 id="package-moonpool"><a href="#package-moonpool" class="anchor"></a>Package moonpool <nav><a type="text/plain; charset=UTF-8" href="_doc-dir/CHANGES.md">changes</a> <a href="#package_info">more…</a></nav></h1><ul class="modules"><li><a href="Moonpool/index.html"><code>Moonpool</code></a> <span class="synopsis">Moonpool</span></li><li><a href="Moonpool_dpool/index.html"><code>Moonpool_dpool</code></a> <span class="synopsis">Static pool of domains.</span></li><li><a href="Moonpool_fib/index.html"><code>Moonpool_fib</code></a> <span class="synopsis">Fibers for moonpool.</span></li><li><a href="Moonpool_forkjoin/index.html"><code>Moonpool_forkjoin</code></a> <span class="synopsis">Fork-join primitives.</span></li><li><a href="Moonpool_private/index.html"><code>Moonpool_private</code></a> </li></ul></header><nav class="odoc-toc"><ul><li><a href="#package_info">Package info</a></li></ul></nav><div class="odoc-content"><h2 id="package_info"><a href="#package_info" class="anchor"></a>Package info</h2><table class="package info"><tr id="info-changes-files"><td><a href="#info-changes-files" aria-hidden="true" class="anchor"></a>changes-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/CHANGES.md">CHANGES.md</a></li></ul></td></tr><tr id="info-readme-files"><td><a href="#info-readme-files" aria-hidden="true" class="anchor"></a>readme-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/README.md">README.md</a></li></ul></td></tr></table></div></body></html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>index (moonpool.index)</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> moonpool</nav><header class="odoc-preamble"><h1 id="package-moonpool"><a href="#package-moonpool" class="anchor"></a>Package moonpool <nav><a type="text/plain; charset=UTF-8" href="_doc-dir/CHANGES.md">changes</a> <a href="#package_info">more…</a></nav></h1><ul class="modules"><li><a href="Moonpool/index.html"><code>Moonpool</code></a> <span class="synopsis">Moonpool</span></li><li><a href="Moonpool_dpool/index.html"><code>Moonpool_dpool</code></a> <span class="synopsis">Static pool of domains.</span></li><li><a href="Moonpool_fib/index.html"><code>Moonpool_fib</code></a> <span class="synopsis">Fibers for moonpool.</span></li><li><a href="Moonpool_forkjoin/index.html"><code>Moonpool_forkjoin</code></a> <span class="synopsis">Fork-join primitives.</span></li><li><a href="Moonpool_private/index.html"><code>Moonpool_private</code></a> </li><li><a href="Moonpool_sync/index.html"><code>Moonpool_sync</code></a> </li></ul></header><nav class="odoc-toc"><ul><li><a href="#package_info">Package info</a></li></ul></nav><div class="odoc-content"><h2 id="package_info"><a href="#package_info" class="anchor"></a>Package info</h2><table class="package info"><tr id="info-changes-files"><td><a href="#info-changes-files" aria-hidden="true" class="anchor"></a>changes-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/CHANGES.md">CHANGES.md</a></li></ul></td></tr><tr id="info-readme-files"><td><a href="#info-readme-files" aria-hidden="true" class="anchor"></a>readme-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/README.md">README.md</a></li></ul></td></tr></table></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Multicore_magic (multicore-magic.Multicore_magic)</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">multicore-magic</a> &#x00BB; Multicore_magic</nav><header class="odoc-preamble"><h1>Module <code><span>Multicore_magic</span></code></h1><p>This is a library of magic multicore utilities intended for experts for extracting the best possible performance from multicore OCaml.</p><p>Hopefully future releases of multicore OCaml will make this library obsolete!</p></header><nav class="odoc-toc"><ul><li><a href="#helpers-for-using-padding-to-avoid-false-sharing">Helpers for using padding to avoid false sharing</a></li><li><a href="#missing-atomic-operations">Missing <code>Atomic</code> operations</a></li><li><a href="#fixes-and-workarounds">Fixes and workarounds</a></li><li><a href="#missing-functionality">Missing functionality</a></li><li><a href="#avoiding-contention">Avoiding contention</a></li></ul></nav><div class="odoc-content"><h2 id="helpers-for-using-padding-to-avoid-false-sharing"><a href="#helpers-for-using-padding-to-avoid-false-sharing" class="anchor"></a>Helpers for using padding to avoid false sharing</h2><div class="odoc-spec"><div class="spec value anchored" id="val-copy_as_padded"><a href="#val-copy_as_padded" class="anchor"></a><code><span><span class="keyword">val</span> copy_as_padded : <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p>Depending on the object, either creates a shallow clone of it or returns it as is. When cloned, the clone will have extra padding words added after the last used word.</p><p>This is designed to help avoid <a href="https://en.wikipedia.org/wiki/False_sharing">false sharing</a>. False sharing has a negative impact on multicore performance. Accesses of both atomic and non-atomic locations, whether read-only or read-write, may suffer from false sharing.</p><p>The intended use case for this is to pad all long lived objects that are being accessed highly frequently (read or written).</p><p>Many kinds of objects can be padded, for example:</p><pre class="language-ocaml"><code>let padded_atomic = Multicore_magic.copy_as_padded (Atomic.make 101)
let padded_ref = Multicore_magic.copy_as_padded (ref 42)
let padded_record = Multicore_magic.copy_as_padded {
number = 76;
pointer = 1 :: 2 :: 3 :: [];
}
let padded_variant = Multicore_magic.copy_as_padded (Some 1)</code></pre><p>Padding changes the length of an array. If you need to pad an array, use <a href="#val-make_padded_array"><code>make_padded_array</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-copy_as"><a href="#val-copy_as" class="anchor"></a><code><span><span class="keyword">val</span> copy_as : <span><span class="optlabel">?padded</span>:bool <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">'a</span></span></code></div><div class="spec-doc"><p><code>copy_as x</code> by default simply returns <code>x</code>. When <code>~padded:true</code> is explicitly specified, returns <a href="#val-copy_as_padded" title="copy_as_padded"><code>copy_as_padded x</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-make_padded_array"><a href="#val-make_padded_array" class="anchor"></a><code><span><span class="keyword">val</span> make_padded_array : <span>int <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> array</span></span></code></div><div class="spec-doc"><p>Creates a padded array. The length of the returned array includes padding. Use <a href="#val-length_of_padded_array"><code>length_of_padded_array</code></a> to get the unpadded length.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-length_of_padded_array"><a href="#val-length_of_padded_array" class="anchor"></a><code><span><span class="keyword">val</span> length_of_padded_array : <span><span><span class="type-var">'a</span> array</span> <span class="arrow">&#45;&gt;</span></span> int</span></code></div><div class="spec-doc"><p>Returns the length of an array created by <a href="#val-make_padded_array"><code>make_padded_array</code></a> without the padding.</p><p><b>WARNING</b>: This is not guaranteed to work with <a href="#val-copy_as_padded"><code>copy_as_padded</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-length_of_padded_array_minus_1"><a href="#val-length_of_padded_array_minus_1" class="anchor"></a><code><span><span class="keyword">val</span> length_of_padded_array_minus_1 : <span><span><span class="type-var">'a</span> array</span> <span class="arrow">&#45;&gt;</span></span> int</span></code></div><div class="spec-doc"><p>Returns the length of an array created by <a href="#val-make_padded_array"><code>make_padded_array</code></a> without the padding minus 1.</p><p><b>WARNING</b>: This is not guaranteed to work with <a href="#val-copy_as_padded"><code>copy_as_padded</code></a>.</p></div></div><h2 id="missing-atomic-operations"><a href="#missing-atomic-operations" class="anchor"></a>Missing <code>Atomic</code> operations</h2><div class="odoc-spec"><div class="spec value anchored" id="val-fenceless_get"><a href="#val-fenceless_get" class="anchor"></a><code><span><span class="keyword">val</span> fenceless_get : <span><span><span class="type-var">'a</span> <a href="../../ocaml/Stdlib/Atomic/index.html#type-t">Stdlib.Atomic.t</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p>Get a value from the atomic without performing an acquire fence.</p><p>Consider the following prototypical example of a lock-free algorithm:</p><pre class="language-ocaml"><code>let rec prototypical_lock_free_algorithm () =
let expected = Atomic.get atomic in
let desired = (* computed from expected *) in
if not (Atomic.compare_and_set atomic expected desired) then
(* failure, maybe retry *)
else
(* success *)</code></pre><p>A potential performance problem with the above example is that it performs two acquire fences. Both the <code>Atomic.get</code> and the <code>Atomic.compare_and_set</code> perform an acquire fence. This may have a negative impact on performance.</p><p>Assuming the first fence is not necessary, we can rewrite the example using <a href="#val-fenceless_get"><code>fenceless_get</code></a> as follows:</p><pre class="language-ocaml"><code>let rec prototypical_lock_free_algorithm () =
let expected = Multicore_magic.fenceless_get atomic in
let desired = (* computed from expected *) in
if not (Atomic.compare_and_set atomic expected desired) then
(* failure, maybe retry *)
else
(* success *)</code></pre><p>Now only a single acquire fence is performed by <code>Atomic.compare_and_set</code> and performance may be improved.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-fenceless_set"><a href="#val-fenceless_set" class="anchor"></a><code><span><span class="keyword">val</span> fenceless_set : <span><span><span class="type-var">'a</span> <a href="../../ocaml/Stdlib/Atomic/index.html#type-t">Stdlib.Atomic.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>Set the value of an atomic without performing a full fence.</p><p>Consider the following example:</p><pre class="language-ocaml"><code>let new_atomic = Atomic.make dummy_value in
(* prepare data_structure referring to new_atomic *)
Atomic.set new_atomic data_structure;
(* publish the data_structure: *)
Atomic.exchance old_atomic data_structure</code></pre><p>A potential performance problem with the above example is that it performs two full fences. Both the <code>Atomic.set</code> used to initialize the data structure and the <code>Atomic.exchange</code> used to publish the data structure perform a full fence. The same would also apply in cases where <code>Atomic.compare_and_set</code> or <code>Atomic.set</code> would be used to publish the data structure. This may have a negative impact on performance.</p><p>Using <a href="#val-fenceless_set"><code>fenceless_set</code></a> we can rewrite the example as follows:</p><pre class="language-ocaml"><code>let new_atomic = Atomic.make dummy_value in
(* prepare data_structure referring to new_atomic *)
Multicore_magic.fenceless_set new_atomic data_structure;
(* publish the data_structure: *)
Atomic.exchance old_atomic data_structure</code></pre><p>Now only a single full fence is performed by <code>Atomic.exchange</code> and performance may be improved.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-fence"><a href="#val-fence" class="anchor"></a><code><span><span class="keyword">val</span> fence : <span><span>int <a href="../../ocaml/Stdlib/Atomic/index.html#type-t">Stdlib.Atomic.t</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p>Perform a full acquire-release fence on the given atomic.</p><p><code>fence atomic</code> is equivalent to <code>ignore (Atomic.fetch_and_add atomic 0)</code>.</p></div></div><h2 id="fixes-and-workarounds"><a href="#fixes-and-workarounds" class="anchor"></a>Fixes and workarounds</h2><div class="odoc-spec"><div class="spec module anchored" id="module-Transparent_atomic"><a href="#module-Transparent_atomic" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Transparent_atomic/index.html">Transparent_atomic</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A replacement for <code>Stdlib.Atomic</code> with fixes and performance improvements</p></div></div><h2 id="missing-functionality"><a href="#missing-functionality" class="anchor"></a>Missing functionality</h2><div class="odoc-spec"><div class="spec module anchored" id="module-Atomic_array"><a href="#module-Atomic_array" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Atomic_array/index.html">Atomic_array</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Array of (potentially unboxed) atomic locations.</p></div></div><h2 id="avoiding-contention"><a href="#avoiding-contention" class="anchor"></a>Avoiding contention</h2><div class="odoc-spec"><div class="spec value anchored" id="val-instantaneous_domain_index"><a href="#val-instantaneous_domain_index" class="anchor"></a><code><span><span class="keyword">val</span> instantaneous_domain_index : <span>unit <span class="arrow">&#45;&gt;</span></span> int</span></code></div><div class="spec-doc"><p><code>instantaneous_domain_index ()</code> potentially (re)allocates and returns a non-negative integer &quot;index&quot; for the current domain. The indices are guaranteed to be unique among the domains that exist at a point in time. Each call of <code>instantaneous_domain_index ()</code> may return a different index.</p><p>The intention is that the returned value can be used as an index into a contention avoiding parallelism safe data structure. For example, a naïve scalable increment of one counter from an array of counters could be done as follows:</p><pre class="language-ocaml"><code>let incr counters =
(* Assuming length of [counters] is a power of two and larger than
the number of domains. *)
let mask = Array.length counters - 1 in
let index = instantaneous_domain_index () in
Atomic.incr counters.(index land mask)</code></pre><p>The implementation ensures that the indices are allocated as densely as possible at any given moment. This should allow allocating as many counters as needed and essentially eliminate contention.</p><p>On OCaml 4 <code>instantaneous_domain_index ()</code> will always return <code>0</code>.</p></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Multicore_magic__ (multicore-magic.Multicore_magic__)</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">multicore-magic</a> &#x00BB; Multicore_magic__</nav><header class="odoc-preamble"><h1>Module <code><span>Multicore_magic__</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Multicore_magic__Cache (multicore-magic.Multicore_magic__Cache)</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">multicore-magic</a> &#x00BB; Multicore_magic__Cache</nav><header class="odoc-preamble"><h1>Module <code><span>Multicore_magic__Cache</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Multicore_magic__Index (multicore-magic.Multicore_magic__Index)</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">multicore-magic</a> &#x00BB; Multicore_magic__Index</nav><header class="odoc-preamble"><h1>Module <code><span>Multicore_magic__Index</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Multicore_magic__Padding (multicore-magic.Multicore_magic__Padding)</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">multicore-magic</a> &#x00BB; Multicore_magic__Padding</nav><header class="odoc-preamble"><h1>Module <code><span>Multicore_magic__Padding</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Multicore_magic__Transparent_atomic (multicore-magic.Multicore_magic__Transparent_atomic)</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">multicore-magic</a> &#x00BB; Multicore_magic__Transparent_atomic</nav><header class="odoc-preamble"><h1>Module <code><span>Multicore_magic__Transparent_atomic</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,33 @@
## 2.3.0
- Add `copy_as ~padded` for convenient optional padding (@polytypic)
- Add `multicore-magic-dscheck` package and library to help testing with DScheck
(@lyrm, review @polytypic)
## 2.2.0
- Add (unboxed) `Atomic_array` (@polytypic)
## 2.1.0
- Added `instantaneous_domain_index` for the implementation of contention
avoiding data structures. (@polytypic)
- Added `Transparent_atomic` module as a workaround to CSE issues in OCaml 5.0
and OCaml 5.1 and also to allow more efficient arrays of atomics. (@polytypic)
- Fixed `fenceless_get` to not be subject to CSE. (@polytypic)
## 2.0.0
- Changed the semantics of `copy_as_padded` to not always copy and to not
guarantee that `length_of_padded_array*` works with it. These semantic changes
allow better use of the OCaml allocator to guarantee cache friendly alignment.
(@polytypic)
## 1.0.1
- Ported the library to OCaml 4 (@polytypic)
- License changed to ISC from 0BSD (@tarides)
## 1.0.0
- Initial release (@polytypic)

View file

@ -0,0 +1,13 @@
Copyright © 2023 Vesa Karvonen
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

View file

@ -0,0 +1,8 @@
[API reference](https://ocaml-multicore.github.io/multicore-magic/doc/multicore-magic/Multicore_magic/index.html)
# **multicore-magic** &mdash; Low-level multicore utilities for OCaml
This is a library of magic multicore utilities intended for experts for
extracting the best possible performance from multicore OCaml.
Hopefully future releases of multicore OCaml will make this library obsolete!

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>index (multicore-magic.index)</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> multicore-magic</nav><header class="odoc-preamble"><h1 id="package-multicore-magic"><a href="#package-multicore-magic" class="anchor"></a>Package multicore-magic <nav><a type="text/plain; charset=UTF-8" href="_doc-dir/CHANGES.md">changes</a> <a href="#package_info">more…</a></nav></h1><ul class="modules"><li><a href="Multicore_magic/index.html"><code>Multicore_magic</code></a> <span class="synopsis">This is a library of magic multicore utilities intended for experts for extracting the best possible performance from multicore OCaml.</span></li></ul></header><nav class="odoc-toc"><ul><li><a href="#package_info">Package info</a></li></ul></nav><div class="odoc-content"><h2 id="package_info"><a href="#package_info" class="anchor"></a>Package info</h2><table class="package info"><tr id="info-changes-files"><td><a href="#info-changes-files" aria-hidden="true" class="anchor"></a>changes-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/CHANGES.md">CHANGES.md</a></li></ul></td></tr><tr id="info-license-files"><td><a href="#info-license-files" aria-hidden="true" class="anchor"></a>license-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/LICENSE.md">LICENSE.md</a></li></ul></td></tr><tr id="info-readme-files"><td><a href="#info-readme-files" aria-hidden="true" class="anchor"></a>readme-files</td><td><ul><li><a type="text/plain; charset=UTF-8" href="_doc-dir/README.md">README.md</a></li></ul></td></tr></table></div></body></html>

View file

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Tx (picos.Picos.Computation.Tx)</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</a> &#x00BB; <a href="../../index.html">Picos</a> &#x00BB; <a href="../index.html">Computation</a> &#x00BB; Tx</nav><header class="odoc-preamble"><h1>Module <code><span>Computation.Tx</span></code></h1><p>Transactional interface for atomically completing multiple computations.</p><p>⚠️ The implementation of this mechanism is designed to avoid making the single computation completing operations, i.e. <a href="../index.html#val-try_return" title="Computation.try_return"><code>try_return</code></a> and <a href="../index.html#val-try_cancel" title="Computation.try_cancel"><code>try_cancel</code></a>, slower and to avoid making computations heavier. For this reason the transaction mechanism is only <a href="https://en.wikipedia.org/wiki/Non-blocking_algorithm#Obstruction-freedom">obstruction-free</a>. What this means is that a transaction may be aborted by another transaction or by a single computation manipulating operation.</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec type subst anchored" id="type-computation"><a href="#type-computation" class="anchor"></a><code><span><span class="keyword">type</span> <span>'a computation</span></span><span> := <span><span class="type-var">'a</span> <a href="../index.html#type-t">t</a></span></span></code></div><div class="spec-doc"><p>Destructively substituted alias for <a href="../index.html#type-t"><code>Computation.t</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-same"><a href="#val-same" class="anchor"></a><code><span><span class="keyword">val</span> same : <span><span><span class="type-var">_</span> <a href="#type-computation">computation</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span><span class="type-var">_</span> <a href="#type-computation">computation</a></span> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>same computation1 computation2</code> determines whether the two computations are the one and the same.</p></div></div><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> t</span></code></div><div class="spec-doc"><p>Represents a transaction.</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>unit <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>create ()</code> returns a new empty transaction.</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><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> <span><span><span class="type-var">'a</span> <a href="#type-computation">computation</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 tx computation value</code> adds the completion of the <code>computation</code> as having returned the given <code>value</code> to the transaction. Returns <code>true</code> in case the computation had not yet been completed and the transaction was still alive. Otherwise returns <code>false</code> which means that transaction was aborted and it is as if none of the completions succesfully added to the transaction have taken place.</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><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span>
<span><span><span class="type-var">'a</span> <a href="#type-computation">computation</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 tx computation exn bt</code> adds the completion of the computation as having canceled with the given exception and backtrace to the transaction. Returns <code>true</code> in case the computation had not yet been completed and the transaction was still alive. Otherwise returns <code>false</code> which means that transaction was aborted and it is as if none of the completions succesfully added to the transaction have taken place.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_commit"><a href="#val-try_commit" class="anchor"></a><code><span><span class="keyword">val</span> try_commit : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_commit tx</code> attempts to mark the transaction as committed successfully. Returns <code>true</code> in case of success, which means that all the completions added to the transaction have been performed atomically. Otherwise returns <code>false</code> which means that transaction was aborted and it is as if none of the completions succesfully added to the transaction have taken place.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Handler (picos.Picos.Handler)</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</a> &#x00BB; <a href="../index.html">Picos</a> &#x00BB; Handler</nav><header class="odoc-preamble"><h1>Module <code><span>Picos.Handler</span></code></h1><p>Handler for the effects based operations of Picos for OCaml 4.</p></header><div class="odoc-content"><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>'c t</span></span><span> = </span><span>{</span></code><ol><li id="type-t.current" class="def record field anchored"><a href="#type-t.current" class="anchor"></a><code><span>current : <span><span class="type-var">'c</span> <span class="arrow">&#45;&gt;</span></span> <a href="../Fiber/index.html#type-t">Fiber.t</a>;</span></code><div class="def-doc"><span class="comment-delim">(*</span><p>See <a href="../Fiber/index.html#val-current"><code>Picos.Fiber.current</code></a>.</p><span class="comment-delim">*)</span></div></li><li id="type-t.spawn" class="def record field anchored"><a href="#type-t.spawn" class="anchor"></a><code><span>spawn : <span><span class="type-var">'c</span> <span class="arrow">&#45;&gt;</span></span> <span><a href="../Fiber/index.html#type-t">Fiber.t</a> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><a href="../Fiber/index.html#type-t">Fiber.t</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span> unit;</span></code><div class="def-doc"><span class="comment-delim">(*</span><p>See <a href="../Fiber/index.html#val-spawn"><code>Picos.Fiber.spawn</code></a>.</p><span class="comment-delim">*)</span></div></li><li id="type-t.yield" class="def record field anchored"><a href="#type-t.yield" class="anchor"></a><code><span>yield : <span><span class="type-var">'c</span> <span class="arrow">&#45;&gt;</span></span> unit;</span></code><div class="def-doc"><span class="comment-delim">(*</span><p>See <a href="../Fiber/index.html#val-yield"><code>Picos.Fiber.yield</code></a>.</p><span class="comment-delim">*)</span></div></li><li id="type-t.cancel_after" class="def record field anchored"><a href="#type-t.cancel_after" class="anchor"></a><code><span>cancel_after : 'a. <span><span class="type-var">'c</span> <span class="arrow">&#45;&gt;</span></span>
<span><span><span class="type-var">'a</span> <a href="../Computation/index.html#type-t">Computation.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 class="def-doc"><span class="comment-delim">(*</span><p>See <a href="../Computation/index.html#val-cancel_after"><code>Picos.Computation.cancel_after</code></a>.</p><span class="comment-delim">*)</span></div></li><li id="type-t.await" class="def record field anchored"><a href="#type-t.await" class="anchor"></a><code><span>await : <span><span class="type-var">'c</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> <span><span>(exn * <a href="../../../ocaml/Stdlib/Printexc/index.html#type-raw_backtrace">Stdlib.Printexc.raw_backtrace</a>)</span> option</span>;</span></code><div class="def-doc"><span class="comment-delim">(*</span><p>See <a href="../Trigger/index.html#val-await"><code>Picos.Trigger.await</code></a>.</p><span class="comment-delim">*)</span></div></li></ol><code><span>}</span></code></div><div class="spec-doc"><p>A record of implementations of the primitive effects based operations of Picos. The operations take a context of type <code>'c</code> as an argument.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-using"><a href="#val-using" class="anchor"></a><code><span><span class="keyword">val</span> using : <span><span><span class="type-var">'c</span> <a href="#type-t">t</a></span> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'c</span> <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><a href="../Fiber/index.html#type-t">Fiber.t</a> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>using handler context main</code> sets the <code>handler</code> and the <code>context</code> for the handler of the primitive effects based operations of Picos while running <code>main</code>.</p><p> The behavior is that</p><ul><li>on OCaml 4, <code>using</code> stores the <code>handler</code> in <a href="../../Picos_thread/TLS/index.html" title="Picos_thread.TLS"><code>TLS</code></a>, which allows the operations to be accessed during the execution of the <code>thunk</code>, and</li><li>on OCaml 5, <code>using</code> runs <code>thunk</code> with a deep effect handler that delegates to the operations of the <code>handler</code>.</li></ul><p>⚠️ While this works on OCaml 5, you usually want to use a scheduler that implements an effect handler directly, because that is likely to perform better.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

6
picos/Picos/index.html Normal file

File diff suppressed because one or more lines are too long

2
picos/Picos__/index.html Normal file
View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos__ (picos.Picos__)</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</a> &#x00BB; Picos__</nav><header class="odoc-preamble"><h1>Module <code><span>Picos__</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos__Intf (picos.Picos__Intf)</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</a> &#x00BB; Picos__Intf</nav><header class="odoc-preamble"><h1>Module <code><span>Picos__Intf</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>DLS (picos.Picos_domain.DLS)</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</a> &#x00BB; <a href="../index.html">Picos_domain</a> &#x00BB; DLS</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_domain.DLS</span></code></h1><p>Domain-local storage for Picos.</p><p> On OCaml 4 there is always only a single domain.</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec type anchored" id="type-key"><a href="#type-key" class="anchor"></a><code><span><span class="keyword">type</span> <span>'a key</span></span></code></div><div class="spec-doc"><p>Represents a key for storing values of type <code>'a</code> in storage associated with domains.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-new_key"><a href="#val-new_key" class="anchor"></a><code><span><span class="keyword">val</span> new_key : <span><span>(<span>unit <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">'a</span> <a href="#type-key">key</a></span></span></code></div><div class="spec-doc"><p><code>new_key compute</code> allocates a new key for associating values in storage associated with domains. The initial value for each domain is <code>compute</code>d by calling the given function if the <code>key</code> is <a href="#val-get" title="get">read</a> before it has been <a href="#val-set" title="set">written</a>. The <code>compute</code> function might be called multiple times per domain, but only one result will be used.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-get"><a href="#val-get" class="anchor"></a><code><span><span class="keyword">val</span> get : <span><span><span class="type-var">'a</span> <a href="#type-key">key</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>get key</code> returns the value associated with the <code>key</code> in the storage associated with the current domain.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-set"><a href="#val-set" class="anchor"></a><code><span><span class="keyword">val</span> set : <span><span><span class="type-var">'a</span> <a href="#type-key">key</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>set key value</code> sets the <code>value</code> associated with the <code>key</code> in the storage associated with the current domain.</p></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_domain (picos.Picos_domain)</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</a> &#x00BB; Picos_domain</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_domain</span></code></h1><p>Minimalistic domain API available both on OCaml 5 and on OCaml 4.</p><p> On OCaml 4 there is always only a single domain.</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec value anchored" id="val-at_exit"><a href="#val-at_exit" class="anchor"></a><code><span><span class="keyword">val</span> at_exit : <span><span>(<span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>at_exit action</code> registers <code>action</code> to be called when the current domain exits.</p><p>On OCaml 5 this calls <code>Domain.at_exit</code>. On OCaml 4 this calls <a href="../../ocaml/Stdlib/index.html#val-at_exit"><code>Stdlib.at_exit</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-recommended_domain_count"><a href="#val-recommended_domain_count" class="anchor"></a><code><span><span class="keyword">val</span> recommended_domain_count : <span>unit <span class="arrow">&#45;&gt;</span></span> int</span></code></div><div class="spec-doc"><p><code>recommended_domain_count ()</code> returns <code>1</code> on OCaml 4 and calls <code>Domain.recommended_domain_count</code> on OCaml 5.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-is_main_domain"><a href="#val-is_main_domain" class="anchor"></a><code><span><span class="keyword">val</span> is_main_domain : <span>unit <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>is_main_domain ()</code> returns <code>true</code> on OCaml 4 and calls <code>Domain.is_main_domain</code> on OCaml 5.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-DLS"><a href="#module-DLS" class="anchor"></a><code><span><span class="keyword">module</span> <a href="DLS/index.html">DLS</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Domain-local storage for Picos.</p></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>TLS (picos.Picos_thread.TLS)</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</a> &#x00BB; <a href="../index.html">Picos_thread</a> &#x00BB; TLS</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_thread.TLS</span></code></h1><p>Thread-local storage.</p><p>Note that here &quot;thread&quot; refers to system level threads rather than fibers or domains. In case a system level thread implementation, i.e. the <code>threads.posix</code> library, is not available, this will use <a href="../../Picos_domain/DLS/index.html"><code>Picos_domain.DLS</code></a>.</p></header><div class="odoc-content"><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 key for associating values with threads.</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>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> allocates a new key for associating values with threads.</p><p>⚠️ Keys should not be created dynamically as each key will potentially increase the space taken by every thread.</p></div></div><div class="odoc-spec"><div class="spec exception anchored" id="exception-Not_set"><a href="#exception-Not_set" class="anchor"></a><code><span><span class="keyword">exception</span> </span><span><span class="exception">Not_set</span></span></code></div><div class="spec-doc"><p>Exception raised by <a href="#val-get_exn"><code>get_exn</code></a> when no value is associated with the specified key for the current thread.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-get_exn"><a href="#val-get_exn" class="anchor"></a><code><span><span class="keyword">val</span> get_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>get_exn key</code> returns the value associated with the specified key for the current thread or raises <a href="#exception-Not_set"><code>Not_set</code></a> in case no value has been <a href="#val-set"><code>set</code></a> for the key.</p><p>⚠️ The <a href="#exception-Not_set"><code>Not_set</code></a> exception is raised with no backtrace. Always catch the exception unless it is known that a value has been set.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-set"><a href="#val-set" class="anchor"></a><code><span><span class="keyword">val</span> set : <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>set key value</code> associates the value with the specified key for the current thread.</p></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_thread (picos.Picos_thread)</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</a> &#x00BB; Picos_thread</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_thread</span></code></h1><p>Minimalistic thread API available with or without <code>threads.posix</code>.</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec value anchored" id="val-is_main_thread"><a href="#val-is_main_thread" class="anchor"></a><code><span><span class="keyword">val</span> is_main_thread : <span>unit <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>is_main_thread ()</code> determines whether running on the main thread of the application.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-TLS"><a href="#module-TLS" class="anchor"></a><code><span><span class="keyword">module</span> <a href="TLS/index.html">TLS</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Thread-local storage.</p></div></div></div></body></html>

171
picos/_doc-dir/CHANGES.md Normal file
View file

@ -0,0 +1,171 @@
## 0.5.0
- Major additions, changes, bug fixes, improvements, and restructuring
(@polytypic, @c-cube)
- Additions:
- Minimalistic Cohttp implementation
- Implicitly propagated `Flock` of fibers for structured concurrency
- Option to terminate `Bundle` and `Flock` on return
- `Event` abstraction
- Synchronization and communication primitives:
- Incremental variable or `Ivar`
- Countdown `Latch`
- `Semaphore`
- `Stream` of events
- Multi-producer, multi-consumer lock-free queue optimized for schedulers
- Multithreaded (work-stealing) FIFO scheduler
- Support `quota` for FIFO based schedulers
- Transactional interface for atomically completing multiple `Computation`s
- Changes:
- Redesigned resource management based on `('r -> 'a) -> 'a` functions
- Redesigned `spawn` interface allowing `FLS` entries to be populated before
spawn
- Introduced concept of fatal errors, which must terminate the scheduler or
the whole program
- Simplified `FLS` interface
- Removed `Exn_bt`
- Improvements:
- Signficantly reduced per fiber memory usage of various sample schedulers
- Picos has now been split into multiple packages and libraries:
- pkg: `picos`
- lib: `picos`
- lib: `picos.domain`
- lib: `picos.thread`
- pkg: `picos_aux`
- lib: `picos_aux.htbl`
- lib: `picos_aux.mpmcq`
- lib: `picos_aux.mpscq`
- lib: `picos_aux.rc`
- pkg: `picos_lwt`
- lib: `picos_lwt`
- lib: `picos_lwt.unix`
- pkg: `picos_meta` (integration tests)
- pkg: `picos_mux`
- lib: `picos_mux.fifo`
- lib: `picos_mux.multififo`
- lib: `picos_mux.random`
- lib: `picos_mux.thread`
- pkg: `picos_std`
- lib: `picos_std.event`
- lib: `picos_std.finally`
- lib: `picos_std.structured`
- lib: `picos_std.sync`
- pkg: `picos_io`
- lib: `picos_io`
- lib: `picos_io.fd`
- lib: `picos_io.select`
- pkg: `picos_io_cohttp`
- lib: `picos_io_cohttp`
## 0.4.0
- Renamed `Picos_mpsc_queue` to `Picos_mpscq`. (@polytypic)
- Core API changes:
- Added `Computation.returned`. (@polytypic)
- `Lwt` interop improvements:
- Fixed `Picos_lwt` handling of `Cancel_after` to not raise in case of
cancelation. (@polytypic)
- Redesigned `Picos_lwt` to take a `System` module, which must implement a
semi thread-safe trigger mechanism to allow unblocking `Lwt` promises on the
main thread. (@polytypic)
- Added `Picos_lwt_unix` interface to `Lwt`, which includes an internal
`System` module implemented using `Lwt_unix`. (@polytypic)
- Dropped thunking from `Picos_lwt.await`. (@polytypic)
- Added a randomized multicore scheduler `Picos_randos` for testing.
(@polytypic)
- Changed `Picos_select.check_configured` to always (re)configure signal
handling on the current thread. (@polytypic)
- `Picos_structured`:
- Added a minimalistic `Promise` abstraction. (@polytypic)
- Changed to more consistently not treat `Terminate` as an error. (@polytypic)
- Changed schedulers to take `~forbid` as an optional argument. (@polytypic)
- Various minor additions, fixes, and documentation improvements. (@polytypic)
## 0.3.0
- Core API changes:
- Added `Fiber.set_computation`, which represents a semantic change
- Renamed `Fiber.computation` to `Fiber.get_computation`
- Added `Computation.attach_canceler`
- Added `Fiber.sleep`
- Added `Fiber.create_packed`
- Removed `Fiber.try_attach`
- Removed `Fiber.detach`
Most of the above changes were motivated by work on and requirements of the
added structured concurrency library (@polytypic)
- Added a basic user level structured concurrent programming library
`Picos_structured` (@polytypic)
- Added a functorized `Picos_lwt` providing direct style effects based interface
to programming with Lwt (@polytypic)
- Added missing `Picos_stdio.Unix.select` (@polytypic)
## 0.2.0
- Documentation fixes and restructuring (@polytypic)
- Scheduler friendly `waitpid`, `wait`, and `system` in `Picos_stdio.Unix` for
platforms other than Windows (@polytypic)
- Added `Picos_select.configure` to allow, and sometimes require, configuring
`Picos_select` for co-operation with libraries that also deal with signals
(@polytypic)
- Moved `Picos_tls` into `Picos_thread.TLS` (@polytypic)
- Enhanced `sleep` and `sleepf` in `Picos_stdio.Unix` to block in a scheduler
friendly manner (@polytypic)
## 0.1.0
- First experimental release of Picos.
Core:
- `picos` — A framework for interoperable effects based concurrency.
Sample schedulers:
- `picos.fifos` — Basic single-threaded effects based Picos compatible
scheduler for OCaml 5.
- `picos.threaded` — Basic `Thread` based Picos compatible scheduler for
OCaml 4.
Scheduler agnostic libraries:
- `picos.sync` — Basic communication and synchronization primitives for Picos.
- `picos.stdio` — Basic IO facilities based on OCaml standard libraries for
Picos.
- `picos.select` — Basic `Unix.select` based IO event loop for Picos.
Auxiliary libraries:
- `picos.domain` — Minimalistic domain API available both on OCaml 5 and on
OCaml 4.
- `picos.exn_bt` — Wrapper for exceptions with backtraces.
- `picos.fd` — Externally reference counted file descriptors.
- `picos.htbl` — Lock-free hash table.
- `picos.mpsc_queue` — Multi-producer, single-consumer queue.
- `picos.rc` — External reference counting tables for disposable resources.
- `picos.tls` — Thread-local storage.

13
picos/_doc-dir/LICENSE.md Normal file
View file

@ -0,0 +1,13 @@
Copyright © 2023 Vesa Karvonen
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

791
picos/_doc-dir/README.md Normal file
View file

@ -0,0 +1,791 @@
[API reference](https://ocaml-multicore.github.io/picos/doc/index.html) &middot;
[Benchmarks](https://bench.ci.dev/ocaml-multicore/picos/branch/main?worker=pascal&image=bench.Dockerfile)
&middot;
[Stdlib Benchmarks](https://bench.ci.dev/ocaml-multicore/multicore-bench/branch/main?worker=pascal&image=bench.Dockerfile)
# **Picos** &mdash; Interoperable effects based concurrency
Picos is a
[systems programming](https://en.wikipedia.org/wiki/Systems_programming)
interface between effects based schedulers and concurrent abstractions.
<p align="center"><a href="https://ocaml-multicore.github.io/picos/doc/picos/index.html"><img width="65%" src="https://raw.githubusercontent.com/ocaml-multicore/picos/main/doc/picos-ecosystem.svg"></a></p>
Picos is designed to enable an _open ecosystem_ of
[interoperable](https://en.wikipedia.org/wiki/Interoperability) and
interchangeable elements of effects based cooperative concurrent programming
models such as
- [schedulers](<https://en.wikipedia.org/wiki/Scheduling_(computing)>) that
multiplex large numbers of
[user level fibers](https://en.wikipedia.org/wiki/Green_thread) to run on a
small number of system level threads,
- mechanisms for managing fibers and for
[structuring concurrency](https://en.wikipedia.org/wiki/Structured_concurrency),
- communication and synchronization primitives, such as
[mutexes and condition variables](<https://en.wikipedia.org/wiki/Monitor_(synchronization)>),
message queues,
[STM](https://en.wikipedia.org/wiki/Software_transactional_memory)s, and more,
and
- integrations with low level
[asynchronous IO](https://en.wikipedia.org/wiki/Asynchronous_I/O) systems
by decoupling such elements from each other.
Picos comes with a
[reference manual](https://ocaml-multicore.github.io/picos/doc/index.html) and
many sample libraries.
⚠️ Please note that Picos is still considered experimental and unstable.
## Introduction
Picos addresses the incompatibility of effects based schedulers at a fundamental
level by introducing
[an _interface_ to decouple schedulers and other concurrent abstractions](https://ocaml-multicore.github.io/picos/doc/picos/Picos/index.html)
that need services from a scheduler.
The
[core abstractions of Picos](https://ocaml-multicore.github.io/picos/doc/picos/Picos/index.html#the-architecture-of-picos)
are
- [`Trigger`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Trigger/index.html)
— the ability to await for a signal,
- [`Computation`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Computation/index.html)
— a cancelable computation, and
- [`Fiber`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Fiber/index.html)
— an independent thread of execution,
that are implemented partially by the Picos interface in terms of the effects
- [`Trigger.Await`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Trigger/index.html#extension-Await)
— to suspend and resume a fiber,
- [`Computation.Cancel_after`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Computation/index.html#extension-Cancel_after)
— to cancel a computation after given period of time,
- [`Fiber.Current`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Fiber/index.html#extension-Current)
— to obtain the current fiber,
- [`Fiber.Yield`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Fiber/index.html#extension-Yield)
— to request rescheduling, and
- [`Fiber.Spawn`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Fiber/index.html#extension-Spawn)
— to start a new fiber.
The partial implementation of the abstractions and the effects define a contract
between schedulers and other concurrent abstractions. By handling the Picos
effects according to the contract a scheduler becomes _Picos compatible_, which
allows any abstractions written against the Picos interface, i.e. _Implemented
in Picos_, to be used with the scheduler.
### Understanding cancelation
A central idea or goal of Picos is to provide a collection of building blocks
for parallelism safe cancelation that allows the implementation of both blocking
abstractions as well as the implementation of abstractions for structuring
fibers for cancelation or managing the propagation and scope of cancelation.
While cancelation, which is essentially a kind of asynchronous exception or
signal, is not necessarily recommended as a general control mechanism, the
ability to cancel fibers in case of errors is crucial for the implementation of
practical concurrent programming models.
Consider the following characteristic
[example](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/index.html#understanding-cancelation):
```ocaml skip
Mutex.protect mutex begin fun () ->
while true do
Condition.wait condition mutex
done
end
```
Assume that a fiber executing the above code might be canceled, at any point, by
another fiber running in parallel. This could be necessary, for example, due to
an error that requires the application to be shut down. How could that be done
while ensuring both
[safety and liveness](https://en.wikipedia.org/wiki/Safety_and_liveness_properties)?
- For safety, cancelation should not leave the program in an invalid state or
cause the program to leak memory. In this case, `Condition.wait` must exit
with the mutex locked, even in case of cancelation, and, as `Mutex.protect`
exits, the ownership of the mutex must be transferred to the next fiber, if
any, waiting in queue for the mutex. No references to unused objects may be
left in the mutex or the condition variable.
- For liveness, cancelation should ensure that the fiber will eventually
continue after cancelation. In this case, cancelation could be triggered
during the `Mutex.lock` operation inside `Mutex.protect` or the
`Condition.wait` operation, when the fiber might be in a suspended state, and
cancelation should then allow the fiber to continue.
The set of abstractions, `Trigger`, `Computation`, and `Fiber`, work together
[to support cancelation](https://ocaml-multicore.github.io/picos/doc/picos/Picos/index.html#cancelation-in-picos).
Briefly, a fiber corresponds to an independent thread of execution and every
fiber is associated with a computation at all times. When a fiber creates a
trigger in order to await for a signal, it ask the scheduler to suspend the
fiber on the trigger. Assuming the fiber has not forbidden the propagation of
cancelation, which is required, for example, in the implementation of
`Condition.wait` to lock the mutex upon exit, the scheduler must also attach the
trigger to the computation associated with the fiber. If the computation is then
canceled before the trigger is otherwise signaled, the trigger will be signaled
by the cancelation of the computation, and the fiber will be resumed by the
scheduler as canceled.
This cancelable suspension protocol and its partial implementation designed
around the first-order
[`Trigger.Await`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Trigger/index.html#extension-Await)
effect creates a clear separation between schedulers and user code running in
fibers and is designed to handle the possibility of a trigger being signaled or
a computation being canceled at any point during the suspension of a fiber.
Schedulers are given maximal freedom to decide which fiber to resume next. As an
example, a scheduler could give priority to canceled fibers &mdash; going as far
as moving a fiber already in the ready queue of the scheduler to the front of
the queue at the point of cancelation &mdash; based on the assumption that user
code promptly cancels external requests and frees critical resources.
### `Trigger`
A trigger provides the ability to await for a signal and is perhaps the best
established and least controversial element of the Picos interface.
Here is an extract from the signature of the
[`Trigger` module](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Trigger/index.html):
<!--
```ocaml
# open Picos
# open Picos_std_finally
# open Picos_std_structured
# open Picos_std_sync
```
-->
```ocaml skip
type t
val create : unit -> t
val await : t -> (exn * Printexc.raw_backtrace) option
val signal : t -> unit
val on_signal : (* for schedulers *)
```
The idea is that a fiber may create a trigger, insert it into some shared data
structure, and then call `await` to ask the scheduler to suspend the fiber until
something signals the trigger. When `await` returns an exception with a
backtrace it means that the fiber has been canceled.
As an example, let's consider the implementation of an `Ivar` or incremental or
single-assignment variable:
```ocaml skip
type 'a t
val create : unit -> 'a t
val try_fill : 'a t -> 'a -> bool
val read : 'a t -> 'a
```
An `Ivar` is created as empty and can be filled with a value once. An attempt to
read an `Ivar` blocks until the `Ivar` is filled.
Using `Trigger` and `Atomic`, we can represent an `Ivar` as follows:
```ocaml
type 'a state =
| Filled of 'a
| Empty of Trigger.t list
type 'a t = 'a state Atomic.t
```
The `try_fill` operation is then fairly straightforward to implement:
```ocaml
let rec try_fill t value =
match Atomic.get t with
| Filled _ -> false
| Empty triggers as before ->
let after = Filled value in
if Atomic.compare_and_set t before after then
begin
List.iter Trigger.signal triggers; (* ! *)
true
end
else
try_fill t value
```
The interesting detail above is that after successfully filling an `Ivar`, the
triggers are signaled. This allows the `await` inside the `read` operation to
return:
<!--
```ocaml
let cleanup _t _trigger = ()
```
--->
```ocaml
let rec read t =
match Atomic.get t with
| Filled value -> value
| Empty triggers as before ->
let trigger = Trigger.create () in
let after = Empty (trigger :: triggers) in
if Atomic.compare_and_set t before after then
match Trigger.await trigger with
| None -> read t
| Some (exn, bt) ->
cleanup t trigger; (* ! *)
Printexc.raise_with_backtrace exn bt
else
read t
```
An important detail above is that when `await` returns an exception with a
backtrace, meaning that the fiber has been canceled, the `cleanup` operation
(which is omitted) is called to remove the `trigger` from the `Ivar` to avoid
potentially accumulating unbounded numbers of triggers in an empty `Ivar`.
As simple as it is, the design of `Trigger` is far from arbitrary:
- First of all, `Trigger` has single-assignment semantics. After being signaled,
a trigger takes a constant amount of space and does not point to any other
heap object. This makes it easier to reason about the behavior and can also
help to avoid leaks or optimize data structures containing triggers, because
it is safe to hold bounded amounts of signaled triggers.
- The `Trigger` abstraction is essentially first-order, which provides a clear
separation between a scheduler and programs, or fibers, running on a
scheduler. The `await` operation performs the `Await` effect, which passes the
trigger to the scheduler. The scheduler then attaches its own callback to the
trigger using `on_signal`. This way a scheduler does not call arbitrary user
specified code in the `Await` effect handler.
- Separating the creation of a trigger from the `await` operation allows one to
easily insert a trigger into any number of places and allows the trigger to be
potentially concurrently signaled before the `Await` effect is performed in
which case the effect can be skipped entirely.
- No value is propagated with a trigger. This makes triggers simpler and makes
it less likely for one to e.g. accidentally drop such a value. In many cases,
like with the `Ivar`, there is already a data structure through which values
can be propagated.
- The `signal` operation gives no indication of whether a fiber will then be
resumed as canceled or not. This gives maximal flexibility for the scheduler
and also makes it clear that cancelation must be handled based on the return
value of `await`.
### `Computation`
A `Computation` basically holds the status, i.e. _running_, _returned_, or
_canceled_, of some sort of computation and allows anyone with access to the
computation to attach triggers to it to be signaled in case the computation
stops running.
Here is an extract from the signature of the
[`Computation` module](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Computation/index.html):
```ocaml skip
type 'a t
val create : unit -> 'a t
val try_attach : 'a t -> Trigger.t -> bool
val detach : 'a t -> Trigger.t -> unit
val try_return : 'a t -> 'a -> bool
val try_cancel : 'a t -> exn -> Printexc.raw_backtrace -> bool
val check : 'a t -> unit
val await : 'a t -> 'a
```
A `Computation` directly provides a superset of the functionality of the `Ivar`
we sketched in the previous section:
```ocaml
type 'a t = 'a Computation.t
let create : unit -> 'a t = Computation.create
let try_fill : 'a t -> 'a -> bool =
Computation.try_return
let read : 'a t -> 'a = Computation.await
```
However, what really makes the `Computation` useful is the ability to
momentarily attach triggers to it. A `Computation` essentially implements a
specialized lock-free bag of triggers, which allows one to implement dynamic
completion propagation networks.
The `Computation` abstraction is also designed with both simplicity and
flexibility in mind:
- Similarly to `Trigger`, `Computation` has single-assignment semantics, which
makes it easier to reason about.
- Unlike a typical cancelation context of a structured concurrency model,
`Computation` is unopinionated in that it does not impose a specific
hierarchical structure.
- Anyone may ask to be notified when a `Computation` is completed by attaching
triggers to it and anyone may complete a `Computation`. This makes
`Computation` an omnidirectional communication primitive.
Interestingly, and unintentionally, it turns out that, given
[the ability to complete two (or more) computations atomically](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Computation/Tx/index.html),
`Computation` is essentially expressive enough to implement the
[event](https://ocaml.org/manual/latest/api/Event.html) abstraction of
[Concurrent ML](https://en.wikipedia.org/wiki/Concurrent_ML). The same features
that make `Computation` suitable for implementing more or less arbitrary dynamic
completion propagation networks make it suitable for implementing Concurrent ML
style abstractions.
### `Fiber`
A fiber corresponds to an independent thread of execution. Technically an
effects based scheduler creates a fiber, effectively giving it an identity, as
it runs some function under its handler. The `Fiber` abstraction provides a way
to share a proxy identity, and a bit of state, between a scheduler and other
concurrent abstractions.
Here is an extract from the signature of the
[`Fiber` module](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Fiber/index.html):
```ocaml skip
type t
val current : unit -> t
val create : forbid:bool -> 'a Computation.t -> t
val spawn : t -> (t -> unit) -> unit
val get_computation : t -> Computation.packed
val set_computation : t -> Computation.packed -> unit
val has_forbidden : t -> bool
val exchange : t -> forbid:bool -> bool
module FLS : sig (* ... *) end
```
Fibers are where all of the low level bits and pieces of Picos come together,
which makes it difficult to give both meaningful and concise examples, but let's
implement a slightly simplistic structured concurrency mechanism:
```ocaml skip
type t (* represents a scope *)
val run : (t -> unit) -> unit
val fork : t -> (unit -> unit) -> unit
```
The idea here is that `run` creates a "scope" and waits until all of the fibers
forked into the scope have finished. In case any fiber raises an unhandled
exception, or the main fiber that created the scope is canceled, all of the
fibers are canceled and an exception is raised. To keep things slightly simpler,
only the first exception is kept.
A scope can be represented by a simple record type:
```ocaml
type t = {
count : int Atomic.t;
inner : unit Computation.t;
ended : Trigger.t;
}
```
The idea is that after a fiber is finished, we decrement the count and if it
becomes zero, we finish the computation and signal the main fiber that the scope
has ended:
```ocaml
let decr t =
let n = Atomic.fetch_and_add t.count (-1) in
if n = 1 then begin
Computation.finish t.inner;
Trigger.signal t.ended
end
```
When forking a fiber, we increment the count unless it already was zero, in
which case we raise an error:
```ocaml
let rec incr t =
let n = Atomic.get t.count in
if n = 0 then invalid_arg "ended";
if not (Atomic.compare_and_set t.count n (n + 1))
then incr t
```
The fork operation is now relatively straightforward to implement:
```ocaml
let fork t action =
incr t;
try
let main _ =
match action () with
| () -> decr t
| exception exn ->
let bt = Printexc.get_raw_backtrace () in
Computation.cancel t.inner exn bt;
decr t
in
let fiber =
Fiber.create ~forbid:false t.inner
in
Fiber.spawn fiber main
with canceled_exn ->
decr t;
raise canceled_exn
```
The above `fork` first increments the count and then tries to spawn a fiber. The
Picos interface specifies that when `Fiber.spawn` returns normally, the action,
`main`, must be called by the scheduler. This allows us to ensure that the
increment is always matched with a decrement.
Setting up a scope is the most complex operation:
<!--
```ocaml
let join _ _ _ _ = ()
```
-->
```ocaml
let run body =
let count = Atomic.make 1 in
let inner = Computation.create () in
let ended = Trigger.create () in
let t = { count; inner; ended } in
let fiber = Fiber.current () in
let (Packed outer) =
Fiber.get_computation fiber
in
let canceler =
Computation.attach_canceler
~from:outer
~into:t.inner
in
match
Fiber.set_computation fiber (Packed t.inner);
body t
with
| () -> join t outer canceler fiber
| exception exn ->
let bt = Printexc.get_raw_backtrace () in
Computation.cancel t.inner exn bt;
join t outer canceler fiber;
Printexc.raise_with_backtrace exn bt
```
The `Computation.attach_canceler` operation attaches a special trigger to
propagate cancelation from one computation into another. After the body exits,
`join`
```ocaml
let join t outer canceler fiber =
decr t;
Fiber.set_computation fiber (Packed outer);
let forbid = Fiber.exchange fiber ~forbid:true in
Trigger.await t.ended |> ignore;
Fiber.set fiber ~forbid;
Computation.detach outer canceler;
Computation.check t.inner;
Fiber.check fiber
```
is called to wait for the scoped fibers and restore the state of the main fiber.
An important detail is that propagation of cancelation is forbidden by setting
the `forbid` flag to `true` before the call of `Trigger.await`. This is
necessary to ensure that `join` does not exit, due to the fiber being canceled,
before all of the child fibers have actually finished. Finally, `join` checks
the inner computation and the fiber, which means that an exception will be
raised in case either was canceled.
The design of `Fiber` includes several key features:
- The low level design allows one to both avoid unnecessary overheads, such as
allocating a `Computation.t` for every fiber, when implementing simple
abstractions and also to implement more complex behaviors that might prove
difficult given e.g. a higher level design with a built-in notion of
hierarchy.
- As `Fiber.t` stores the `forbid` flag and the `Computation.t` associated with
the fiber one need not pass those as arguments through the program. This
allows various concurrent abstractions to be given traditional interfaces,
which would otherwise need to be complicated.
- Effects are relatively expensive. The cost of performing effects can be
amortized by obtaining the `Fiber.t` once and then manipulating it multiple
times.
- A `Fiber.t` also provides an identity for the fiber. It has so far proven to
be sufficient for most purposes. Fiber local storage, which we do not cover
here, can be used to implement, for example, a unique integer id for fibers.
### Assumptions
Now, consider the `Ivar` abstraction presented earlier as an example of the use
of the `Trigger` abstraction. That `Ivar` implementation, as well as the
`Computation` based implementation, works exactly as desired inside the scope
abstraction presented in the previous section. In particular, a blocked
`Ivar.read` can be canceled, either when another fiber in a scope raises an
unhandled exception or when the main fiber of the scope is canceled, which
allows the fiber to continue by raising an exception after cleaning up. In fact,
Picos comes with a number of libraries that all would work quite nicely with the
examples presented here.
For example, a library provides an operation to run a block with a timeout on
the current fiber. One could use it with `Ivar.read` to implement a read
operation
[with a timeout](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/Control/index.html#val-terminate_after):
```ocaml
let read_in ~seconds ivar =
Control.terminate_after ~seconds @@ fun () ->
Ivar.read ivar
```
This interoperability is not accidental. For example, the scope abstraction
basically assumes that one does not use `Fiber.set_computation`, in an arbitrary
unscoped manner inside the scoped fibers. An idea with the Picos interface
actually is that it is not supposed to be used by applications at all and most
higher level libraries should be built on top of libraries that do not directly
expose elements of the Picos interface.
Perhaps more interestingly, there are obviously limits to what can be achieved
in an "interoperable" manner. Imagine an operation like
```ocaml skip
val at_exit : (unit -> unit) -> unit
```
that would allow one to run an action just before a fiber exits. One could, of
course, use a custom spawn function that would support such cleanup, but then
`at_exit` could only be used on fibers spawned through that particular spawn
function.
### The effects
As mentioned previously, the Picos interface is implemented partially in terms
of five effects:
```ocaml version>=5.0.0
type _ Effect.t +=
| Await : Trigger.t -> (exn * Printexc.raw_backtrace) option Effect.t
| Cancel_after : {
seconds : float;
exn: exn;
bt : Printexc.raw_backtrace;
computation : 'a Computation.t;
}
-> unit Effect.t
| Current : t Effect.t
| Yield : unit Effect.t
| Spawn : {
fiber : Fiber.t;
main : (Fiber.t -> unit);
}
-> unit Effect.t
```
A scheduler must handle those effects as specified in the Picos documentation.
The Picos interface does not, in particular, dictate which ready fibers a
scheduler must run next and on which domains. Picos also does not require that a
fiber should stay on the domain on which it was spawned. Abstractions
implemented against the Picos interface should not assume any particular
scheduling.
Picos actually comes with
[a randomized multithreaded scheduler](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_randos/index.html),
that, after handling any of the effects, picks the next ready fiber randomly. It
has proven to be useful for testing that abstractions implemented in Picos do
not make invalid scheduling assumptions.
When a concurrent abstraction requires a particular scheduling, it should
primarily be achieved through the use of synchronization abstractions like when
programming with traditional threads. Application programs may, of course, pick
specific schedulers.
## Status and results
We have an experimental design and implementation of the core Picos interface as
illustrated in the previous section. We have also created several _Picos
compatible_
[sample schedulers](https://ocaml-multicore.github.io/picos/doc/picos_mux/index.html).
A scheduler, in this context, just multiplexes fibers to run on one or more
system level threads. We have also created some sample higher-level
[scheduler agnostic libraries](https://ocaml-multicore.github.io/picos/doc/picos_std/index.html)
_Implemented in Picos_. These libraries include
[a library for resource management](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_finally/index.html),
[a library for structured concurrency](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/index.html),
[a library of synchronization primitives](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_sync/index.html),
and
[an asynchronous I/O library](https://ocaml-multicore.github.io/picos/doc/picos_io/Picos_io/index.html).
The synchronization library and the I/O library intentionally mimic libraries
that come with the OCaml distribution. All of the libraries work with all of the
schedulers and all of these _elements_ are interoperable and entirely opt-in.
What is worth explicitly noting is that all of these schedulers and libraries
are small, independent, and highly modular pieces of code. They all crucially
depend on and are decoupled from each other via the core Picos interface
library. A basic single threaded scheduler implementation requires only about
100 lines of code (LOC). A more complex parallel scheduler might require a
couple of hundred LOC. The scheduler agnostic libraries are similarly small.
Here is an
[example](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/index.html#a-simple-echo-server-and-clients)
of a concurrent echo server using the scheduler agnostic libraries provided as
samples:
```ocaml
let run_server server_fd =
Unix.listen server_fd 8;
Flock.join_after begin fun () ->
while true do
let@ client_fd = instantiate Unix.close @@ fun () ->
Unix.accept ~cloexec:true server_fd |> fst
in
Flock.fork begin fun () ->
let@ client_fd = move client_fd in
Unix.set_nonblock client_fd;
let bs = Bytes.create 100 in
let n =
Unix.read client_fd bs 0 (Bytes.length bs)
in
Unix.write client_fd bs 0 n |> ignore
end
done
end
```
The
[`Unix`](https://ocaml-multicore.github.io/picos/doc/picos_io/Picos_io/Unix/index.html)
module is provided by the I/O library. The operations on file descriptors on
that module, such as `accept`, `read`, and `write`, use the Picos interface to
suspend fibers allowing other fibers to run while waiting for I/O. The
[`Flock`](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/Flock/index.html)
module comes from the structured concurrency library. A call of
[`join_after`](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/Flock/index.html#val-join_after)
returns only after all the fibers
[`fork`](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/Flock/index.html#val-fork)ed
into the flock have terminated. If the main fiber of the flock is canceled, or
any fiber within the flock raises an unhandled exception, all the fibers within
the flock will be canceled and an exception will be raised on the main fiber of
the flock. The
[`let@`](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_finally/index.html#val-let@),
[`finally`](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_finally/index.html#val-instantiate),
and
[`move`](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_finally/index.html#val-move)
operations come from the resource management library and allow dealing with
resources in a leak-free manner. The responsibility to close the `client_fd`
socket is
[`move`](https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_finally/index.html#val-move)d
from the main server fiber to a fiber forked to handle that client.
We should emphasize that the above is just an example. The Picos interface
should be both expressive and efficient enough to support practical
implementations of many different kinds of concurrent programming models. Also,
as described previously, the Picos interface does not, for example, internally
implement structured concurrency. However, the abstractions provided by Picos
are designed to allow structured and unstructured concurrency to be _Implemented
in Picos_ as libraries that will then work with any _Picos compatible_ scheduler
and with other concurrent abstractions.
Finally, an interesting demonstration that Picos really fundamentally is an
interface is
[a prototype _Picos compatible_ direct style interface to Lwt](https://ocaml-multicore.github.io/picos/doc/picos_lwt/Picos_lwt/index.html).
The implementation uses shallow effect handlers and defers all scheduling
decisions to Lwt. Running a program with the scheduler returns a Lwt promise.
## Future work
As mentioned previously, Picos is still an ongoing project and the design is
considered experimental. We hope that Picos soon matures to serve the needs of
both the commercial users of OCaml and the community at large.
Previous sections already touched a couple of updates currently in development,
such as the support for finalizing resources stored in
[`FLS`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Fiber/FLS/index.html)
and the development of Concurrent ML style abstractions. We also have ongoing
work to formalize aspects of the Picos interface.
One potential change we will be investigating is whether the
[`Computation`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Computation/index.html)
abstraction should be simplified to only support cancelation.
The implementation of some operations, such as
[`Fiber.current`](https://ocaml-multicore.github.io/picos/doc/picos/Picos/Fiber/index.html#val-current)
to retrieve the current fiber proxy identity, do not strictly need to be
effects. Performing an effect is relatively expensive and we will likely design
a mechanism to store a reference to the current fiber in some sort of local
storage, which could significantly improve the performance of certain
abstractions, such as checked mutexes, that need to access the current fiber.
We also plan to develop a minimalist library for spawning threads over domains,
much like Moonpool, in a cooperative manner for schedulers and other libraries.
We also plan to make Domainslib Picos compatible, which will require developing
a more efficient non-effects based interface for spawning fibers, and
investigate making Eio Picos compatible.
We also plan to design and implement asynchronous IO libraries for Picos using
various system call interface for asynchronous IO such as io_uring.
Finally, Picos is supposed to be an _open ecosystem_. If you have feedback or
would like to work on something mentioned above, let us know.
## Motivation
There are already several concrete effects-based concurrent programming
libraries and models being developed. Here is a list of some such publicly
available projects:<sup>[\*](https://xkcd.com/927/)</sup>
1. [Affect](https://github.com/dbuenzli/affect) — "Composable concurrency
primitives with OCaml effects handlers (unreleased)",
2. [Domainslib](https://github.com/ocaml-multicore/domainslib) —
"Nested-parallel programming",
3. [Eio](https://github.com/ocaml-multicore/eio) — "Effects-Based Parallel IO
for OCaml",
4. [Fuseau](https://github.com/c-cube/fuseau) — "Lightweight fiber library for
OCaml 5",
5. [Miou](https://github.com/robur-coop/miou) — "A simple scheduler for OCaml
5",
6. [Moonpool](https://github.com/c-cube/moonpool) — "Commodity thread pools for
OCaml 5", and
7. [Riot](https://github.com/leostera/riot) — "An actor-model multi-core
scheduler for OCaml 5".
All of the above libraries are mutually incompatible with each other with the
exception that Domainslib, Eio, and Moonpool implement an earlier
interoperability proposal called
[domain-local-await](https://github.com/ocaml-multicore/domain-local-await/) or
DLA, which allows a concurrent programming library like
[Kcas](https://github.com/ocaml-multicore/kcas/)[\*](https://github.com/ocaml-multicore/kcas/pull/136)
to work on all of those. Unfortunately, DLA, by itself, is known to be
insufficient and the design has not been universally accepted.
By introducing a scheduler interface and key libraries, such as an IO library,
implemented on top of the interface, we hope that the scarce resources of the
OCaml community are not further divided into mutually incompatible ecosystems
built on top of such mutually incompatible concurrent programming libraries,
while, simultaneously, making it possible to experiment with many kinds of
concurrent programming models.
It should be
technically<sup>[\*](https://www.youtube.com/watch?v=hou0lU8WMgo)</sup> possible
for all the previously mentioned libraries, except
[Miou](https://github.com/robur-coop/miou), to
1. be made
[Picos compatible](https://ocaml-multicore.github.io/picos/doc/picos/index.html#picos-compatible),
i.e. to handle the Picos effects, and
2. have their elements
[implemented in Picos](https://ocaml-multicore.github.io/picos/doc/picos/index.html#implemented-in-picos),
i.e. to make them usable on other Picos-compatible schedulers.
Please read
[the reference manual](https://ocaml-multicore.github.io/picos/doc/index.html)
for further information.

View file

@ -0,0 +1,150 @@
{0 Picos — Interoperable effects based concurrency}
{1 Introduction}
{!Picos} is a {{:https://en.wikipedia.org/wiki/Systems_programming} systems
programming} interface between effects based schedulers and concurrent
abstractions. Picos is designed to enable an ecosystem of
{{:https://en.wikipedia.org/wiki/Interoperability} interoperable} elements of
{{:https://v2.ocaml.org/manual/effects.html} effects based}
{{:https://en.wikipedia.org/wiki/Cooperative_multitasking} cooperative}
{{:https://en.wikipedia.org/wiki/Concurrent_computing} concurrent programming
models} such as
- {{:https://en.wikipedia.org/wiki/Scheduling_(computing)} schedulers} that
multiplex large numbers of {{:https://en.wikipedia.org/wiki/Green_thread} user
level fibers} to run on a small number of system level threads,
- mechanisms for managing fibers and for
{{:https://en.wikipedia.org/wiki/Structured_concurrency} structuring
concurrency},
- communication and synchronization primitives, such as
{{:https://en.wikipedia.org/wiki/Monitor_(synchronization)} mutexes and
condition variables}, message queues,
{{:https://en.wikipedia.org/wiki/Software_transactional_memory} STMs}, and
more, and
- integrations with low level {{:https://en.wikipedia.org/wiki/Asynchronous_I/O}
asynchronous IO} systems.
If you are the author of an application level concurrent programming library or
framework, then Picos should not fundamentally be competing with your work.
However, Picos and libraries built on top of Picos probably do have overlap with
your work and making your work Picos compatible may offer benefits:
- You may find it useful that the {{!Picos} core} of Picos provides parallelism
safe building blocks for cancelation, which is a particularly tricky problem
to get right.
- You may find it useful that you don't have to reinvent many of the basic
communication and synchronization abstractions such as mutexes and condition
variables, promises, concurrent bounded queues, channels, and what not.
- You may benefit from further non-trivial libraries, such as IO libraries, that
you don't have to reimplement.
- Potential users of your work may be reassured and benefit from the ability to
mix-and-match your work with other Picos compatible libraries and frameworks.
Of course, interoperability does have some costs. It takes time to understand
Picos and it takes time to implement Picos compatibility. Implementing your
programming model elements in terms of the Picos interface may not always give
ideal results. To address concerns such as those, a conscious effort has been
made to keep Picos as minimal and unopinionated as possible.
{2 Interoperability}
Picos is essentially an interface between schedulers and concurrent
abstractions. Two phrases, {i Picos compatible} and {i Implemented in Picos},
are used to describe the opposing sides of this contract.
{3 Picos compatible}
The idea is that schedulers provide their own handlers for the Picos effects.
By handling the Picos effects a scheduler allows any libraries built on top of
the Picos interface to be used with the scheduler. Such a scheduler is then
said to be {i Picos compatible}.
{3 Implemented in Picos}
A scheduler is just one element of a concurrent programming model. Separately
from making a scheduler Picos compatible, one may choose to implement other
elements of the programming model, e.g. a particular approach to structuring
concurrency or a particular collection of communication and synchronization
primitives, in terms of the Picos interface. Such scheduler agnostic elements
can then be used on any Picos compatible scheduler and are said to be {i
Implemented in Picos}.
{2 Design goals and principles}
The {{!Picos} core} of Picos is designed and developed with various goals and
principles in mind.
- {b Simple}: Picos should be kept as simple as possible.
- {b Minimal}: Picos should be kept minimal. The dependency footprint should be
as small as possible. Convenience features should be built on top of the
interface.
- {b Safe}: Picos should be designed with safety in mind. The implementation
must be data race free. The interface should promote and always allow proper
resource management.
- {b Unopinionated}: Picos should not make strong design choices that are
controversial.
- {b Flexible}: Picos should allow higher level libraries as much freedom as
possible to make their own design choices.
The documentation of the {{!Picos} concepts} includes design rationale for some
of the specific ideas behind their detailed design.
{3 Constraints Liberate, Liberties Constrain}
Picos aims to be unopinionated and flexible enough to allow higher level
libraries to provide many different kinds of concurrent programming models.
While it is impossible to give a complete list of what Picos does not dictate,
it is perhaps illuminating to explicitly mention some of those:
- Picos does not implement
{{:https://en.wikipedia.org/wiki/Capability-based_security} capability-based
security}. Higher level libraries with or without capabilities may be built
on top of Picos.
- Picos never cancels computations implicitly. Higher level libraries may
decide when cancelation should be allowed to take effect.
- Picos does not dictate which fiber should be scheduled next after a Picos
effect. Different schedulers may freely use desired data structures (queues,
work-stealing deques, stacks, priority queues, ...) and, after handling any
Picos effect, freely decide which fiber to run next.
- Picos does not dictate how fibers should be managed. It is possible to
implement both unstructured and structured concurrent programming models on
top of Picos.
- Picos does not dictate which mechanisms applications should use for
communication and synchronization. It is possible to build many different
kinds of communication and synchronization mechanisms on top of Picos
including mutexes and condition variables, STMs, asynchronous and synchronous
message passing, {{:https://en.wikipedia.org/wiki/Actor_model} actors}, and
more.
- Picos does not dictate that there should be a connection between the scheduler
and other elements of the concurrent programming model. It is possible to
provide those separately and mix-and-match.
- Picos does not dictate which library to use for IO. It is possible to build
direct-style asynchronous IO libraries on top of Picos that can then be used
with any Picos compatible schedulers or concurrent programming models.
Let's build an incredible ecosystem of interoperable concurrent programming
libraries and frameworks!
{1 Libraries}
{!modules:
Picos
Picos_domain
Picos_thread
}
{1 Conventions}
Many operation in the Picos libraries use
{{:https://en.wikipedia.org/wiki/Non-blocking_algorithm} non-blocking}
algorithms. Unless explicitly specified otherwise,
- non-blocking operations in Picos are {i atomic} or {i strictly linearizable}
(i.e. {{:https://en.wikipedia.org/wiki/Linearizability} linearizable} and
{{:https://en.wikipedia.org/wiki/Database_transaction_schedule#Serializable}
serializable}), and
- {{:https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom}
lock-free} operations in Picos are designed to avoid having competing
operations of widely different complexities, which should make such operations
much less prone to starvation.

2
picos/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_event (picos_std.Picos_std_event)</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_event</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_event</span></code></h1><p>Basic event abstraction for <a href="../../picos/Picos/index.html"><code>Picos</code></a>.</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec module anchored" id="module-Event"><a href="#module-Event" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Event/index.html">Event</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>First-class synchronous communication abstraction.</p></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_event__ (picos_std.Picos_std_event__)</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_event__</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_event__</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_event__Event (picos_std.Picos_std_event__Event)</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_event__Event</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_event__Event</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Run (picos_std.Picos_std_structured.Run)</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; <a href="../index.html">Picos_std_structured</a> &#x00BB; Run</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_structured.Run</span></code></h1><p>Operations for running fibers in specific patterns.</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec value anchored" id="val-all"><a href="#val-all" class="anchor"></a><code><span><span class="keyword">val</span> all : <span><span><span>(<span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> list</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>all actions</code> starts the actions as separate fibers and waits until they all complete or one of them raises an unhandled exception other than <a href="../Control/index.html#exception-Terminate" title="Control.Terminate"><code>Terminate</code></a>, which is not counted as an error, after which the remaining fibers will be canceled.</p><p>⚠️ One of actions may be run on the current fiber.</p><p>⚠️ It is not guaranteed that any of the actions in the list are called. In particular, after any action raises an unhandled exception or after the main fiber is canceled, the actions that have not yet started may be skipped entirely.</p><p><code>all</code> is roughly equivalent to</p><pre class="language-ocaml"><code>let all actions =
Bundle.join_after @@ fun bundle -&gt;
List.iter (Bundle.fork bundle) actions</code></pre><p>but treats the list of actions as a single computation.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-any"><a href="#val-any" class="anchor"></a><code><span><span class="keyword">val</span> any : <span><span><span>(<span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> list</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>any actions</code> starts the actions as separate fibers and waits until one of them completes or raises an unhandled exception other than <a href="../Control/index.html#exception-Terminate" title="Control.Terminate"><code>Terminate</code></a>, which is not counted as an error, after which the rest of the started fibers will be canceled.</p><p>⚠️ One of actions may be run on the current fiber.</p><p>⚠️ It is not guaranteed that any of the actions in the list are called. In particular, after the first action returns successfully or after any action raises an unhandled exception or after the main fiber is canceled, the actions that have not yet started may be skipped entirely.</p><p><code>any</code> is roughly equivalent to</p><pre class="language-ocaml"><code>let any actions =
Bundle.join_after @@ fun bundle -&gt;
try
actions
|&gt; List.iter @@ fun action -&gt;
Bundle.fork bundle @@ fun () -&gt;
action ();
Bundle.terminate bundle
with Control.Terminate -&gt; ()</code></pre><p>but treats the list of actions as a single computation.</p></div></div></div></body></html>

View file

@ -0,0 +1,189 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_structured (picos_std.Picos_std_structured)</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_structured</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_structured</span></code></h1><p>Basic structured concurrency primitives for <a href="../../picos/Picos/index.html"><code>Picos</code></a>.</p><p>This library essentially provides one application programming interface for structuring fibers with any Picos compatible scheduler.</p><p>For the <a href="#examples" title="examples">examples</a> we open some modules:</p><pre class="language-ocaml"><code>open Picos_io
open Picos_std_event
open Picos_std_finally
open Picos_std_structured
open Picos_std_sync</code></pre></header><nav class="odoc-toc"><ul><li><a href="#modules">Modules</a></li><li><a href="#examples">Examples</a><ul><li><a href="#understanding-cancelation">Understanding cancelation</a></li><li><a href="#errors-and-cancelation">Errors and cancelation</a></li><li><a href="#a-simple-echo-server-and-clients">A simple echo server and clients</a></li></ul></li></ul></nav><div class="odoc-content"><h2 id="modules"><a href="#modules" class="anchor"></a>Modules</h2><div class="odoc-spec"><div class="spec module anchored" id="module-Control"><a href="#module-Control" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Control/index.html">Control</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Basic control operations and exceptions for structured concurrency.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Promise"><a href="#module-Promise" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Promise/index.html">Promise</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A cancelable promise.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Bundle"><a href="#module-Bundle" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Bundle/index.html">Bundle</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>An explicit dynamic bundle of fibers guaranteed to be joined at the end.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Flock"><a href="#module-Flock" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Flock/index.html">Flock</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>An implicit dynamic flock of fibers guaranteed to be joined at the end.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Run"><a href="#module-Run" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Run/index.html">Run</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Operations for running fibers in specific patterns.</p></div></div><h2 id="examples"><a href="#examples" class="anchor"></a>Examples</h2><h3 id="understanding-cancelation"><a href="#understanding-cancelation" class="anchor"></a>Understanding cancelation</h3><p>Consider the following program:</p><pre class="language-ocaml"><code>let main () =
Flock.join_after begin fun () -&gt;
let promise =
Flock.fork_as_promise @@ fun () -&gt;
Control.block ()
in
Flock.fork begin fun () -&gt;
Promise.await promise
end;
Flock.fork begin fun () -&gt;
let condition = Condition.create ()
and mutex = Mutex.create () in
Mutex.protect mutex begin fun () -&gt;
while true do
Condition.wait condition mutex
done
end
end;
Flock.fork begin fun () -&gt;
let sem =
Semaphore.Binary.make false
in
Semaphore.Binary.acquire sem
end;
Flock.fork begin fun () -&gt;
let sem =
Semaphore.Counting.make 0
in
Semaphore.Counting.acquire sem
end;
Flock.fork begin fun () -&gt;
Event.sync (Event.choose [])
end;
Flock.fork begin fun () -&gt;
let latch = Latch.create 1 in
Latch.await latch
end;
Flock.fork begin fun () -&gt;
let ivar = Ivar.create () in
Ivar.read ivar
end;
Flock.fork begin fun () -&gt;
let stream = Stream.create () in
Stream.read (Stream.tap stream)
|&gt; ignore
end;
Flock.fork begin fun () -&gt;
let@ inn, out = finally
Unix.close_pair @@ fun () -&gt;
Unix.socketpair ~cloexec:true
PF_UNIX SOCK_STREAM 0
in
Unix.set_nonblock inn;
let n =
Unix.read inn (Bytes.create 1)
0 1
in
assert (n = 1)
end;
Flock.fork begin fun () -&gt;
let a_month =
60.0 *. 60.0 *. 24.0 *. 30.0
in
Control.sleep ~seconds:a_month
end;
(* Let the children get stuck *)
Control.sleep ~seconds:0.1;
Flock.terminate ()
end</code></pre><p>First of all, note that above the <a href="../Picos_std_sync/Mutex/index.html" title="Picos_std_sync.Mutex"><code>Mutex</code></a>, <a href="../Picos_std_sync/Condition/index.html" title="Picos_std_sync.Condition"><code>Condition</code></a>, and <a href="../Picos_std_sync/Semaphore/index.html" title="Picos_std_sync.Semaphore"><code>Semaphore</code></a> modules come from the <a href="../Picos_std_sync/index.html"><code>Picos_std_sync</code></a> library and the <span class="xref-unresolved" title="Picos_io.Unix"><code>Unix</code></span> module comes from the <code>Picos_io</code> library. They do not come from the standard OCaml libraries.</p><p>The above program creates a <a href="Flock/index.html" title="Flock">flock</a> of fibers and <a href="Flock/index.html#val-fork" title="Flock.fork">forks</a> several fibers to the flock that all block in various ways. In detail,</p><ul><li><a href="Control/index.html#val-block"><code>Control.block</code></a> never returns,</li><li><a href="Promise/index.html#val-await"><code>Promise.await</code></a> never returns as the promise won't be completed,</li><li><a href="../Picos_std_sync/Condition/index.html#val-wait" title="Picos_std_sync.Condition.wait"><code>Condition.wait</code></a> never returns, because the condition is never signaled,</li><li><a href="../Picos_std_sync/Semaphore/Binary/index.html#val-acquire" title="Picos_std_sync.Semaphore.Binary.acquire"><code>Semaphore.Binary.acquire</code></a> and <a href="../Picos_std_sync/Semaphore/Counting/index.html#val-acquire" title="Picos_std_sync.Semaphore.Counting.acquire"><code>Semaphore.Counting.acquire</code></a> never return, because the counts of the semaphores never change from <code>0</code>,</li><li><a href="../Picos_std_event/Event/index.html#val-sync" title="Picos_std_event.Event.sync"><code>Event.sync</code></a> never returns, because the event can never be committed to,</li><li><a href="../Picos_std_sync/Latch/index.html#val-await" title="Picos_std_sync.Latch.await"><code>Latch.await</code></a> never returns, because the count of the latch never reaches <code>0</code>,</li><li><a href="../Picos_std_sync/Ivar/index.html#val-read" title="Picos_std_sync.Ivar.read"><code>Ivar.read</code></a> never returns, because the incremental variable is never filled,</li><li><a href="../Picos_std_sync/Stream/index.html#val-read" title="Picos_std_sync.Stream.read"><code>Stream.read</code></a> never returns, because the stream is never pushed to,</li><li><span class="xref-unresolved" title="Picos_io.Unix.read"><code>Unix.read</code></span> never returns, because the socket is never written to, and the</li><li><a href="Control/index.html#val-sleep"><code>Control.sleep</code></a> call would return only after about a month.</li></ul><p>Fibers forked to a flock can be canceled in various ways. In the above program we call <a href="Flock/index.html#val-terminate"><code>Flock.terminate</code></a> to cancel all of the fibers and effectively close the flock. This allows the program to return normally immediately and without leaking or leaving anything in an invalid state:</p><pre class="language-ocaml"><code># Picos_mux_random.run_on ~n_domains:2 main
- : unit = ()</code></pre><p>Now, the point of the above example isn't that you should just call <a href="Flock/index.html#val-terminate" title="Flock.terminate"><code>terminate</code></a> when your program gets stuck. 😅</p><p>What the above example hopefully demonstrates is that concurrent abstractions like mutexes and condition variables, asynchronous IO libraries, and others can be designed to support cancelation.</p><p>Cancelation is a signaling mechanism that allows structured concurrent abstractions, like the <a href="Flock/index.html"><code>Flock</code></a> abstraction, to (hopefully) gracefully tear down concurrent fibers in case of errors. Indeed, one of the basic ideas behind the <a href="Flock/index.html"><code>Flock</code></a> abstraction is that in case any fiber forked to the flock raises an unhandled exception, the whole flock will be terminated and the error will raised from the flock, which allows you to understand what went wrong, instead of having to debug a program that mysteriously gets stuck, for example.</p><p>Cancelation can also, with some care, be used as a mechanism to terminate fibers once they are no longer needed. However, just like sleep, for example, cancelation is inherently prone to races, i.e. it is difficult to understand the exact point and state at which a fiber gets canceled and it is usually non-deterministic, and therefore cancelation is not recommended for use as a general synchronization or communication mechanism.</p><h3 id="errors-and-cancelation"><a href="#errors-and-cancelation" class="anchor"></a>Errors and cancelation</h3><p>Consider the following program:</p><pre class="language-ocaml"><code>let many_errors () =
Flock.join_after @@ fun () -&gt;
let latch = Latch.create 1 in
let fork_raising exn =
Flock.fork begin fun () -&gt;
Control.protect begin fun () -&gt;
Latch.await latch
end;
raise exn
end
in
fork_raising Exit;
fork_raising Not_found;
fork_raising Control.Terminate;
Latch.decr latch</code></pre><p>The above program starts three fibers and uses a <a href="../Picos_std_sync/Latch/index.html" title="Picos_std_sync.Latch">latch</a> to ensure that all of them have been started, before two of them raise errors and the third raises <a href="Control/index.html#exception-Terminate" title="Control.Terminate"><code>Terminate</code></a>, which is not considered an error in this library. Running the program</p><pre class="language-ocaml"><code># Picos_mux_fifo.run many_errors
Exception: Errors[Stdlib.Exit; Not_found]</code></pre><p>raises a collection of all of the <a href="Control/index.html#exception-Errors" title="Control.Errors">errors</a>.</p><h3 id="a-simple-echo-server-and-clients"><a href="#a-simple-echo-server-and-clients" class="anchor"></a>A simple echo server and clients</h3><p>Let's build a simple TCP echo server and run it with some clients.</p><p>We first define a function for the server:</p><pre class="language-ocaml"><code>let run_server server_fd =
Flock.join_after begin fun () -&gt;
while true do
let@ client_fd =
instantiate Unix.close @@ fun () -&gt;
Unix.accept
~cloexec:true server_fd |&gt; fst
in
(* Fork a fiber for client *)
Flock.fork begin fun () -&gt;
let@ client_fd =
move client_fd
in
Unix.set_nonblock client_fd;
let bs = Bytes.create 100 in
let n =
Unix.read client_fd bs 0
(Bytes.length bs)
in
Unix.write client_fd bs 0 n
|&gt; ignore
end
done
end</code></pre><p>The server function expects a listening socket. For each accepted client the server forks a new fiber to handle it. The client socket is <span class="xref-unresolved" title="Finally.move">moved</span> from the server fiber to the client fiber to avoid leaks and to ensure that the socket will be closed.</p><p>Let's then define a function for the clients:</p><pre class="language-ocaml"><code>let run_client server_addr =
let@ socket =
finally Unix.close @@ fun () -&gt;
Unix.socket ~cloexec:true
PF_INET SOCK_STREAM 0
in
Unix.set_nonblock socket;
Unix.connect socket server_addr;
let msg = &quot;Hello!&quot; in
Unix.write_substring
socket msg 0 (String.length msg)
|&gt; ignore;
let bytes =
Bytes.create (String.length msg)
in
let n =
Unix.read socket bytes 0
(Bytes.length bytes)
in
Printf.printf &quot;Received: %s\n%!&quot;
(Bytes.sub_string bytes 0 n)</code></pre><p>The client function takes the address of the server and connects a socket to the server address. It then writes a message to the server and reads a reply from the server and prints it.</p><p>Here is the main program:</p><pre class="language-ocaml"><code>let main () =
let@ server_fd =
finally Unix.close @@ fun () -&gt;
Unix.socket ~cloexec:true
PF_INET SOCK_STREAM 0
in
Unix.set_nonblock server_fd;
(* Let system determine the port *)
Unix.bind server_fd Unix.(
ADDR_INET(inet_addr_loopback, 0));
Unix.listen server_fd 8;
let server_addr =
Unix.getsockname server_fd
in
Flock.join_after ~on_return:`Terminate begin fun () -&gt;
(* Start server *)
Flock.fork begin fun () -&gt;
run_server server_fd
end;
(* Run clients concurrently *)
Flock.join_after begin fun () -&gt;
for _ = 1 to 5 do
Flock.fork @@ fun () -&gt;
run_client server_addr
done
end
end</code></pre><p>The main program creates a socket for the server and configures it. The server is then started as a fiber in a flock terminated on return. Then the clients are started to run concurrently in an inner flock.</p><p>Finally we run the main program with a scheduler:</p><pre class="language-ocaml"><code># Picos_mux_random.run_on ~n_domains:1 main
Received: Hello!
Received: Hello!
Received: Hello!
Received: Hello!
Received: Hello!
- : unit = ()</code></pre><p>As an exercise, you might want to refactor the server to avoid <span class="xref-unresolved" title="Finally.move">moving</span> the file descriptors and use a <span class="xref-unresolved" title="Finally.let@">recursive</span> accept loop instead. You could also <a href="Flock/index.html#val-terminate" title="Flock.terminate">terminate the whole flock</a> at the end instead of just terminating the server.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_structured__ (picos_std.Picos_std_structured__)</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_structured__</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_structured__</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_structured__Bundle (picos_std.Picos_std_structured__Bundle)</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_structured__Bundle</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_structured__Bundle</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_structured__Control (picos_std.Picos_std_structured__Control)</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_structured__Control</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_structured__Control</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_structured__Flock (picos_std.Picos_std_structured__Flock)</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_structured__Flock</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_structured__Flock</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_structured__Promise (picos_std.Picos_std_structured__Promise)</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_structured__Promise</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_structured__Promise</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_structured__Run (picos_std.Picos_std_structured__Run)</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_structured__Run</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_structured__Run</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Condition (picos_std.Picos_std_sync.Condition)</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; <a href="../index.html">Picos_std_sync</a> &#x00BB; Condition</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_sync.Condition</span></code></h1><p>A condition variable.</p><p> This intentionally mimics the interface of <a href="../../../ocaml/Stdlib/Condition/index.html"><code>Stdlib.Condition</code></a>. Unlike with the standard library condition variable, blocking on this condition variable allows an effects based scheduler to run other fibers on the thread.</p></header><div class="odoc-content"><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> t</span></code></div><div class="spec-doc"><p>Represents a condition variable.</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">?padded</span>:bool <span class="arrow">&#45;&gt;</span></span> <span>unit <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>create ()</code> return a new condition variable.</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><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="../Mutex/index.html#type-t">Mutex.t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>wait condition</code> unlocks the <code>mutex</code>, waits for the <code>condition</code>, and locks the <code>mutex</code> before returning or raising due to the operation being canceled.</p><p> If the fiber has been canceled and propagation of cancelation is allowed, this may raise the cancelation exception.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-signal"><a href="#val-signal" class="anchor"></a><code><span><span class="keyword">val</span> signal : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>signal condition</code> wakes up one fiber waiting on the <code>condition</code> variable unless there are no such fibers.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-broadcast"><a href="#val-broadcast" class="anchor"></a><code><span><span class="keyword">val</span> broadcast : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>broadcast condition</code> wakes up all the fibers waiting on the <code>condition</code> variable.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,4 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Latch (picos_std.Picos_std_sync.Latch)</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; <a href="../index.html">Picos_std_sync</a> &#x00BB; Latch</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_sync.Latch</span></code></h1><p>A dynamic single-use countdown latch.</p><p>Latches are typically used for determining when a finite set of parallel computations is done. If the size of the set is known a priori, then the latch can be initialized with the size as initial count and then each computation just <a href="#val-decr" title="decr">decrements</a> the latch.</p><p>If the size is unknown, i.e. it is determined dynamically, then a latch is initialized with a count of one, the a priori known computations are started and then the latch is <a href="#val-decr" title="decr">decremented</a>. When a computation is stsrted, the latch is <a href="#val-try_incr" title="try_incr">incremented</a>, and then <a href="#val-decr" title="decr">decremented</a> once the computation has finished.</p></header><div class="odoc-content"><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> t</span></code></div><div class="spec-doc"><p>Represents a dynamic countdown latch.</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">?padded</span>:bool <span class="arrow">&#45;&gt;</span></span> <span>int <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>create initial</code> creates a new countdown latch with the specified <code>initial</code> count.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>in case the specified <code>initial</code> count is negative.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_decr"><a href="#val-try_decr" class="anchor"></a><code><span><span class="keyword">val</span> try_decr : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_decr latch</code> attempts to decrement the count of the latch and returns <code>true</code> in case the count of the latch was greater than zero and <code>false</code> in case the count already was zero.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-decr"><a href="#val-decr" class="anchor"></a><code><span><span class="keyword">val</span> decr : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>decr latch</code> is equivalent to:</p><pre class="language-ocaml"><code>if not (try_decr latch) then
invalid_arg &quot;zero count&quot;</code></pre><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>in case the count of the latch is zero.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_incr"><a href="#val-try_incr" class="anchor"></a><code><span><span class="keyword">val</span> try_incr : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_incr latch</code> attempts to increment the count of the latch and returns <code>true</code> on success and <code>false</code> on failure, which means that the latch has already reached zero.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-incr"><a href="#val-incr" class="anchor"></a><code><span><span class="keyword">val</span> incr : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>incr latch</code> is equivalent to:</p><pre class="language-ocaml"><code>if not (try_incr latch) then
invalid_arg &quot;zero count&quot;</code></pre><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>in case the count of the latch is zero.</p></li></ul></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><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>await latch</code> returns after the count of the latch has reached zero.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-await_evt"><a href="#val-await_evt" class="anchor"></a><code><span><span class="keyword">val</span> await_evt : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> <span>unit <a href="../../Picos_std_event/Event/index.html#type-t">Picos_std_event.Event.t</a></span></span></code></div><div class="spec-doc"><p><code>await_evt latch</code> returns an event that can be committed to once the count of the latch has reached zero.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Binary (picos_std.Picos_std_sync.Semaphore.Binary)</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; <a href="../../index.html">Picos_std_sync</a> &#x00BB; <a href="../index.html">Semaphore</a> &#x00BB; Binary</nav><header class="odoc-preamble"><h1>Module <code><span>Semaphore.Binary</span></code></h1><p>A binary semaphore.</p></header><div class="odoc-content"><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> t</span></code></div><div class="spec-doc"><p>Represents a binary semaphore.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-make"><a href="#val-make" class="anchor"></a><code><span><span class="keyword">val</span> make : <span><span class="optlabel">?padded</span>:bool <span class="arrow">&#45;&gt;</span></span> <span>bool <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>make initial</code> creates a new binary semaphore with count of <code>1</code> in case <code>initial</code> is <code>true</code> and count of <code>0</code> otherwise.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-release"><a href="#val-release" class="anchor"></a><code><span><span class="keyword">val</span> release : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>release semaphore</code> sets the count of the semaphore to <code>1</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-acquire"><a href="#val-acquire" class="anchor"></a><code><span><span class="keyword">val</span> acquire : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>acquire semaphore</code> waits until the count of the semaphore is <code>1</code> and then atomically changes the count to <code>0</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_acquire"><a href="#val-try_acquire" class="anchor"></a><code><span><span class="keyword">val</span> try_acquire : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_acquire semaphore</code> attempts to atomically change the count of the semaphore from <code>1</code> to <code>0</code>.</p></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Counting (picos_std.Picos_std_sync.Semaphore.Counting)</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; <a href="../../index.html">Picos_std_sync</a> &#x00BB; <a href="../index.html">Semaphore</a> &#x00BB; Counting</nav><header class="odoc-preamble"><h1>Module <code><span>Semaphore.Counting</span></code></h1><p>A counting semaphore.</p></header><div class="odoc-content"><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> t</span></code></div><div class="spec-doc"><p>Represents a counting semaphore.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-make"><a href="#val-make" class="anchor"></a><code><span><span class="keyword">val</span> make : <span><span class="optlabel">?padded</span>:bool <span class="arrow">&#45;&gt;</span></span> <span>int <span class="arrow">&#45;&gt;</span></span> <a href="#type-t">t</a></span></code></div><div class="spec-doc"><p><code>make initial</code> creates a new counting semaphore with the given <code>initial</code> count.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>in case the given <code>initial</code> count is negative.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-release"><a href="#val-release" class="anchor"></a><code><span><span class="keyword">val</span> release : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>release semaphore</code> increments the count of the semaphore.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Sys_error</code> <p>in case the count would overflow.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-acquire"><a href="#val-acquire" class="anchor"></a><code><span><span class="keyword">val</span> acquire : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>acquire semaphore</code> waits until the count of the semaphore is greater than <code>0</code> and then atomically decrements the count.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-try_acquire"><a href="#val-try_acquire" class="anchor"></a><code><span><span class="keyword">val</span> try_acquire : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> bool</span></code></div><div class="spec-doc"><p><code>try_acquire semaphore</code> attempts to atomically decrement the count of the semaphore unless the count is already <code>0</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-get_value"><a href="#val-get_value" class="anchor"></a><code><span><span class="keyword">val</span> get_value : <span><a href="#type-t">t</a> <span class="arrow">&#45;&gt;</span></span> int</span></code></div><div class="spec-doc"><p><code>get_value semaphore</code> returns the current count of the semaphore. This should only be used for debugging or informational messages.</p></div></div></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Semaphore (picos_std.Picos_std_sync.Semaphore)</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; <a href="../index.html">Picos_std_sync</a> &#x00BB; Semaphore</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_sync.Semaphore</span></code></h1><p><a href="Counting/index.html"><code>Counting</code></a> and <a href="Binary/index.html"><code>Binary</code></a> semaphores.</p><p> This intentionally mimics the interface of <a href="../../../ocaml/Stdlib/Semaphore/index.html"><code>Stdlib.Semaphore</code></a>. Unlike with the standard library semaphores, blocking on these semaphores allows an effects based scheduler to run other fibers on the thread.</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec module anchored" id="module-Counting"><a href="#module-Counting" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Counting/index.html">Counting</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A counting semaphore.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Binary"><a href="#module-Binary" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Binary/index.html">Binary</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A binary semaphore.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,98 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_sync (picos_std.Picos_std_sync)</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_sync</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_sync</span></code></h1><p>Basic communication and synchronization primitives for <a href="../../picos/Picos/index.html"><code>Picos</code></a>.</p><p>This library essentially provides a conventional set of communication and synchronization primitives for concurrent programming with any Picos compatible scheduler.</p><p>For the <a href="#examples" title="examples">examples</a> we open some modules:</p><pre class="language-ocaml"><code>open Picos_std_structured
open Picos_std_sync</code></pre></header><nav class="odoc-toc"><ul><li><a href="#modules">Modules</a></li><li><a href="#examples">Examples</a><ul><li><a href="#a-simple-bounded-queue">A simple bounded queue</a></li></ul></li><li><a href="#conventions">Conventions</a></li></ul></nav><div class="odoc-content"><h2 id="modules"><a href="#modules" class="anchor"></a>Modules</h2><div class="odoc-spec"><div class="spec module anchored" id="module-Mutex"><a href="#module-Mutex" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Mutex/index.html">Mutex</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A mutual-exclusion lock or mutex.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Condition"><a href="#module-Condition" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Condition/index.html">Condition</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A condition variable.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Semaphore"><a href="#module-Semaphore" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Semaphore/index.html">Semaphore</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p><a href="Semaphore/Counting/index.html"><code>Counting</code></a> and <a href="Semaphore/Binary/index.html"><code>Binary</code></a> semaphores.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Lazy"><a href="#module-Lazy" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Lazy/index.html">Lazy</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A lazy suspension.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Latch"><a href="#module-Latch" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Latch/index.html">Latch</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A dynamic single-use countdown latch.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Ivar"><a href="#module-Ivar" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Ivar/index.html">Ivar</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>An incremental or single-assignment poisonable variable.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Stream"><a href="#module-Stream" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Stream/index.html">Stream</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>A lock-free, poisonable, many-to-many, stream.</p></div></div><h2 id="examples"><a href="#examples" class="anchor"></a>Examples</h2><h3 id="a-simple-bounded-queue"><a href="#a-simple-bounded-queue" class="anchor"></a>A simple bounded queue</h3><p>Here is an example of a simple bounded (blocking) queue using a mutex and condition variables:</p><pre class="language-ocaml"><code>module Bounded_q : sig
type 'a t
val create : capacity:int -&gt; 'a t
val push : 'a t -&gt; 'a -&gt; unit
val pop : 'a t -&gt; 'a
end = struct
type 'a t = {
mutex : Mutex.t;
queue : 'a Queue.t;
capacity : int;
not_empty : Condition.t;
not_full : Condition.t;
}
let create ~capacity =
if capacity &lt; 0 then
invalid_arg &quot;negative capacity&quot;
else {
mutex = Mutex.create ();
queue = Queue.create ();
capacity;
not_empty = Condition.create ();
not_full = Condition.create ();
}
let is_full_unsafe t =
t.capacity &lt;= Queue.length t.queue
let push t x =
let was_empty =
Mutex.protect t.mutex @@ fun () -&gt;
while is_full_unsafe t do
Condition.wait t.not_full t.mutex
done;
Queue.push x t.queue;
Queue.length t.queue = 1
in
if was_empty then
Condition.broadcast t.not_empty
let pop t =
let elem, was_full =
Mutex.protect t.mutex @@ fun () -&gt;
while Queue.length t.queue = 0 do
Condition.wait
t.not_empty t.mutex
done;
let was_full = is_full_unsafe t in
Queue.pop t.queue, was_full
in
if was_full then
Condition.broadcast t.not_full;
elem
end</code></pre><p>The above is definitely not the fastest nor the most scalable bounded queue, but we can now demonstrate it with the cooperative <code>Picos_mux_fifo</code> scheduler:</p><pre class="language-ocaml"><code># Picos_mux_fifo.run @@ fun () -&gt;
let bq =
Bounded_q.create ~capacity:3
in
Flock.join_after ~on_return:`Terminate begin fun () -&gt;
Flock.fork begin fun () -&gt;
while true do
Printf.printf &quot;Popped %d\n%!&quot;
(Bounded_q.pop bq)
done
end;
for i=1 to 5 do
Printf.printf &quot;Pushing %d\n%!&quot; i;
Bounded_q.push bq i
done;
Printf.printf &quot;All done?\n%!&quot;;
Control.yield ();
end;
Printf.printf &quot;Pushing %d\n%!&quot; 101;
Bounded_q.push bq 101;
Printf.printf &quot;Popped %d\n%!&quot;
(Bounded_q.pop bq)
Pushing 1
Pushing 2
Pushing 3
Pushing 4
Popped 1
Popped 2
Popped 3
Pushing 5
All done?
Popped 4
Popped 5
Pushing 101
Popped 101
- : unit = ()</code></pre><p>Notice how the producer was able to push three elements to the queue after which the fourth push blocked and the consumer was started. Also, after canceling the consumer, the queue could still be used just fine.</p><h2 id="conventions"><a href="#conventions" class="anchor"></a>Conventions</h2><p>The optional <code>padded</code> argument taken by several constructor functions, e.g. <a href="Latch/index.html#val-create"><code>Latch.create</code></a>, <a href="Mutex/index.html#val-create"><code>Mutex.create</code></a>, <a href="Condition/index.html#val-create"><code>Condition.create</code></a>, <a href="Semaphore/Counting/index.html#val-make"><code>Semaphore.Counting.make</code></a>, and <a href="Semaphore/Binary/index.html#val-make"><code>Semaphore.Binary.make</code></a>, defaults to <code>false</code>. When explicitly specified as <code>~padded:true</code> the object is allocated in a way to avoid <a href="https://en.wikipedia.org/wiki/False_sharing">false sharing</a>. For relatively long lived objects this can improve performance and make performance more stable at the cost of using more memory. It is not recommended to use <code>~padded:true</code> for short lived objects.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_sync__ (picos_std.Picos_std_sync__)</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_sync__</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_sync__</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_sync__Condition (picos_std.Picos_std_sync__Condition)</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_sync__Condition</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_sync__Condition</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_sync__Ivar (picos_std.Picos_std_sync__Ivar)</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_sync__Ivar</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_sync__Ivar</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Picos_std_sync__Latch (picos_std.Picos_std_sync__Latch)</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_sync__Latch</nav><header class="odoc-preamble"><h1>Module <code><span>Picos_std_sync__Latch</span></code></h1></header><div class="odoc-content"><p>This module is hidden.</p></div></body></html>

Some files were not shown because too many files have changed in this diff Show more