Skip to content

Commit 6426050

Browse files
committed
Add blocking
1 parent 3a38477 commit 6426050

24 files changed

+1142
-229
lines changed

README.md

Lines changed: 318 additions & 43 deletions
Large diffs are not rendered by default.

dune-project

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
(homepage "https://github.com/ocaml-multicore/kcas")
88
(license "ISC")
99
(package (name kcas)
10-
(synopsis "Multi-word compare-and-set library")
10+
(synopsis "Software transactional memory based on lock-free multi-word compare-and-set")
1111
(depends
1212
(ocaml (>= 5.0))
1313
(mdx (and (>= 1.10.0) :with-test))))
1414
(package (name kcas_data)
15-
(synopsis "Compositional lock-free data structures")
15+
(synopsis "Compositional lock-free data structures and primitives for communication and synchronization")
1616
(depends
1717
(kcas (= :version))
1818
(mdx (and (>= 1.10.0) :with-test))))

kcas.opam

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# This file is generated by dune, edit dune-project instead
22
opam-version: "2.0"
3-
synopsis: "Multi-word compare-and-set library"
3+
synopsis:
4+
"Software transactional memory based on lock-free multi-word compare-and-set"
45
maintainer: ["KC Sivaramakrishnan <sk826@cl.cam.ac.uk>"]
56
authors: ["KC Sivaramakrishnan <sk826@cl.cam.ac.uk>"]
67
license: "ISC"

kcas_data.opam

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# This file is generated by dune, edit dune-project instead
22
opam-version: "2.0"
3-
synopsis: "Compositional lock-free data structures"
3+
synopsis:
4+
"Compositional lock-free data structures and primitives for communication and synchronization"
45
maintainer: ["KC Sivaramakrishnan <sk826@cl.cam.ac.uk>"]
56
authors: ["KC Sivaramakrishnan <sk826@cl.cam.ac.uk>"]
67
license: "ISC"

src/backoff.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1717
*)
1818

19+
(** Randomized exponential backoff mechanism. *)
20+
1921
type t
2022
(** Type of backoff values. *)
2123

src/domain_local_await.ml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
type mode = [ `Cancelable | `Protected ]
2+
type t = { release : unit -> unit; await : unit -> unit }
3+
4+
module Default = struct
5+
type t = { mutex : Mutex.t; condition : Condition.t; mutable alarm : bool }
6+
7+
let init () =
8+
let t =
9+
let mutex = Mutex.create ()
10+
and condition = Condition.create ()
11+
and alarm = false in
12+
{ mutex; condition; alarm }
13+
in
14+
let methods =
15+
let release () =
16+
if not t.alarm then (
17+
Mutex.lock t.mutex;
18+
t.alarm <- true;
19+
Mutex.unlock t.mutex;
20+
Condition.signal t.condition)
21+
and await () =
22+
if not t.alarm then (
23+
Mutex.lock t.mutex;
24+
while not t.alarm do
25+
Condition.wait t.condition t.mutex
26+
done;
27+
Mutex.unlock t.mutex)
28+
in
29+
{ release; await }
30+
in
31+
fun (_ : mode) ->
32+
t.alarm <- false;
33+
methods
34+
end
35+
36+
let key = Domain.DLS.new_key Default.init
37+
38+
let using ~prepare_for_await ~while_running =
39+
let old = Domain.DLS.get key in
40+
Domain.DLS.set key prepare_for_await;
41+
Fun.protect ~finally:(fun () -> Domain.DLS.set key old) while_running
42+
43+
let prepare_for_await mode = Domain.DLS.get key mode

src/domain_local_await.mli

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
(** A scheduler independent blocking mechanism. *)
2+
3+
type mode =
4+
[ `Cancelable
5+
(** In the [`Cancelable] mode {!prepare_for_await} and {!t.await} are
6+
allowed to raise an (unspecified) exception that indicates that the
7+
caller's fiber has been canceled (and should terminate). If an
8+
exception is raised, then the caller should perform whatever cleanup is
9+
necessary to e.g. avoid space leaks. *)
10+
| `Protected
11+
(** In the [`Protected] mode {!prepare_for_await} and {!t.await} should act
12+
as if the caller's fiber has not been canceled. The [`Protected] mode
13+
should only be used in special cases such as when await might be needed
14+
during cleanup actions during stack unwinding. *)
15+
]
16+
(** Specifies a mode of operation regarding cancellation. *)
17+
18+
type t = {
19+
release : unit -> unit;
20+
(** [t.release ()] resumes the corresponding caller of [t.await ()] or
21+
does nothing in case the corresponding [t.await ()] has already
22+
resumed or the target fiber has been canceled.
23+
24+
{b NOTE}: An implementation of [t.release ()] should never fail. *)
25+
await : unit -> unit;
26+
(** [t.await ()] suspends the caller at most until [t.release ()] is
27+
called. *)
28+
}
29+
(** Represents an asynchronous trigger.
30+
31+
{b NOTE}: {!release} and {!await} should be domain safe and ideally
32+
optimized with the assumption that {!release} may be called multiple times
33+
and even before {!await} is called. Furthermore, {!await} may be called at
34+
most once. *)
35+
36+
val prepare_for_await : mode -> t
37+
(** [prepare_for_await mode] prepares and returns a trigger [t] for (at most)
38+
one use of [t.await ()] by calling the [prepare] function registered for the
39+
current domain.
40+
41+
{b NOTE}: It is allowed for two different calls of [prepare_for_await] to
42+
return the same trigger and e.g. share a single trigger per domain or per
43+
fiber or even just have one single trigger. *)
44+
45+
val using : prepare_for_await:(mode -> t) -> while_running:(unit -> 'a) -> 'a
46+
(** [using ~prepare_for_await ~while_running] registers the given asynchronous
47+
trigger mechanism for the current domain for the duration of running the
48+
given scheduler. In other words, this sets the implementation of
49+
{!prepare_for_await} for the current domain.
50+
51+
{b NOTE}: The given [prepare_for_await] function is called every time
52+
{!prepare_for_await} is called while the scheduler is running.
53+
54+
{b NOTE}: This is normally only called by libraries that implement
55+
schedulers and the specified [prepare_for_await] typically returns a trigger
56+
mechanism {!t} that tightly integrates with the scheduler by e.g. performing
57+
an effect to suspend the current fiber when {!t.await} is called. *)

0 commit comments

Comments
 (0)