mirror of
https://github.com/c-cube/tiny_httpd.git
synced 2025-12-06 03:05:29 -05:00
feat WS: abstraction for critical section
can be replaced with a proper cooperative lock
This commit is contained in:
parent
0f917ddf72
commit
f10992ec32
2 changed files with 52 additions and 27 deletions
|
|
@ -1,5 +1,28 @@
|
||||||
open Common_ws_
|
open Common_ws_
|
||||||
|
|
||||||
|
module With_lock = struct
|
||||||
|
type t = { with_lock: 'a. (unit -> 'a) -> 'a }
|
||||||
|
type builder = unit -> t
|
||||||
|
|
||||||
|
let default_builder : builder =
|
||||||
|
fun () ->
|
||||||
|
let mutex = Mutex.create () in
|
||||||
|
{
|
||||||
|
with_lock =
|
||||||
|
(fun f ->
|
||||||
|
Mutex.lock mutex;
|
||||||
|
try
|
||||||
|
let x = f () in
|
||||||
|
Mutex.unlock mutex;
|
||||||
|
x
|
||||||
|
with e ->
|
||||||
|
Mutex.unlock mutex;
|
||||||
|
raise e);
|
||||||
|
}
|
||||||
|
|
||||||
|
let builder : builder ref = ref default_builder
|
||||||
|
end
|
||||||
|
|
||||||
type handler = unit Request.t -> IO.Input.t -> IO.Output.t -> unit
|
type handler = unit Request.t -> IO.Input.t -> IO.Output.t -> unit
|
||||||
|
|
||||||
module Frame_type = struct
|
module Frame_type = struct
|
||||||
|
|
@ -52,7 +75,7 @@ module Writer = struct
|
||||||
mutable offset: int; (** number of bytes already in [buf] *)
|
mutable offset: int; (** number of bytes already in [buf] *)
|
||||||
oc: IO.Output.t;
|
oc: IO.Output.t;
|
||||||
mutable closed: bool;
|
mutable closed: bool;
|
||||||
mutex: Mutex.t;
|
mutex: With_lock.t;
|
||||||
}
|
}
|
||||||
|
|
||||||
let create ?(buf_size = 16 * 1024) ~oc () : t =
|
let create ?(buf_size = 16 * 1024) ~oc () : t =
|
||||||
|
|
@ -63,19 +86,9 @@ module Writer = struct
|
||||||
offset = 0;
|
offset = 0;
|
||||||
oc;
|
oc;
|
||||||
closed = false;
|
closed = false;
|
||||||
mutex = Mutex.create ();
|
mutex = !With_lock.builder ();
|
||||||
}
|
}
|
||||||
|
|
||||||
let[@inline] with_mutex_ (self : t) f =
|
|
||||||
Mutex.lock self.mutex;
|
|
||||||
try
|
|
||||||
let x = f () in
|
|
||||||
Mutex.unlock self.mutex;
|
|
||||||
x
|
|
||||||
with e ->
|
|
||||||
Mutex.unlock self.mutex;
|
|
||||||
raise e
|
|
||||||
|
|
||||||
let[@inline] close self = self.closed <- true
|
let[@inline] close self = self.closed <- true
|
||||||
let int_of_bool : bool -> int = Obj.magic
|
let int_of_bool : bool -> int = Obj.magic
|
||||||
|
|
||||||
|
|
@ -142,7 +155,7 @@ module Writer = struct
|
||||||
if self.offset = Bytes.length self.buf then really_output_buf_ self
|
if self.offset = Bytes.length self.buf then really_output_buf_ self
|
||||||
|
|
||||||
let send_pong (self : t) : unit =
|
let send_pong (self : t) : unit =
|
||||||
let@ () = with_mutex_ self in
|
let@ () = self.mutex.with_lock in
|
||||||
self.header.fin <- true;
|
self.header.fin <- true;
|
||||||
self.header.ty <- Frame_type.pong;
|
self.header.ty <- Frame_type.pong;
|
||||||
self.header.payload_len <- 0;
|
self.header.payload_len <- 0;
|
||||||
|
|
@ -151,7 +164,7 @@ module Writer = struct
|
||||||
write_header_ self
|
write_header_ self
|
||||||
|
|
||||||
let output_char (self : t) c : unit =
|
let output_char (self : t) c : unit =
|
||||||
let@ () = with_mutex_ self in
|
let@ () = self.mutex.with_lock in
|
||||||
let cap = Bytes.length self.buf - self.offset in
|
let cap = Bytes.length self.buf - self.offset in
|
||||||
(* make room for [c] *)
|
(* make room for [c] *)
|
||||||
if cap = 0 then really_output_buf_ self;
|
if cap = 0 then really_output_buf_ self;
|
||||||
|
|
@ -161,7 +174,7 @@ module Writer = struct
|
||||||
if cap = 1 then really_output_buf_ self
|
if cap = 1 then really_output_buf_ self
|
||||||
|
|
||||||
let output (self : t) buf i len : unit =
|
let output (self : t) buf i len : unit =
|
||||||
let@ () = with_mutex_ self in
|
let@ () = self.mutex.with_lock in
|
||||||
let i = ref i in
|
let i = ref i in
|
||||||
let len = ref len in
|
let len = ref len in
|
||||||
while !len > 0 do
|
while !len > 0 do
|
||||||
|
|
@ -179,7 +192,7 @@ module Writer = struct
|
||||||
flush_if_full self
|
flush_if_full self
|
||||||
|
|
||||||
let flush self : unit =
|
let flush self : unit =
|
||||||
let@ () = with_mutex_ self in
|
let@ () = self.mutex.with_lock in
|
||||||
flush_ self
|
flush_ self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -187,8 +200,8 @@ module Reader = struct
|
||||||
type state =
|
type state =
|
||||||
| Begin (** At the beginning of a frame *)
|
| Begin (** At the beginning of a frame *)
|
||||||
| Reading_frame of { mutable remaining_bytes: int; mutable num_read: int }
|
| Reading_frame of { mutable remaining_bytes: int; mutable num_read: int }
|
||||||
(** Currently reading the payload of a frame with [remaining_bytes]
|
(** Currently reading the payload of a frame with [remaining_bytes] left
|
||||||
left to read from the underlying [ic] *)
|
to read from the underlying [ic] *)
|
||||||
| Close
|
| Close
|
||||||
|
|
||||||
type t = {
|
type t = {
|
||||||
|
|
@ -266,7 +279,7 @@ module Reader = struct
|
||||||
external apply_masking_ :
|
external apply_masking_ :
|
||||||
key:bytes -> key_offset:int -> buf:bytes -> int -> int -> unit
|
key:bytes -> key_offset:int -> buf:bytes -> int -> int -> unit
|
||||||
= "tiny_httpd_ws_apply_masking"
|
= "tiny_httpd_ws_apply_masking"
|
||||||
[@@noalloc]
|
[@@noalloc]
|
||||||
(** Apply masking to the parsed data *)
|
(** Apply masking to the parsed data *)
|
||||||
|
|
||||||
let[@inline] apply_masking ~mask_key ~mask_offset (buf : bytes) off len : unit
|
let[@inline] apply_masking ~mask_key ~mask_offset (buf : bytes) off len : unit
|
||||||
|
|
@ -414,7 +427,8 @@ let upgrade ic oc : _ * _ =
|
||||||
in
|
in
|
||||||
ws_ic, ws_oc
|
ws_ic, ws_oc
|
||||||
|
|
||||||
(** Turn a regular connection handler (provided by the user) into a websocket upgrade handler *)
|
(** Turn a regular connection handler (provided by the user) into a websocket
|
||||||
|
upgrade handler *)
|
||||||
module Make_upgrade_handler (X : sig
|
module Make_upgrade_handler (X : sig
|
||||||
val accept_ws_protocol : string -> bool
|
val accept_ws_protocol : string -> bool
|
||||||
val handler : handler
|
val handler : handler
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
(** Websockets for Tiny_httpd.
|
(** Websockets for Tiny_httpd.
|
||||||
|
|
||||||
This sub-library ([tiny_httpd.ws]) exports a small implementation
|
This sub-library ([tiny_httpd.ws]) exports a small implementation for a
|
||||||
for a websocket server. It has no additional dependencies.
|
websocket server. It has no additional dependencies. *)
|
||||||
*)
|
|
||||||
|
|
||||||
type handler = unit Request.t -> IO.Input.t -> IO.Output.t -> unit
|
type handler = unit Request.t -> IO.Input.t -> IO.Output.t -> unit
|
||||||
(** Websocket handler *)
|
(** Websocket handler *)
|
||||||
|
|
@ -11,8 +10,8 @@ val upgrade : IO.Input.t -> IO.Output.t -> IO.Input.t * IO.Output.t
|
||||||
(** Upgrade a byte stream to the websocket framing protocol. *)
|
(** Upgrade a byte stream to the websocket framing protocol. *)
|
||||||
|
|
||||||
exception Close_connection
|
exception Close_connection
|
||||||
(** Exception that can be raised from IOs inside the handler,
|
(** Exception that can be raised from IOs inside the handler, when the
|
||||||
when the connection is closed from underneath. *)
|
connection is closed from underneath. *)
|
||||||
|
|
||||||
val add_route_handler :
|
val add_route_handler :
|
||||||
?accept:(unit Request.t -> (unit, int * string) result) ->
|
?accept:(unit Request.t -> (unit, int * string) result) ->
|
||||||
|
|
@ -23,8 +22,9 @@ val add_route_handler :
|
||||||
handler ->
|
handler ->
|
||||||
unit
|
unit
|
||||||
(** Add a route handler for a websocket endpoint.
|
(** Add a route handler for a websocket endpoint.
|
||||||
@param accept_ws_protocol decides whether this endpoint accepts the websocket protocol
|
@param accept_ws_protocol
|
||||||
sent by the client. Default accepts everything. *)
|
decides whether this endpoint accepts the websocket protocol sent by the
|
||||||
|
client. Default accepts everything. *)
|
||||||
|
|
||||||
(**/**)
|
(**/**)
|
||||||
|
|
||||||
|
|
@ -33,4 +33,15 @@ module Private_ : sig
|
||||||
mask_key:bytes -> mask_offset:int -> bytes -> int -> int -> unit
|
mask_key:bytes -> mask_offset:int -> bytes -> int -> int -> unit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
(** @since NEXT_RELEASE *)
|
||||||
|
module With_lock : sig
|
||||||
|
type t = { with_lock: 'a. (unit -> 'a) -> 'a }
|
||||||
|
type builder = unit -> t
|
||||||
|
|
||||||
|
val default_builder : builder
|
||||||
|
(** Lock using [Mutex]. *)
|
||||||
|
|
||||||
|
val builder : builder ref
|
||||||
|
end
|
||||||
|
|
||||||
(**/**)
|
(**/**)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue