Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib_eio_posix/.claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(timeout 3 sh:*)",
"Bash(timeout 5 sh:*)",
"Bash(dune build:*)"
]
}
}
66 changes: 66 additions & 0 deletions lib_eio_posix/posix_eventfd.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
(*
* Copyright (C) 2025 Aaron Eline
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)
module Rcfd = Eio_unix.Private.Rcfd

module Writer = struct
type t = Rcfd.t
let wake_buffer = Bytes.of_string "!"
let wakeup t =
Rcfd.use t
~if_closed:ignore
(fun fd ->
try
ignore (Unix.single_write fd wake_buffer 0 1)
with
(* If the pipe is full then a wake up is pending anyway. *)
| Unix.Unix_error ((Unix.EACCES | EWOULDBLOCK), _, _) -> ()
(* We're shutting down; the event has already been processed. *)
| Unix.Unix_error (Unix.EPIPE, _, _) -> ()
)
end

module Owner = struct
type t = {
read : Unix.file_descr;
write : Rcfd.t;
}

let is_reader fd t = fd = t.read

let reader_fd t = t.read

let create_writer t = t.write

let clear t =
let buf = Bytes.create 8 in
let got = Unix.read t.read buf 0 (Bytes.length buf) in
assert (got > 0)

let create () =
let read, write = Unix.pipe ~cloexec:true () in
Unix.set_nonblock read;
Unix.set_nonblock write;
let write = Rcfd.make write in
{
read; write
}

let cleanup t =
Unix.close t.read;
let was_open = Rcfd.close t.write in
assert was_open

end
61 changes: 61 additions & 0 deletions lib_eio_posix/posix_eventfd.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
(*
* Copyright (C) 2025 Aaron Eline
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)

(**
This module implements a thread safe re-usable abstraction for POSIX compliant eventfds.
Eventfds are backed by a pipe.
*)

(**
The [Writer] module is the writing end of the eventfd.
Having a [Writer.t] allows you to signal to the holder of the owner to wake up
It is safe to share between threads
*)
module Writer :
sig type t

(** Signal to the owning thread to wake up *)
val wakeup : t -> unit
end

(**
The [Owner] module is the reading end of the event fd.
It is not safe to share between threads.
Anyone who holds a [Writer.t] can send wake up signals to an [Owner.t]
*)
module Owner :
sig
type t

(** Check if a given fd is the read end of the event fd *)
val is_reader : Unix.file_descr -> t -> bool

(** @return the reading fd of the eventfd. This is not safe to share between threads. *)
val reader_fd : t -> Unix.file_descr

(** Get a view into the write end of the event fd.
@return the writing end. Safe to share between threads. *)
val create_writer : t -> Writer.t

(** Clear pending events from the event fd *)
val clear : t -> unit

(** @return a new eventfd owner *)
val create : unit -> t

(** Close the file descriptors associated with the eventfd *)
val cleanup : t -> unit
end
Loading
Loading