Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

on Windows reading stdin from a pipe command throws"broken pipe" exception #792

Closed
bdodrem opened this issue Jan 9, 2025 · 5 comments
Closed
Labels
bug Something isn't working good first issue Good for newcomers windows

Comments

@bdodrem
Copy link
Contributor

bdodrem commented Jan 9, 2025

On Windows, the following code :

     open Eio.Std
     open Eio.Buf_read  

     let _ = Eio_main.run (fun env ->  Seq.iter (traceln "%s" ) @@ lines @@ of_flow env#stdin ~max_size:1024  )

when run in a terminal (bash console) with the command :
echo 1 | dune exec ./test.exe

Throws the exception :

+1
Fatal error: exception Eio.Io Net Connection_reset Unix_error (Broken pipe, "stub_cstruct_read", "")

(I'm currently using ocaml 5.2.1 and eio 1.2 on MINGW64 )

@talex5 talex5 added bug Something isn't working good first issue Good for newcomers windows labels Jan 10, 2025
@talex5
Copy link
Collaborator

talex5 commented Jan 10, 2025

I did a search on the Internet, and it turns out I reported the same bug in Lwt back in 2013. D'oh!

@bdodrem
Copy link
Contributor Author

bdodrem commented Jan 10, 2025

The issue seemed to be solved when I replaced Unix_cstruct.read with Unix.read_bigarray in the function read_cstruct (lib_eio_windows/low_level.ml).

diff --git a/lib_eio_windows/low_level.ml b/lib_eio_windows/low_level.ml
index 85f25cd..962210d 100755
--- a/lib_eio_windows/low_level.ml
+++ b/lib_eio_windows/low_level.ml
@@ -42,9 +42,9 @@ let read fd buf start len =
   Fd.use_exn "read" fd @@ fun fd ->
   do_nonblocking Read (fun fd -> Unix.read fd buf start len) fd

-let read_cstruct fd buf =
+let read_cstruct fd (buf:Cstruct.t) =
   Fd.use_exn "read_cstruct" fd @@ fun fd ->
-  do_nonblocking Read (fun fd -> Unix_cstruct.read fd buf) fd
+  do_nonblocking Read (fun fd -> Unix.read_bigarray fd buf.buffer buf.off buf.len) fd

 let write fd buf start len =
   Fd.use_exn "write" fd @@ fun fd ->

Hopefully this will solve the bug

@talex5
Copy link
Collaborator

talex5 commented Jan 14, 2025

This fix looks right to me.

@patricoferris how about removing eio_windows_cstruct_stubs.c and using the Unix functions instead?

@bdodrem
Copy link
Contributor Author

bdodrem commented Jan 20, 2025

Hi,

Here below is a patch to:

diff --git a/lib_eio_windows/dune b/lib_eio_windows/dune
index 8791342..0fa2546 100644
--- a/lib_eio_windows/dune
+++ b/lib_eio_windows/dune
@@ -6,7 +6,7 @@
  (foreign_stubs
   (language c)
   (include_dirs ../lib_eio/unix/include)
-  (names eio_windows_stubs eio_windows_cstruct_stubs))
+  (names eio_windows_stubs ))
  (c_library_flags :standard -lbcrypt -lntdll)
  (libraries eio eio.unix eio.utils fmt))

diff --git a/lib_eio_windows/low_level.ml b/lib_eio_windows/low_level.ml
index 85f25cd..54ba0e6 100755
--- a/lib_eio_windows/low_level.ml
+++ b/lib_eio_windows/low_level.ml
@@ -39,17 +39,25 @@ let rec do_nonblocking ty fn fd =
     do_nonblocking ty fn fd

 let read fd buf start len =
+  await_readable fd;
   Fd.use_exn "read" fd @@ fun fd ->
   do_nonblocking Read (fun fd -> Unix.read fd buf start len) fd

-let read_cstruct fd buf =
+let read_cstruct fd (buf:Cstruct.t) =
+  await_readable fd;
   Fd.use_exn "read_cstruct" fd @@ fun fd ->
-  do_nonblocking Read (fun fd -> Unix_cstruct.read fd buf) fd
+  do_nonblocking Read (fun fd -> Unix.read_bigarray fd buf.buffer buf.off buf.len) fd

 let write fd buf start len =
+  await_writable fd;
   Fd.use_exn "write" fd @@ fun fd ->
   do_nonblocking Write (fun fd -> Unix.write fd buf start len) fd

+let write_cstruct fd (buf:Cstruct.t) =
+  await_writable fd;
+  Fd.use_exn "write_cstruct" fd @@ fun fd ->
+  do_nonblocking Write (fun fd -> Unix.write_bigarray fd buf.buffer buf.off buf.len) fd
+
 let sleep_until time =
   Sched.enter @@ fun t k ->
   Sched.await_timeout t k time
@@ -148,8 +156,11 @@ let readv fd bufs =
   do_nonblocking Read (fun fd -> eio_readv fd bufs) fd

 let writev fd bufs =
-  Fd.use_exn "writev" fd @@ fun fd ->
-  do_nonblocking Write (fun fd -> Unix_cstruct.writev fd bufs) fd
+  let rec loop buf = if Cstruct.length buf > 0 then begin
+    let n = write_cstruct fd buf in
+    loop @@ Cstruct.shift buf n
+  end in
+  List.iter loop bufs

 let preadv ~file_offset fd bufs =
   Fd.use_exn "preadv" fd @@ fun fd ->
diff --git a/lib_eio_windows/low_level.mli b/lib_eio_windows/low_level.mli
index e2ec400..782a175 100755
--- a/lib_eio_windows/low_level.mli
+++ b/lib_eio_windows/low_level.mli
@@ -22,6 +22,7 @@ val sleep_until : Mtime.t -> unit
 val read : fd -> bytes -> int -> int -> int
 val read_cstruct : fd -> Cstruct.t -> int
 val write : fd -> bytes -> int -> int -> int
+val write_cstruct : fd -> Cstruct.t -> int

 val socket : sw:Switch.t -> Unix.socket_domain -> Unix.socket_type -> int -> fd
 val connect : fd -> Unix.sockaddr -> unit

Do I need to create a pull request ?

@talex5
Copy link
Collaborator

talex5 commented Jan 21, 2025

Do I need to create a pull request ?

That would be easier, yes. Though I can do it if that's a problem for you.

bdodrem added a commit to bdodrem/eio that referenced this issue Jan 25, 2025
      Adding await_readable before reading fd

- fix broken pipe exception : issue ocaml-multicore#792.
      Use Unix.read_bigarray instead of Unix_cstruct.read

- replace eio_windows_cstruct_stubs.c by Unix functions.
      Unix.read_bigarray and Unix.write_bigarray implemented since Ocaml 5.2
bdodrem added a commit to bdodrem/eio that referenced this issue Jan 25, 2025
      Adding await_readable before reading fd

* fix broken pipe exception : issue ocaml-multicore#792.
      Use Unix.read_bigarray instead of Unix_cstruct.read

* replace eio_windows_cstruct_stubs.c by Unix functions.
     Since Ocaml 5.2, Unix.read_bigarray and Unix.write_bigarray can be used.
talex5 pushed a commit to bdodrem/eio that referenced this issue Jan 27, 2025
* fix blocking issue on Windows : issue ocaml-multicore#793.
      Adding await_readable before reading fd

* fix broken pipe exception : issue ocaml-multicore#792.
      Use Unix.read_bigarray instead of Unix_cstruct.read

* replace eio_windows_cstruct_stubs.c by Unix functions.
     Since OCaml 5.2, Unix.read_bigarray and Unix.write_bigarray can be used.
talex5 pushed a commit to bdodrem/eio that referenced this issue Jan 27, 2025
* fix blocking issue on Windows : issue ocaml-multicore#793.
      Adding await_readable before reading fd

* fix broken pipe exception : issue ocaml-multicore#792.
      Use Unix.read_bigarray instead of Unix_cstruct.read

* replace eio_windows_cstruct_stubs.c by Unix functions.
     Since OCaml 5.2, Unix.read_bigarray and Unix.write_bigarray can be used.
talex5 added a commit that referenced this issue Jan 27, 2025
…d_792

On Windows, fix stdin broken-pipe and blocking domain.  Issues #793 and #792.
@talex5 talex5 closed this as completed Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good first issue Good for newcomers windows
Projects
None yet
Development

No branches or pull requests

2 participants