Skip to content

Commit f10992e

Browse files
committed
feat WS: abstraction for critical section
can be replaced with a proper cooperative lock
1 parent 0f917dd commit f10992e

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

src/ws/tiny_httpd_ws.ml

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
open Common_ws_
22

3+
module With_lock = struct
4+
type t = { with_lock: 'a. (unit -> 'a) -> 'a }
5+
type builder = unit -> t
6+
7+
let default_builder : builder =
8+
fun () ->
9+
let mutex = Mutex.create () in
10+
{
11+
with_lock =
12+
(fun f ->
13+
Mutex.lock mutex;
14+
try
15+
let x = f () in
16+
Mutex.unlock mutex;
17+
x
18+
with e ->
19+
Mutex.unlock mutex;
20+
raise e);
21+
}
22+
23+
let builder : builder ref = ref default_builder
24+
end
25+
326
type handler = unit Request.t -> IO.Input.t -> IO.Output.t -> unit
427

528
module Frame_type = struct
@@ -52,7 +75,7 @@ module Writer = struct
5275
mutable offset: int; (** number of bytes already in [buf] *)
5376
oc: IO.Output.t;
5477
mutable closed: bool;
55-
mutex: Mutex.t;
78+
mutex: With_lock.t;
5679
}
5780

5881
let create ?(buf_size = 16 * 1024) ~oc () : t =
@@ -63,19 +86,9 @@ module Writer = struct
6386
offset = 0;
6487
oc;
6588
closed = false;
66-
mutex = Mutex.create ();
89+
mutex = !With_lock.builder ();
6790
}
6891

69-
let[@inline] with_mutex_ (self : t) f =
70-
Mutex.lock self.mutex;
71-
try
72-
let x = f () in
73-
Mutex.unlock self.mutex;
74-
x
75-
with e ->
76-
Mutex.unlock self.mutex;
77-
raise e
78-
7992
let[@inline] close self = self.closed <- true
8093
let int_of_bool : bool -> int = Obj.magic
8194

@@ -142,7 +155,7 @@ module Writer = struct
142155
if self.offset = Bytes.length self.buf then really_output_buf_ self
143156

144157
let send_pong (self : t) : unit =
145-
let@ () = with_mutex_ self in
158+
let@ () = self.mutex.with_lock in
146159
self.header.fin <- true;
147160
self.header.ty <- Frame_type.pong;
148161
self.header.payload_len <- 0;
@@ -151,7 +164,7 @@ module Writer = struct
151164
write_header_ self
152165

153166
let output_char (self : t) c : unit =
154-
let@ () = with_mutex_ self in
167+
let@ () = self.mutex.with_lock in
155168
let cap = Bytes.length self.buf - self.offset in
156169
(* make room for [c] *)
157170
if cap = 0 then really_output_buf_ self;
@@ -161,7 +174,7 @@ module Writer = struct
161174
if cap = 1 then really_output_buf_ self
162175

163176
let output (self : t) buf i len : unit =
164-
let@ () = with_mutex_ self in
177+
let@ () = self.mutex.with_lock in
165178
let i = ref i in
166179
let len = ref len in
167180
while !len > 0 do
@@ -179,16 +192,16 @@ module Writer = struct
179192
flush_if_full self
180193

181194
let flush self : unit =
182-
let@ () = with_mutex_ self in
195+
let@ () = self.mutex.with_lock in
183196
flush_ self
184197
end
185198

186199
module Reader = struct
187200
type state =
188201
| Begin (** At the beginning of a frame *)
189202
| Reading_frame of { mutable remaining_bytes: int; mutable num_read: int }
190-
(** Currently reading the payload of a frame with [remaining_bytes]
191-
left to read from the underlying [ic] *)
203+
(** Currently reading the payload of a frame with [remaining_bytes] left
204+
to read from the underlying [ic] *)
192205
| Close
193206

194207
type t = {
@@ -266,7 +279,7 @@ module Reader = struct
266279
external apply_masking_ :
267280
key:bytes -> key_offset:int -> buf:bytes -> int -> int -> unit
268281
= "tiny_httpd_ws_apply_masking"
269-
[@@noalloc]
282+
[@@noalloc]
270283
(** Apply masking to the parsed data *)
271284

272285
let[@inline] apply_masking ~mask_key ~mask_offset (buf : bytes) off len : unit
@@ -414,7 +427,8 @@ let upgrade ic oc : _ * _ =
414427
in
415428
ws_ic, ws_oc
416429

417-
(** Turn a regular connection handler (provided by the user) into a websocket upgrade handler *)
430+
(** Turn a regular connection handler (provided by the user) into a websocket
431+
upgrade handler *)
418432
module Make_upgrade_handler (X : sig
419433
val accept_ws_protocol : string -> bool
420434
val handler : handler

src/ws/tiny_httpd_ws.mli

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
(** Websockets for Tiny_httpd.
22
3-
This sub-library ([tiny_httpd.ws]) exports a small implementation
4-
for a websocket server. It has no additional dependencies.
5-
*)
3+
This sub-library ([tiny_httpd.ws]) exports a small implementation for a
4+
websocket server. It has no additional dependencies. *)
65

76
type handler = unit Request.t -> IO.Input.t -> IO.Output.t -> unit
87
(** Websocket handler *)
@@ -11,8 +10,8 @@ val upgrade : IO.Input.t -> IO.Output.t -> IO.Input.t * IO.Output.t
1110
(** Upgrade a byte stream to the websocket framing protocol. *)
1211

1312
exception Close_connection
14-
(** Exception that can be raised from IOs inside the handler,
15-
when the connection is closed from underneath. *)
13+
(** Exception that can be raised from IOs inside the handler, when the
14+
connection is closed from underneath. *)
1615

1716
val add_route_handler :
1817
?accept:(unit Request.t -> (unit, int * string) result) ->
@@ -23,8 +22,9 @@ val add_route_handler :
2322
handler ->
2423
unit
2524
(** Add a route handler for a websocket endpoint.
26-
@param accept_ws_protocol decides whether this endpoint accepts the websocket protocol
27-
sent by the client. Default accepts everything. *)
25+
@param accept_ws_protocol
26+
decides whether this endpoint accepts the websocket protocol sent by the
27+
client. Default accepts everything. *)
2828

2929
(**/**)
3030

@@ -33,4 +33,15 @@ module Private_ : sig
3333
mask_key:bytes -> mask_offset:int -> bytes -> int -> int -> unit
3434
end
3535

36+
(** @since NEXT_RELEASE *)
37+
module With_lock : sig
38+
type t = { with_lock: 'a. (unit -> 'a) -> 'a }
39+
type builder = unit -> t
40+
41+
val default_builder : builder
42+
(** Lock using [Mutex]. *)
43+
44+
val builder : builder ref
45+
end
46+
3647
(**/**)

0 commit comments

Comments
 (0)