Skip to content

Commit a97c4fb

Browse files
committed
Reduce memory use of external reference counting
This uses the recently added `try_compare_and_remove` operation in the hash table to avoid having an extra `Atomic` indirection. This also simplifies the update logic.
1 parent 33c1c84 commit a97c4fb

File tree

1 file changed

+36
-46
lines changed

1 file changed

+36
-46
lines changed

lib/picos_aux.rc/picos_aux_rc.ml

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -31,56 +31,47 @@ struct
3131
match bt with Some bt -> bt | None -> Printexc.get_callstack 15
3232
in
3333
if
34-
Htbl.try_add ht t
35-
(Atomic.make { count_and_bits = count_1 lor Bool.to_int dispose; bt })
34+
Htbl.try_add ht t { count_and_bits = count_1 lor Bool.to_int dispose; bt }
3635
then t
37-
else begin
38-
(* We assume resources may only be reused after they have been
39-
disposed. *)
40-
created ()
41-
end
36+
else created ()
4237

43-
let unsafe_get = Fun.id
44-
45-
let rec incr t entry backoff =
46-
let before = Atomic.get entry in
47-
if
48-
before.count_and_bits < count_1
49-
|| before.count_and_bits land closed_bit <> 0
50-
then disposed ()
51-
else
52-
let count_and_bits = before.count_and_bits + count_1 in
53-
let after = { before with count_and_bits } in
54-
if not (Atomic.compare_and_set entry before after) then
55-
incr t entry (Backoff.once backoff)
56-
57-
let incr t =
38+
let rec incr t backoff =
5839
match Htbl.find_exn ht t with
40+
| before ->
41+
if before.count_and_bits land closed_bit <> 0 then disposed ()
42+
else
43+
let count_and_bits = before.count_and_bits + count_1 in
44+
let after = { before with count_and_bits } in
45+
if not (Htbl.try_compare_and_set ht t before after) then
46+
incr t (Backoff.once backoff)
5947
| exception Not_found -> disposed ()
60-
| entry -> incr t entry Backoff.default
61-
62-
let rec decr closed_bit t entry backoff =
63-
let before = Atomic.get entry in
64-
let count_and_bits = (before.count_and_bits - count_1) lor closed_bit in
65-
if count_and_bits < 0 then disposed ()
66-
else
67-
let after = { before with count_and_bits } in
68-
if not (Atomic.compare_and_set entry before after) then
69-
decr closed_bit t entry (Backoff.once backoff)
70-
else if count_and_bits < count_1 then begin
71-
Htbl.try_remove ht t |> ignore;
72-
(* We must dispose the resource as the last step, because the value
73-
might be reused after it has been disposed. *)
74-
if after.count_and_bits land dispose_bit <> 0 then Resource.dispose t
75-
end
76-
77-
let decr ?close t =
48+
49+
let rec decr closed_bit t backoff =
7850
match Htbl.find_exn ht t with
51+
| before ->
52+
if before.count_and_bits < count_1 * 2 then
53+
if Htbl.try_compare_and_remove ht t before then begin
54+
if before.count_and_bits land dispose_bit <> 0 then
55+
Resource.dispose t
56+
end
57+
else decr closed_bit t (Backoff.once backoff)
58+
else
59+
let count_and_bits =
60+
(before.count_and_bits - count_1) lor closed_bit
61+
in
62+
let after = { before with count_and_bits } in
63+
if not (Htbl.try_compare_and_set ht t before after) then
64+
decr closed_bit t (Backoff.once backoff)
7965
| exception Not_found -> disposed ()
80-
| entry ->
81-
decr
82-
(match close with None | Some false -> 0 | Some true -> closed_bit)
83-
t entry Backoff.default
66+
67+
let[@inline] incr t = incr t Backoff.default
68+
69+
let[@inline] decr ?close t =
70+
decr
71+
(match close with None | Some false -> 0 | Some true -> closed_bit)
72+
t Backoff.default
73+
74+
let unsafe_get = Fun.id
8475

8576
type info = {
8677
resource : Resource.t;
@@ -92,8 +83,7 @@ struct
9283

9384
let infos () =
9485
Htbl.to_seq ht
95-
|> Seq.map @@ fun (resource, entry) ->
96-
let { count_and_bits; bt } = Atomic.get entry in
86+
|> Seq.map @@ fun (resource, { count_and_bits; bt }) ->
9787
let count = count_and_bits lsr count_shift in
9888
let closed = count_and_bits land closed_bit <> 0 in
9989
let dispose = count_and_bits land dispose_bit <> 0 in

0 commit comments

Comments
 (0)