mirror of
https://github.com/ocaml-multicore/eio.git
synced 2025-07-18 00:02:52 -04:00
Compare commits
No commits in common. "ad7149dc297b856c9bedd692e5809538fd27a4e2" and "387fb6d2b9cb6bf03775c432b880f6ab6604e8ce" have entirely different histories.
ad7149dc29
...
387fb6d2b9
63
CHANGES.md
63
CHANGES.md
@ -1,66 +1,3 @@
|
|||||||
## v0.12
|
|
||||||
|
|
||||||
New features / API changes:
|
|
||||||
|
|
||||||
- Replace objects with variants (@talex5 @patricoferris #553 #605 #608, reviewed by @avsm).
|
|
||||||
Some potential users found object types confusing, so we now use an alternative scheme for OS resources.
|
|
||||||
For users of the resources, the only thing that changes is the types:
|
|
||||||
|
|
||||||
- Instead of taking an argument of type `#foo`, you should now take `_ foo`.
|
|
||||||
- Instead of returning a value of type `foo`, you should now return `foo_ty Eio.Resource.t`.
|
|
||||||
|
|
||||||
To provide your own implementation of an interface, you now provide a module rather than an object.
|
|
||||||
For example, to provide your own source flow, use `Eio.Flow.Pi.source (module My_source)`.
|
|
||||||
|
|
||||||
If you want to define your own interfaces, see the `Eio.Resource` module documentation.
|
|
||||||
|
|
||||||
- Add `Eio.Pool` (@talex5 @darrenldl #602, reviewed by @patricoferris).
|
|
||||||
A lock-free pool of resources. This is similar to `Lwt_pool`.
|
|
||||||
|
|
||||||
- Add `Eio.Lazy` (@talex5 #609, reviewed by @SGrondin).
|
|
||||||
If one fiber tries to force a lazy value while another is already doing it,
|
|
||||||
this will wait for the first one to finish rather than raising an exception (as `Stdlib.Lazy` does).
|
|
||||||
|
|
||||||
- Add `Eio.Path.native` (@talex5 #603, reviewed by @patricoferris).
|
|
||||||
This is useful when interacting with non-Eio libraries, for spawning sub-processes, and for displaying paths to users.
|
|
||||||
|
|
||||||
- Add `Flow.single_write` (@talex5 #598).
|
|
||||||
|
|
||||||
- Add `Eio.Flow.Pi.simple_copy` (@talex5 #611).
|
|
||||||
Provides an easy way to implement the `copy` operation when making your own sink.
|
|
||||||
|
|
||||||
- Eio_unix: add FD passing (@talex5 #522).
|
|
||||||
Allows opening a file and passing the handle over a Unix-domain socket.
|
|
||||||
|
|
||||||
- Add `Process.run ?is_success` to control definition of success (@SGrondin #586, reviewed by @talex5).
|
|
||||||
|
|
||||||
- Add `Eio_mock.Domain_manager` (@talex5 #610).
|
|
||||||
This mock domain manager runs everything in a single domain, allowing tests to remain deterministic.
|
|
||||||
|
|
||||||
- Add `Eio.Debug.with_trace_prefix` (@talex5 #610).
|
|
||||||
Allows prefixing all `traceln` output. The mock domain manager uses this to indicate which fake domain is running.
|
|
||||||
|
|
||||||
Bug fixes:
|
|
||||||
|
|
||||||
- Fork actions must not allocate (@talex5 #593).
|
|
||||||
When using multiple domains, child processes could get stuck if they forked while another domain held the malloc lock.
|
|
||||||
|
|
||||||
- eio_posix: ignore some errors writing to the wake-up pipe (@talex5 #600).
|
|
||||||
If the pipe is full or closed, the wake-up should simply be ignored.
|
|
||||||
|
|
||||||
Build/test fixes:
|
|
||||||
|
|
||||||
- Fix some MDX problems on Windows (@polytypic #597).
|
|
||||||
|
|
||||||
- The README depends on kcas (@talex5 #606).
|
|
||||||
|
|
||||||
- Clarify configuration for lib_eio_linux and enable tests on other arches (@dra27 #592).
|
|
||||||
|
|
||||||
- eio_linux tests: skip fixed buffer test if not available (@talex5 #604).
|
|
||||||
|
|
||||||
- eio_windows: update available line to win32 (@talex5 #588 #591).
|
|
||||||
|
|
||||||
|
|
||||||
## v0.11
|
## v0.11
|
||||||
|
|
||||||
New features / API changes:
|
New features / API changes:
|
||||||
|
@ -23,8 +23,8 @@ module Pi = struct
|
|||||||
|
|
||||||
module type SINK = sig
|
module type SINK = sig
|
||||||
type t
|
type t
|
||||||
val single_write : t -> Cstruct.t list -> int
|
|
||||||
val copy : t -> src:_ source -> unit
|
val copy : t -> src:_ source -> unit
|
||||||
|
val single_write : t -> Cstruct.t list -> int
|
||||||
end
|
end
|
||||||
|
|
||||||
module type SHUTDOWN = sig
|
module type SHUTDOWN = sig
|
||||||
@ -37,6 +37,7 @@ module Pi = struct
|
|||||||
| Sink : ('t, (module SINK with type t = 't), [> sink_ty]) Resource.pi
|
| Sink : ('t, (module SINK with type t = 't), [> sink_ty]) Resource.pi
|
||||||
| Shutdown : ('t, (module SHUTDOWN with type t = 't), [> shutdown_ty]) Resource.pi
|
| Shutdown : ('t, (module SHUTDOWN with type t = 't), [> shutdown_ty]) Resource.pi
|
||||||
|
|
||||||
|
|
||||||
let source (type t) (module X : SOURCE with type t = t) =
|
let source (type t) (module X : SOURCE with type t = t) =
|
||||||
Resource.handler [H (Source, (module X))]
|
Resource.handler [H (Source, (module X))]
|
||||||
|
|
||||||
@ -58,22 +59,6 @@ module Pi = struct
|
|||||||
H (Source, (module X));
|
H (Source, (module X));
|
||||||
H (Sink, (module X));
|
H (Sink, (module X));
|
||||||
]
|
]
|
||||||
|
|
||||||
let simple_copy ~single_write t ~src:(Resource.T (src, src_ops)) =
|
|
||||||
let rec write_all buf =
|
|
||||||
if not (Cstruct.is_empty buf) then (
|
|
||||||
let sent = single_write t [buf] in
|
|
||||||
write_all (Cstruct.shift buf sent)
|
|
||||||
)
|
|
||||||
in
|
|
||||||
let module Src = (val (Resource.get src_ops Source)) in
|
|
||||||
try
|
|
||||||
let buf = Cstruct.create 4096 in
|
|
||||||
while true do
|
|
||||||
let got = Src.single_read src buf in
|
|
||||||
write_all (Cstruct.sub buf 0 got)
|
|
||||||
done
|
|
||||||
with End_of_file -> ()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
open Pi
|
open Pi
|
||||||
@ -168,12 +153,20 @@ let copy_string s = copy (string_source s)
|
|||||||
module Buffer_sink = struct
|
module Buffer_sink = struct
|
||||||
type t = Buffer.t
|
type t = Buffer.t
|
||||||
|
|
||||||
|
let copy t ~src:(Resource.T (src, ops)) =
|
||||||
|
let module Src = (val (Resource.get ops Source)) in
|
||||||
|
let buf = Cstruct.create 4096 in
|
||||||
|
try
|
||||||
|
while true do
|
||||||
|
let got = Src.single_read src buf in
|
||||||
|
Buffer.add_string t (Cstruct.to_string ~len:got buf)
|
||||||
|
done
|
||||||
|
with End_of_file -> ()
|
||||||
|
|
||||||
let single_write t bufs =
|
let single_write t bufs =
|
||||||
let old_length = Buffer.length t in
|
let old_length = Buffer.length t in
|
||||||
List.iter (fun buf -> Buffer.add_bytes t (Cstruct.to_bytes buf)) bufs;
|
List.iter (fun buf -> Buffer.add_bytes t (Cstruct.to_bytes buf)) bufs;
|
||||||
Buffer.length t - old_length
|
Buffer.length t - old_length
|
||||||
|
|
||||||
let copy t ~src = Pi.simple_copy ~single_write t ~src
|
|
||||||
end
|
end
|
||||||
|
|
||||||
let buffer_sink =
|
let buffer_sink =
|
||||||
|
@ -121,13 +121,8 @@ module Pi : sig
|
|||||||
|
|
||||||
module type SINK = sig
|
module type SINK = sig
|
||||||
type t
|
type t
|
||||||
|
|
||||||
val single_write : t -> Cstruct.t list -> int
|
|
||||||
|
|
||||||
val copy : t -> src:_ source -> unit
|
val copy : t -> src:_ source -> unit
|
||||||
(** [copy t ~src] allows for optimising copy operations.
|
val single_write : t -> Cstruct.t list -> int
|
||||||
|
|
||||||
If you have no optimisations, you can use {!simple_copy} to implement this using {!single_write}. *)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module type SHUTDOWN = sig
|
module type SHUTDOWN = sig
|
||||||
@ -151,8 +146,5 @@ module Pi : sig
|
|||||||
| Source : ('t, (module SOURCE with type t = 't), [> source_ty]) Resource.pi
|
| Source : ('t, (module SOURCE with type t = 't), [> source_ty]) Resource.pi
|
||||||
| Sink : ('t, (module SINK with type t = 't), [> sink_ty]) Resource.pi
|
| Sink : ('t, (module SINK with type t = 't), [> sink_ty]) Resource.pi
|
||||||
| Shutdown : ('t, (module SHUTDOWN with type t = 't), [> shutdown_ty]) Resource.pi
|
| Shutdown : ('t, (module SHUTDOWN with type t = 't), [> shutdown_ty]) Resource.pi
|
||||||
|
|
||||||
val simple_copy : single_write:('t -> Cstruct.t list -> int) -> 't -> src:_ source -> unit
|
|
||||||
(** [simple_copy ~single_write] implements {!SINK}'s [copy] API using [single_write]. *)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -42,7 +42,25 @@ module Impl = struct
|
|||||||
with Unix.Unix_error (code, name, arg) ->
|
with Unix.Unix_error (code, name, arg) ->
|
||||||
raise (Err.wrap code name arg)
|
raise (Err.wrap code name arg)
|
||||||
|
|
||||||
let copy t ~src = Eio.Flow.Pi.simple_copy ~single_write t ~src
|
let write_all t bufs =
|
||||||
|
try
|
||||||
|
let rec loop = function
|
||||||
|
| [] -> ()
|
||||||
|
| bufs ->
|
||||||
|
let wrote = Low_level.writev t (Array.of_list bufs) in
|
||||||
|
loop (Cstruct.shiftv bufs wrote)
|
||||||
|
in
|
||||||
|
loop bufs
|
||||||
|
with Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg)
|
||||||
|
|
||||||
|
let copy dst ~src =
|
||||||
|
let buf = Cstruct.create 4096 in
|
||||||
|
try
|
||||||
|
while true do
|
||||||
|
let got = Eio.Flow.single_read src buf in
|
||||||
|
write_all dst [Cstruct.sub buf 0 got]
|
||||||
|
done
|
||||||
|
with End_of_file -> ()
|
||||||
|
|
||||||
let single_read t buf =
|
let single_read t buf =
|
||||||
match Low_level.readv t [| buf |] with
|
match Low_level.readv t [| buf |] with
|
||||||
|
@ -45,7 +45,14 @@ module Impl = struct
|
|||||||
write_all t bufs;
|
write_all t bufs;
|
||||||
Cstruct.lenv bufs
|
Cstruct.lenv bufs
|
||||||
|
|
||||||
let copy t ~src = Eio.Flow.Pi.simple_copy ~single_write t ~src
|
let copy dst ~src =
|
||||||
|
let buf = Cstruct.create 4096 in
|
||||||
|
try
|
||||||
|
while true do
|
||||||
|
let got = Eio.Flow.single_read src buf in
|
||||||
|
write_all dst [Cstruct.sub buf 0 got]
|
||||||
|
done
|
||||||
|
with End_of_file -> ()
|
||||||
|
|
||||||
let single_read t buf =
|
let single_read t buf =
|
||||||
match Low_level.read_cstruct t buf with
|
match Low_level.read_cstruct t buf with
|
||||||
|
Loading…
x
Reference in New Issue
Block a user