Skip to content

Commit

Permalink
Timeouts
Browse files Browse the repository at this point in the history
  • Loading branch information
polytypic committed Jun 27, 2023
1 parent 0e1ef21 commit 657811f
Show file tree
Hide file tree
Showing 8 changed files with 353 additions and 60 deletions.
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ is distributed under the [ISC license](LICENSE.md).
- [A transactional lock-free queue](#a-transactional-lock-free-queue)
- [Composing transactions](#composing-transactions)
- [Blocking transactions](#blocking-transactions)
- [Timeouts](#timeouts)
- [A transactional lock-free leftist heap](#a-transactional-lock-free-leftist-heap)
- [Programming with transactional data structures](#programming-with-transactional-data-structures)
- [The dining philosophers problem](#the-dining-philosophers-problem)
Expand All @@ -76,6 +77,12 @@ is distributed under the [ISC license](LICENSE.md).

To use the library

<!--
```ocaml
# #thread
```
-->

```ocaml
# #require "kcas"
# open Kcas
Expand Down Expand Up @@ -562,6 +569,74 @@ The retry mechanism essentially allows a transaction to wait for an arbitrary
condition and can function as a fairly expressive communication and
synchronization mechanism.

#### Timeouts

> If you block, will they come?
That is a good question. Blocking indefinitely is often not acceptable.

A blocked transaction can be waken up by a write to any shared memory location
that was accessed by the transaction. This means that, given a suitable timeout
mechanism, one could e.g. setup a timeout that writes to a boolean shared memory
location that is accessed by a blocking transaction:

```ocaml
# let pop_or_raise_if ~xt timeout stack =
(* Check if timeout has expired: *)
if Xt.get ~xt timeout then raise Exit;
pop stack
val pop_or_raise_if :
xt:'a Xt.t -> bool Loc.t -> 'b list Loc.t -> xt:'c Xt.t -> 'b = <fun>
```

This works, but creating, checking, and canceling timeouts properly can be a lot
of work. Therefore **kcas** also directly supports an optional `timeoutf`
argument for potentially blocking operations. For example, to perform a blocking
pop with a timeout, one can simply explicitly pass the desired timeout in
seconds:

```ocaml
# let an_empty_stack = stack () in
Xt.commit ~timeoutf:0.1 { tx = pop an_empty_stack }
Exception: Failure "Domain_local_timeout.set_timeoutf not implemented".
```

Oops! What happened above is that the
[_domain local timeout_](https://github.com/ocaml-multicore/domain-local-timeout)
mechanism used by **kcas** was not implemented on the current domain. The idea
is that, in the future, concurrent schedulers provide the mechanism out of the
box, but there is also a default implementation using the Stdlib `Thread` and
`Unix` modules that works on most platforms. However, to avoid direct
dependencies to `Thread` and `Unix`, we need to explicitly tell the library that
it can use those modules:

```ocaml
# Domain_local_timeout.set_system (module Thread) (module Unix)
- : unit = ()
```

This initialization, if needed, should be done by application code rather than
by libraries.

If we now retry the previous example we will get a
[`Timeout`](https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Timeout/index.html#exception-Timeout)
exception as expected:

```ocaml
# let an_empty_stack = stack () in
Xt.commit ~timeoutf:0.1 { tx = pop an_empty_stack }
Exception: Kcas.Timeout.Timeout.
```

Besides
[`commit`](https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Xt/index.html#val-commit),
potentially blocking single location operations such as
[`get_as`](https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Loc/index.html#val-get_as),
[`update`](https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Loc/index.html#val-update),
and
[`modify`](https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Loc/index.html#val-modify)
support the optional `timeoutf` argument.

#### A transactional lock-free leftist heap

Let's implement something a bit more complicated,
Expand Down
1 change: 1 addition & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
(depends
(ocaml (>= 5.0))
(domain-local-await (>= 0.2.0))
(domain-local-timeout (>= 0.1.0))
(alcotest (and (>= 1.7.0) :with-test))
(mdx (and (>= 1.10.0) :with-test))))
(package (name kcas_data)
Expand Down
1 change: 1 addition & 0 deletions kcas.opam
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ depends: [
"dune" {>= "3.3"}
"ocaml" {>= "5.0"}
"domain-local-await" {>= "0.2.0"}
"domain-local-timeout" {>= "0.1.0"}
"alcotest" {>= "1.7.0" & with-test}
"mdx" {>= "1.10.0" & with-test}
"odoc" {with-doc}
Expand Down
2 changes: 1 addition & 1 deletion src/kcas/dune
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(library
(name kcas)
(public_name kcas)
(libraries domain-local-await))
(libraries domain-local-await domain-local-timeout))
Loading

0 comments on commit 657811f

Please sign in to comment.