Skip to content

Commit 8937436

Browse files
committed
Avoid code duplication in Treiber's stack using a GADT
1 parent eccbfc7 commit 8937436

File tree

2 files changed

+24
-39
lines changed

2 files changed

+24
-39
lines changed

Diff for: src_lockfree/treiber_stack.ml

+23-38
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,31 @@
11
(** Treiber's Lock Free stack *)
22

3-
type 'a node = Nil | Next of 'a * 'a node
4-
type 'a t = { head : 'a node Atomic.t }
3+
type 'a node = Nil | Cons of { value : 'a; tail : 'a node }
4+
type 'a t = 'a node Atomic.t
55

6-
let create () =
7-
let head = Nil in
8-
{ head = Atomic.make head }
6+
let create () = Atomic.make Nil |> Multicore_magic.copy_as_padded
7+
let is_empty t = Atomic.get t == Nil
98

10-
let is_empty q = match Atomic.get q.head with Nil -> true | Next _ -> false
9+
let rec push t value backoff =
10+
let tail = Atomic.get t in
11+
let cons = Cons { value; tail } in
12+
if not (Atomic.compare_and_set t tail cons) then
13+
push t value (Backoff.once backoff)
1114

12-
let rec push backoff q v =
13-
let head = Atomic.get q.head in
14-
let new_node = Next (v, head) in
15-
if Atomic.compare_and_set q.head head new_node then ()
16-
else
17-
let backoff = Backoff.once backoff in
18-
push backoff q v
19-
20-
let push q v = push Backoff.default q v
15+
let push t value = push t value Backoff.default
2116

2217
exception Empty
2318

24-
let rec pop backoff q =
25-
let s = Atomic.get q.head in
26-
match s with
27-
| Nil -> raise Empty
28-
| Next (v, next) ->
29-
if Atomic.compare_and_set q.head s next then v
30-
else
31-
let backoff = Backoff.once backoff in
32-
pop backoff q
33-
34-
let pop q = pop Backoff.default q
35-
36-
let rec pop_opt backoff q =
37-
let s = Atomic.get q.head in
38-
match s with
39-
| Nil -> None
40-
| Next (v, next) ->
41-
if Atomic.compare_and_set q.head s next then Some v
42-
else
43-
let backoff = Backoff.once backoff in
44-
pop_opt backoff q
45-
46-
let pop_opt q = pop_opt Backoff.default q
19+
type ('a, _) poly = Option : ('a, 'a option) poly | Value : ('a, 'a) poly
20+
21+
let rec pop_as : type a r. a t -> Backoff.t -> (a, r) poly -> r =
22+
fun t backoff poly ->
23+
match Atomic.get t with
24+
| Nil -> begin match poly with Option -> None | Value -> raise Empty end
25+
| Cons cons_r as cons ->
26+
if Atomic.compare_and_set t cons cons_r.tail then
27+
match poly with Option -> Some cons_r.value | Value -> cons_r.value
28+
else pop_as t (Backoff.once backoff) poly
29+
30+
let pop t = pop_as t Backoff.default Value
31+
let pop_opt t = pop_as t Backoff.default Option

Diff for: test/treiber_stack/dune

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
(test
77
(package saturn_lockfree)
88
(name treiber_stack_dscheck)
9-
(libraries atomic dscheck alcotest backoff)
9+
(libraries atomic dscheck alcotest backoff multicore-magic)
1010
(enabled_if
1111
(not
1212
(and

0 commit comments

Comments
 (0)