Skip to content

In dune_rpc_lwt closing the output channel should also close the input channel #7624

@gridbugs

Description

@gridbugs

Expected Behavior

In dune_rpc_lwt an input and output channel is created based on unix sockets backed by a single file. After the output channel is closed by passing None to the write function defined in otherlibs/dune-rpc-lwt/src/dune_rpc_lwt.ml I would expect the current/next call to Lwt_io.read* (inside the corresponding read function) to return None.

Actual Behavior

Instead an exception is raised:

Fatal error: exception Unix.Unix_error(Unix.EBADF, "check_descriptor", "")

The current workaround is to use Lwt_io.is_closed to check if the output channel has been closed before attempting to read, but this feels like it shouldn't be necessary. It's also possible to check the file descriptor associated with both the input and output channel to determine if the channel has been closed, as the file is closed when the output channel is closed.

Reproduction

  1. Remove the workaround mentioned above (e.g. redifine the is_channel_closed function to always return false)
  2. The test dune test otherlibs/dune-rpc-lwt/test should now fail, though the error message is surpressed
  3. Build and run the following program which exercises dune_rpc_lwt (build in watch mode as it will connect to the current build server):
module Drpc_lwt = Dune_rpc_lwt.V1
module Drpc = Dune_rpc.V1

let build_dir = "_build"

let () =
  let init = Drpc.Initialize.create ~id:(Drpc.Id.make (Csexp.Atom "hello")) in
  let where = Drpc_lwt.Where.default ~build_dir () in
  print_endline
    (Printf.sprintf "Connecting to server: %s"
       (Dune_rpc_private.Where.to_string where));
  Lwt_main.run
    (let open Lwt.Syntax in
    let open Lwt.Infix in
    let* chan = Drpc_lwt.connect_chan where in
    Drpc_lwt.Client.connect chan init ~f:(fun client ->
        print_endline "client is running";
        let* request =
          Drpc_lwt.Client.Versioned.prepare_request client
            Drpc.Request.build_dir
          >|= Result.get_ok
        in
        let* response =
          Drpc_lwt.Client.request client request () >|= Result.get_ok
        in
        print_endline
          (Printf.sprintf "path is: %s" (Drpc.Path.to_string_absolute response));
        Lwt.return ()))

After removing the workaround, its output should be:

Connecting to server: unix:path=/path/to/project/_build/.rpc/dune
client is running
path is: _build
Fatal error: exception Unix.Unix_error(Unix.EBADF, "check_descriptor", "")

Additional information

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions