From e94afa1b3637110660c8609b7da83b82c915c092 Mon Sep 17 00:00:00 2001 From: Maximiliano Sandoval R Date: Wed, 28 Dec 2022 18:06:21 +0100 Subject: [PATCH 1/5] unix_fd_add: Port to safe-io --- glib/src/source.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/glib/src/source.rs b/glib/src/source.rs index b7702fa8d45a..4956f0069b52 100644 --- a/glib/src/source.rs +++ b/glib/src/source.rs @@ -1,12 +1,10 @@ // Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; use std::{cell::RefCell, mem::transmute, num::NonZeroU32, time::Duration}; use crate::ffi::{self, gboolean, gpointer}; -#[cfg(all(not(unix), docsrs))] -use libc::c_int as RawFd; #[cfg(unix)] use crate::IOCondition; @@ -154,33 +152,35 @@ fn into_raw_child_watch_local(func: F) -> gpointer #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] unsafe extern "C" fn trampoline_unix_fd< - F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + Send + 'static, >( - fd: i32, + raw_fd: i32, condition: ffi::GIOCondition, func: gpointer, ) -> gboolean { let func: &RefCell = &*(func as *const RefCell); + let fd = BorrowedFd::borrow_raw(raw_fd); (*func.borrow_mut())(fd, from_glib(condition)).into_glib() } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] unsafe extern "C" fn trampoline_unix_fd_local< - F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + 'static, >( - fd: i32, + raw_fd: i32, condition: ffi::GIOCondition, func: gpointer, ) -> gboolean { let func: &ThreadGuard> = &*(func as *const ThreadGuard>); + let fd = BorrowedFd::borrow_raw(raw_fd); (*func.get_ref().borrow_mut())(fd, from_glib(condition)).into_glib() } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] unsafe extern "C" fn destroy_closure_unix_fd< - F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + Send + 'static, >( ptr: gpointer, ) { @@ -190,7 +190,7 @@ unsafe extern "C" fn destroy_closure_unix_fd< #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] unsafe extern "C" fn destroy_closure_unix_fd_local< - F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + 'static, >( ptr: gpointer, ) { @@ -199,7 +199,7 @@ unsafe extern "C" fn destroy_closure_unix_fd_local< #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] -fn into_raw_unix_fd ControlFlow + Send + 'static>( +fn into_raw_unix_fd ControlFlow + Send + 'static>( func: F, ) -> gpointer { let func: Box> = Box::new(RefCell::new(func)); @@ -208,7 +208,7 @@ fn into_raw_unix_fd ControlFlow + Send + 'static #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] -fn into_raw_unix_fd_local ControlFlow + 'static>( +fn into_raw_unix_fd_local ControlFlow + 'static>( func: F, ) -> gpointer { let func: Box>> = Box::new(ThreadGuard::new(RefCell::new(func))); @@ -872,14 +872,14 @@ where /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_unix_fd_add_full")] -pub fn unix_fd_add(fd: RawFd, condition: IOCondition, func: F) -> SourceId +pub fn unix_fd_add(fd: impl AsFd, condition: IOCondition, func: F) -> SourceId where - F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_unix_fd_add_full( ffi::G_PRIORITY_DEFAULT, - fd, + fd.as_fd().as_raw_fd(), condition.into_glib(), Some(trampoline_unix_fd::), into_raw_unix_fd(func), @@ -907,7 +907,7 @@ pub fn unix_fd_add_full( func: F, ) -> SourceId where - F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_unix_fd_add_full( @@ -939,9 +939,9 @@ where /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_unix_fd_add_full")] -pub fn unix_fd_add_local(fd: RawFd, condition: IOCondition, func: F) -> SourceId +pub fn unix_fd_add_local(fd: impl AsFd, condition: IOCondition, func: F) -> SourceId where - F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); @@ -950,7 +950,7 @@ where .expect("default main context already acquired by another thread"); from_glib(ffi::g_unix_fd_add_full( ffi::G_PRIORITY_DEFAULT, - fd, + fd.as_fd().as_raw_fd(), condition.into_glib(), Some(trampoline_unix_fd_local::), into_raw_unix_fd_local(func), @@ -984,7 +984,7 @@ pub fn unix_fd_add_local_full( func: F, ) -> SourceId where - F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); @@ -1230,17 +1230,17 @@ where /// until it returns `ControlFlow::Break`. #[doc(alias = "g_unix_fd_source_new")] pub fn unix_fd_source_new( - fd: RawFd, + fd: impl AsFd, condition: IOCondition, name: Option<&str>, priority: Priority, func: F, ) -> Source where - F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, + F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + Send + 'static, { unsafe { - let source = ffi::g_unix_fd_source_new(fd, condition.into_glib()); + let source = ffi::g_unix_fd_source_new(fd.as_fd().as_raw_fd(), condition.into_glib()); ffi::g_source_set_callback( source, Some(transmute::< From 4e66a7e54e9d11ad1bca873f5c4acdc0cb0a56b1 Mon Sep 17 00:00:00 2001 From: Maximiliano Sandoval R Date: Wed, 28 Dec 2022 19:11:50 +0100 Subject: [PATCH 2/5] glib: Mark unix_open_pipe as unsafe --- glib/src/functions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glib/src/functions.rs b/glib/src/functions.rs index 37e3dd660d2c..daa8430e3864 100644 --- a/glib/src/functions.rs +++ b/glib/src/functions.rs @@ -241,7 +241,7 @@ pub fn compute_checksum_for_string( #[cfg(unix)] #[doc(alias = "g_unix_open_pipe")] -pub fn unix_open_pipe(flags: i32) -> Result<(RawFd, RawFd), Error> { +pub unsafe fn unix_open_pipe(flags: i32) -> Result<(RawFd, RawFd), Error> { unsafe { let mut fds = [0, 2]; let mut error = ptr::null_mut(); From 733d06f885e9b5998770b89c6b24814c42565fa8 Mon Sep 17 00:00:00 2001 From: Maximiliano Sandoval R Date: Wed, 28 Dec 2022 20:19:28 +0100 Subject: [PATCH 3/5] spawn_async_with_fds: Mark as unsafe --- glib/src/functions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glib/src/functions.rs b/glib/src/functions.rs index daa8430e3864..40ebf7eb4393 100644 --- a/glib/src/functions.rs +++ b/glib/src/functions.rs @@ -135,7 +135,7 @@ pub fn spawn_async_with_fds>( #[cfg(not(windows))] #[cfg_attr(docsrs, doc(cfg(not(windows))))] #[doc(alias = "g_spawn_async_with_pipes")] -pub fn spawn_async_with_pipes< +pub unsafe fn spawn_async_with_pipes< P: AsRef, T: FromRawFd, U: FromRawFd, From 1d6321d4141dfd8e15eeb34a3f99b4a04305c4b4 Mon Sep 17 00:00:00 2001 From: Maximiliano Sandoval Date: Mon, 10 Jun 2024 20:02:41 +0200 Subject: [PATCH 4/5] unix_streams: Rename and remove unsafe version --- gio/src/unix_input_stream.rs | 14 +------------- gio/src/unix_output_stream.rs | 14 +------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/gio/src/unix_input_stream.rs b/gio/src/unix_input_stream.rs index a1f3e8769a8b..a6530c0303fd 100644 --- a/gio/src/unix_input_stream.rs +++ b/gio/src/unix_input_stream.rs @@ -13,25 +13,13 @@ impl UnixInputStream { // rustdoc-stripper-ignore-next /// Creates a new [`Self`] that takes ownership of the passed in fd. #[doc(alias = "g_unix_input_stream_new")] - pub fn take_fd(fd: OwnedFd) -> UnixInputStream { + pub fn from_fd(fd: OwnedFd) -> UnixInputStream { let fd = fd.into_raw_fd(); let close_fd = true.into_glib(); unsafe { InputStream::from_glib_full(ffi::g_unix_input_stream_new(fd, close_fd)).unsafe_cast() } } - - // rustdoc-stripper-ignore-next - /// Creates a new [`Self`] that does not take ownership of the passed in fd. - /// - /// # Safety - /// You may only close the fd if all references to this stream have been dropped. - #[doc(alias = "g_unix_input_stream_new")] - pub unsafe fn with_fd(fd: T) -> UnixInputStream { - let fd = fd.as_raw_fd(); - let close_fd = false.into_glib(); - InputStream::from_glib_full(ffi::g_unix_input_stream_new(fd, close_fd)).unsafe_cast() - } } impl AsRawFd for UnixInputStream { diff --git a/gio/src/unix_output_stream.rs b/gio/src/unix_output_stream.rs index acd30a22f510..e9e8b34d64e9 100644 --- a/gio/src/unix_output_stream.rs +++ b/gio/src/unix_output_stream.rs @@ -13,25 +13,13 @@ impl UnixOutputStream { // rustdoc-stripper-ignore-next /// Creates a new [`Self`] that takes ownership of the passed in fd. #[doc(alias = "g_unix_output_stream_new")] - pub fn take_fd(fd: OwnedFd) -> UnixOutputStream { + pub fn from_fd(fd: OwnedFd) -> UnixOutputStream { let fd = fd.into_raw_fd(); let close_fd = true.into_glib(); unsafe { OutputStream::from_glib_full(ffi::g_unix_output_stream_new(fd, close_fd)).unsafe_cast() } } - - // rustdoc-stripper-ignore-next - /// Creates a new [`Self`] that does not take ownership of the passed in fd. - /// - /// # Safety - /// You may only close the fd if all references to this stream have been dropped. - #[doc(alias = "g_unix_output_stream_new")] - pub unsafe fn with_fd(fd: T) -> UnixOutputStream { - let fd = fd.as_raw_fd(); - let close_fd = false.into_glib(); - OutputStream::from_glib_full(ffi::g_unix_output_stream_new(fd, close_fd)).unsafe_cast() - } } impl AsRawFd for UnixOutputStream { From 696197e0a78e4e18a0a059f43c846fc59ca98ae4 Mon Sep 17 00:00:00 2001 From: Maximiliano Sandoval Date: Mon, 3 Jun 2024 18:58:22 +0200 Subject: [PATCH 5/5] wip: unix_fd_list: Use custom iterator for steal_fds --- gio/src/unix_fd_list.rs | 79 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/gio/src/unix_fd_list.rs b/gio/src/unix_fd_list.rs index 06dd8cdc0a5e..a8db9530015f 100644 --- a/gio/src/unix_fd_list.rs +++ b/gio/src/unix_fd_list.rs @@ -1,12 +1,12 @@ // Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] -use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use std::{mem, ptr}; use glib::{prelude::*, translate::*}; #[cfg(all(not(unix), docsrs))] -use socket::{AsFd, AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use socket::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::{ffi, UnixFDList}; @@ -69,16 +69,79 @@ pub trait UnixFDListExtManual: IsA + Sized { } #[doc(alias = "g_unix_fd_list_steal_fds")] - fn steal_fds(&self) -> Vec { + fn steal_fds(&self) -> FdArray { unsafe { let mut length = mem::MaybeUninit::uninit(); - let ret = FromGlibContainer::from_glib_full_num( - ffi::g_unix_fd_list_steal_fds(self.as_ref().to_glib_none().0, length.as_mut_ptr()), - length.assume_init() as usize, - ); - ret + + let ptr = + ffi::g_unix_fd_list_steal_fds(self.as_ref().to_glib_none().0, length.as_mut_ptr()); + + FdArray { + ptr: ptr::NonNull::new(ptr).unwrap(), + len: length.assume_init() as usize, + } } } } impl> UnixFDListExtManual for O {} + +pub struct FdArray { + ptr: ptr::NonNull, + len: usize, +} + +pub struct FdIterator { + ptr: ptr::NonNull, + len: usize, +} + +impl Iterator for FdIterator { + type Item = OwnedFd; + + fn next(&mut self) -> Option { + if self.len > 0 { + let current = self.ptr.as_ptr(); + if self.len > 1 { + let next = unsafe { self.ptr.as_ptr().add(1) }; + self.ptr = ptr::NonNull::new(next).unwrap(); + } + self.len -= 1; + Some(unsafe { OwnedFd::from_raw_fd(*current) }) + } else { + None + } + } +} + +impl Drop for FdArray { + fn drop(&mut self) { + while self.len > 0 { + unsafe { + let current = self.ptr.as_ptr(); + libc::close(*current); + } + if self.len > 1 { + let next = unsafe { self.ptr.as_ptr().add(1) }; + self.ptr = ptr::NonNull::new(next).unwrap(); + } + self.len -= 1; + } + } +} + +impl std::iter::IntoIterator for FdArray { + type Item = OwnedFd; + type IntoIter = FdIterator; + + fn into_iter(mut self) -> Self::IntoIter { + let len = std::mem::take(&mut self.len); + FdIterator { len, ptr: self.ptr } + } +} + +impl FdArray { + pub fn as_slice(&self) -> &[BorrowedFd<'_>] { + unsafe { std::slice::from_raw_parts(self.ptr.as_ptr() as *const BorrowedFd, self.len) } + } +}