-
-
Notifications
You must be signed in to change notification settings - Fork 128
Implement safe io #871
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
Implement safe io #871
Changes from all commits
e94afa1
4e66a7e
733d06f
1d6321d
696197e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<UnixFDList> + Sized { | |
} | ||
|
||
#[doc(alias = "g_unix_fd_list_steal_fds")] | ||
fn steal_fds(&self) -> Vec<RawFd> { | ||
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<O: IsA<UnixFDList>> UnixFDListExtManual for O {} | ||
|
||
pub struct FdArray { | ||
ptr: ptr::NonNull<libc::c_int>, | ||
len: usize, | ||
} | ||
|
||
pub struct FdIterator { | ||
ptr: ptr::NonNull<libc::c_int>, | ||
len: usize, | ||
} | ||
|
||
impl Iterator for FdIterator { | ||
type Item = OwnedFd; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't work. You'll have to keep track of the original pointer so it can be freed on |
||
} | ||
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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't work, you'll also have to free the original pointer |
||
} | ||
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<'_>] { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As you didn't implement |
||
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr() as *const BorrowedFd, self.len) } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -135,7 +135,7 @@ pub fn spawn_async_with_fds<P: AsRef<std::path::Path>>( | |
#[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< | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not make this use the new traits? |
||
P: AsRef<std::path::Path>, | ||
T: FromRawFd, | ||
U: FromRawFd, | ||
|
@@ -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> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should probably return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that compatible with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a prior art |
||
unsafe { | ||
let mut fds = [0, 2]; | ||
let mut error = ptr::null_mut(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<F: FnMut(Pid, i32) + 'static>(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<F> = &*(func as *const RefCell<F>); | ||
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<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>); | ||
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<F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static>( | ||
fn into_raw_unix_fd<F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + Send + 'static>( | ||
func: F, | ||
) -> gpointer { | ||
let func: Box<RefCell<F>> = Box::new(RefCell::new(func)); | ||
|
@@ -208,7 +208,7 @@ fn into_raw_unix_fd<F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static | |
|
||
#[cfg(unix)] | ||
#[cfg_attr(docsrs, doc(cfg(unix)))] | ||
fn into_raw_unix_fd_local<F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static>( | ||
fn into_raw_unix_fd_local<F: FnMut(BorrowedFd, IOCondition) -> ControlFlow + 'static>( | ||
func: F, | ||
) -> gpointer { | ||
let func: Box<ThreadGuard<RefCell<F>>> = 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<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these functions all need to be |
||
pub fn unix_fd_add<F>(fd: impl AsFd, condition: IOCondition, func: F) -> SourceId | ||
A6GibKm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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::<F>), | ||
into_raw_unix_fd(func), | ||
|
@@ -907,7 +907,7 @@ pub fn unix_fd_add_full<F>( | |
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<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId | ||
pub fn unix_fd_add_local<F>(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::<F>), | ||
into_raw_unix_fd_local(func), | ||
|
@@ -984,7 +984,7 @@ pub fn unix_fd_add_local_full<F>( | |
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<F>( | ||
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::< | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to also implement
size_hint()
andDoubleEndedIterator
andExactSizeIterator
andFusedIterator
hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In gstreamer-rs I have this macro for defining iterators like this because they happen quite often. Might be helpful here