Skip to content

Commit

Permalink
Invert writers and readers to no_writers and no_readers
Browse files Browse the repository at this point in the history
  • Loading branch information
polytypic committed Jan 19, 2025
1 parent de83647 commit 5821151
Showing 1 changed file with 21 additions and 20 deletions.
41 changes: 21 additions & 20 deletions lib/picos_std.sync/rwlock.slim.ml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ type t = int Awaitable.t

let frozen = 1 lsl 0
let poisoned = 1 lsl 1
let readers = 1 lsl 2
let writers = 1 lsl 3
let awaiters = readers lor writers
let no_writers = 1 lsl 2
let no_readers = 1 lsl 3
let no_awaiters = no_readers lor no_writers
let locked = 1 lsl 4
let exclusive = 1 lsl (Sys.int_size - 2)

Expand All @@ -20,13 +20,13 @@ exception Frozen
let rec lock_awaiting t =
let before = Awaitable.get t in
if before < locked then begin
let after = before lor locked lor exclusive lor writers in
let after = before land lnot no_writers lor locked lor exclusive in
if not (Awaitable.compare_and_set t before after) then lock_awaiting t
end
else if before land (poisoned lor frozen) <> 0 then
raise (if before land poisoned <> 0 then Poisoned else Frozen)
else
let after = before lor writers in
let after = before land lnot no_writers in
if before = after || Awaitable.compare_and_set t before after then
Awaitable.await t after;
lock_awaiting t
Expand All @@ -43,20 +43,20 @@ let lock t =
let rec lock_ro_awaiting t =
let before = Awaitable.get t in
if before < exclusive then begin
let after = (before + locked) lor readers in
let after = (before + locked) land lnot no_readers in
if not (Awaitable.compare_and_set t before after) then lock_ro_awaiting t
end
else if before land poisoned <> 0 then raise Poisoned
else
let after = before lor readers in
let after = before land lnot no_readers in
if before = after || Awaitable.compare_and_set t before after then
Awaitable.await t after;
lock_ro_awaiting t

let rec lock_ro_contended t =
let before = Awaitable.get t in
if locked * 2 <= before then
let after = (before - locked) lor readers in
let after = (before - locked) land lnot no_readers in
if Awaitable.compare_and_set t before after then lock_ro_awaiting t
else lock_ro_contended t

Expand All @@ -66,34 +66,33 @@ let lock_ro t =

let rec signal_awaiters t =
let before = Awaitable.get t in
if before < locked && before land awaiters <> 0 then
if Awaitable.compare_and_set t before (before land lnot awaiters) then
if before land readers <> 0 then Awaitable.broadcast t
else Awaitable.signal t
if before < no_awaiters then
if Awaitable.compare_and_set t before (before lor no_awaiters) then
if no_readers <= before then Awaitable.signal t else Awaitable.broadcast t
else signal_awaiters t

let unlock t =
let before = Awaitable.get t in
if exclusive <= before then begin
let prior =
Awaitable.fetch_and_add t
(-(locked lor exclusive) - (before land awaiters))
((-(locked lor exclusive) lor no_awaiters) - (before land no_awaiters))
in
if prior land awaiters <> 0 then
if prior land readers <> 0 then Awaitable.broadcast t
else Awaitable.signal t
if prior < locked lor exclusive lor no_awaiters then
if locked lor exclusive lor no_readers <= prior then Awaitable.signal t
else Awaitable.broadcast t
end
else
let prior = Awaitable.fetch_and_add t (-locked) in
if prior < locked * 2 && locked + readers < prior then signal_awaiters t
if prior < locked lor no_awaiters then signal_awaiters t

let poison t =
let before = Awaitable.get t in
if before land exclusive = 0 then invalid_arg "not write locked";
(* Unfortunately we cannot check ownership at this point. *)
if before land poisoned = 0 then
let prior = Awaitable.fetch_and_add t poisoned in
if prior land awaiters <> 0 then Awaitable.broadcast t
if prior land no_awaiters <> no_awaiters then Awaitable.broadcast t

let freeze t =
lock_ro t;
Expand All @@ -108,7 +107,7 @@ let freeze t =
before := Awaitable.get t
done;
(* We must wake up any writers waiting to obtain the lock. *)
if !before land awaiters <> 0 then Awaitable.broadcast t;
if !before land no_awaiters <> no_awaiters then Awaitable.broadcast t;
unlock t

let protect t thunk =
Expand All @@ -133,7 +132,9 @@ let protect_ro t thunk =
unlock t;
Printexc.raise_with_backtrace exn bt

let[@inline] create ?padded () = Awaitable.make ?padded 0
let[@inline] create ?padded () =
Awaitable.make ?padded (no_readers lor no_writers)

let[@inline] is_locked t = exclusive <= Awaitable.get t
let[@inline] is_poisoned t = Awaitable.get t land poisoned <> 0
let[@inline] is_frozen t = Awaitable.get t land frozen <> 0
Expand Down

0 comments on commit 5821151

Please sign in to comment.