nodeipc: avoid closing underlying fd multiple times

Summary:
The `FileDescriptor` type will close the underlying fd on drop. In our
use-cases `r` and `w` refer to the same fd so we only need to close it
once. Note the reason we use separate `Mutex`es for r and w is that we
want `recv()` and `send()` running from different threads to not block
by each other.

Reviewed By: zzl0

Differential Revision: D46885308

fbshipit-source-id: b2a5644251ac4773581a995ae8c3d955b0b36861
This commit is contained in:
Jun Wu 2023-06-21 14:49:59 -07:00 committed by Facebook GitHub Bot
parent 8a46d73b6e
commit d9334ee302

View File

@ -12,6 +12,7 @@ use std::io;
use std::io::BufRead; use std::io::BufRead;
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use std::mem::ManuallyDrop;
use std::sync::Mutex; use std::sync::Mutex;
use anyhow::Context; use anyhow::Context;
@ -39,7 +40,9 @@ pub type LibcFd = libc::c_int;
pub struct NodeIpc { pub struct NodeIpc {
// Mutex is used so the static singleton is easier to use // Mutex is used so the static singleton is easier to use
// (send and recv do not take &mut self). // (send and recv do not take &mut self).
pub(crate) w: Mutex<FileDescriptor>, // `r` and `w` share a same file descriptor. `FileDescriptor` closes the underlying
// fd on drop. Use `ManuallyDrop` to avoid duplicated closing.
pub(crate) w: Mutex<ManuallyDrop<FileDescriptor>>,
pub(crate) r: Mutex<io::BufReader<FileDescriptor>>, pub(crate) r: Mutex<io::BufReader<FileDescriptor>>,
// Whether compatible with libuv. // Whether compatible with libuv.
// If true, on Windows, we'll add extra frame headers per message. // If true, on Windows, we'll add extra frame headers per message.
@ -90,6 +93,10 @@ impl NodeIpc {
/// Initialize `NodeIpc` from a OS raw file descriptor. /// Initialize `NodeIpc` from a OS raw file descriptor.
/// The `RawFileDescriptor` is libc fd on POSIX, or `HANDLE` on Windows. /// The `RawFileDescriptor` is libc fd on POSIX, or `HANDLE` on Windows.
///
/// Note: `NodeIpc` will close the underlying file descriptor on drop.
/// So the callsite needs to "forget" the file descriptor if it does not
/// want to close it twice.
pub fn from_raw_file_descriptor( pub fn from_raw_file_descriptor(
raw_file_descriptor: RawFileDescriptor, raw_file_descriptor: RawFileDescriptor,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
@ -97,7 +104,7 @@ impl NodeIpc {
let fd = get_fd(); let fd = get_fd();
let r = Mutex::new(io::BufReader::new(fd)); let r = Mutex::new(io::BufReader::new(fd));
let w = Mutex::new(get_fd()); let w = Mutex::new(ManuallyDrop::new(get_fd()));
let libuv_compat = false; let libuv_compat = false;
let ipc = Self { r, w, libuv_compat }; let ipc = Self { r, w, libuv_compat };
Ok(ipc) Ok(ipc)