@@ -47,8 +47,8 @@ Features and properties:
4747 read-only compare (CMP) operations that can be performed on overlapping
4848 locations in parallel without interference.
4949
50- - ** _ Blocking await_ ** : The algorithm supports timeouts and awaiting for changes
51- to any number of shared memory locations.
50+ - ** _ Blocking await_ ** : The algorithm supports cancelation and awaiting for
51+ changes to any number of shared memory locations.
5252
5353- ** _ Composable_ ** : Independently developed transactions can be composed with
5454 ease sequentially, conjunctively, conditionally, and disjunctively.
@@ -76,7 +76,7 @@ is distributed under the [ISC license](LICENSE.md).
7676 - [ A transactional lock-free queue] ( #a-transactional-lock-free-queue )
7777 - [ Composing transactions] ( #composing-transactions )
7878 - [ Blocking transactions] ( #blocking-transactions )
79- - [ Timeouts] ( #timeouts )
79+ - [ Cancelation and Timeouts] ( #cancelation-and- timeouts )
8080 - [ A transactional lock-free leftist heap] ( #a-transactional-lock-free-leftist-heap )
8181 - [ Programming with transactional data structures] ( #programming-with-transactional-data-structures )
8282 - [ The dining philosophers problem] ( #the-dining-philosophers-problem )
@@ -101,14 +101,7 @@ is distributed under the [ISC license](LICENSE.md).
101101
102102To use the library
103103
104- <!--
105104``` ocaml
106- # #thread
107- ```
108- -->
109-
110- ``` ocaml
111- # #require "kcas"
112105# open Kcas
113106```
114107
@@ -143,6 +136,7 @@ Block waiting for changes to locations:
143136
144137``` ocaml
145138# let a_domain = Domain.spawn @@ fun () ->
139+ Scheduler.run @@ fun () ->
146140 let x = Loc.get_as (fun x -> Retry.unless (x <> 0); x) x in
147141 Printf.sprintf "The answer is %d!" x
148142val a_domain : string Domain.t = <abstr>
@@ -551,13 +545,28 @@ and then spawn a domain that tries to atomically both pop and dequeue:
551545
552546``` ocaml
553547# let a_domain = Domain.spawn @@ fun () ->
548+ Scheduler.run @@ fun () ->
554549 let tx ~xt = (pop ~xt a_stack, dequeue ~xt a_queue) in
555550 let (popped, dequeued) = Xt.commit { tx } in
556551 Printf.sprintf "I popped %d and dequeued %d!"
557552 popped dequeued
558553val a_domain : string Domain.t = <abstr>
559554```
560555
556+ ** Kcas** uses the [ Picos] ( https://github.com/ocaml-multicore/picos/ ) interface
557+ to implement blocking. Above ` Scheduler.run ` starts an effects based
558+ [ Picos compatible] ( https://ocaml-multicore.github.io/picos/doc/picos/index.html#interoperability )
559+ scheduler, which allows ** Kcas** to block in a scheduler friendly manner.
560+
561+ > ** _ Note_ ** : Typically your entire program would run inside a scheduler and you
562+ > should
563+ > [ fork fibers] ( https://ocaml-multicore.github.io/picos/doc/picos_mux/index.html#examples )
564+ > rather than spawn domains and start schedulers. The
565+ > [ MDX] ( https://github.com/realworldocaml/mdx ) tool used for checking this
566+ > document does not allow one to start a scheduler once and run individual code
567+ > snippets within the scheduler, which is why individual examples spawn domains
568+ > and start schedulers.
569+
561570The domain is now blocked waiting for changes to the stack and the queue. As
562571long as we don't populate both at the same time
563572
@@ -585,7 +594,7 @@ The retry mechanism essentially allows a transaction to wait for an arbitrary
585594condition and can function as a fairly expressive communication and
586595synchronization mechanism.
587596
588- #### Timeouts
597+ #### Cancelation and Timeouts
589598
590599> If you block, will they come?
591600
@@ -605,43 +614,30 @@ val pop_or_raise_if :
605614 xt:'a Xt.t -> bool Loc.t -> 'b list Loc.t -> xt:'c Xt.t -> 'b = <fun>
606615```
607616
608- This works, but creating, checking, and canceling timeouts properly can be a lot
609- of work. Therefore ** Kcas** also directly supports an optional ` timeoutf `
610- argument for potentially blocking operations. For example, to perform a blocking
611- pop with a timeout, one can simply explicitly pass the desired timeout in
612- seconds:
613-
614- ``` ocaml
615- # let an_empty_stack = stack () in
616- Xt.commit ~timeoutf:0.1 { tx = pop an_empty_stack }
617- Exception: Failure "Domain_local_timeout.set_timeoutf not implemented".
618- ```
619-
620- Oops! What happened above is that the
621- [ _ domain local timeout_ ] ( https://github.com/ocaml-multicore/domain-local-timeout )
622- mechanism used by ** Kcas** was not implemented on the current domain. The idea
623- is that, in the future, concurrent schedulers provide the mechanism out of the
624- box, but there is also a default implementation using the Stdlib ` Thread ` and
625- ` Unix ` modules that works on most platforms. However, to avoid direct
626- dependencies to ` Thread ` and ` Unix ` , we need to explicitly tell the library that
627- it can use those modules:
617+ This works, but creating, checking, and canceling timeouts properly in this
618+ manner can be a lot of work. Therefore ** Kcas** also directly supports
619+ [ cancelation] ( https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/index.html#understanding-cancelation )
620+ through the [ Picos] ( https://github.com/ocaml-multicore/picos/ ) interface. This
621+ both allows ** Kcas** transactions to be cleanly terminated in case the program
622+ has encountered an error and also allows one to simply use a timeout mechanism
623+ provided by the scheduler. For example, the sample
624+ [ structured concurrency library] ( https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/index.html )
628625
629626``` ocaml
630- # Domain_local_timeout.set_system (module Thread) (module Unix)
631- - : unit = ()
627+ # open Picos_std_structured
632628```
633629
634- This initialization, if needed, should be done by application code rather than
635- by libraries.
636-
637- If we now retry the previous example we will get a
638- [ ` Timeout ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Timeout/index.html#exception-Timeout )
639- exception as expected:
630+ for Picos provides the
631+ [ ` Control.terminate_after ` ] ( https://ocaml-multicore.github.io/picos/doc/picos_std/Picos_std_structured/Control/index.html#val-terminate_after )
632+ operation, which allows one to easily run an operation with a timeout on the
633+ current fiber:
640634
641635``` ocaml
642636# let an_empty_stack = stack () in
643- Xt.commit ~timeoutf:0.1 { tx = pop an_empty_stack }
644- Exception: Kcas.Timeout.Timeout.
637+ Scheduler.run @@ fun () ->
638+ Control.terminate_after ~seconds:0.1 @@ fun () ->
639+ Xt.commit { tx = pop an_empty_stack }
640+ Exception: Picos_std_structured__Control.Terminate.
645641```
646642
647643Besides
@@ -651,7 +647,7 @@ potentially blocking single location operations such as
651647[ ` update ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Loc/index.html#val-update ) ,
652648and
653649[ ` modify ` ] ( https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/Loc/index.html#val-modify )
654- support the optional ` timeoutf ` argument .
650+ support cancelation .
655651
656652#### A transactional lock-free leftist heap
657653
@@ -839,10 +835,9 @@ structures.
839835One source of ready-made data structures is
840836[ ** Kcas_data** ] ( https://ocaml-multicore.github.io/kcas/doc/kcas_data/Kcas_data/index.html ) .
841837Let's explore how we can leverage those data structures. Of course, first we
842- need to ` #require ` the package and we'll also open it for convenience:
838+ open ` Kcas_data ` for convenience:
843839
844840``` ocaml
845- # #require "kcas_data"
846841# open Kcas_data
847842```
848843
@@ -915,6 +910,7 @@ the philosophers:
915910 in
916911 Array.iter Domain.join @@ Array.init philosophers @@ fun i ->
917912 Domain.spawn @@ fun () ->
913+ Scheduler.run @@ fun () ->
918914 let fork_lhs = forks.(i)
919915 and fork_rhs = forks.((i + 1) mod philosophers)
920916 and eaten = eaten.(i) in
0 commit comments