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