use linux_api::close_range::CloseRangeFlags;
use linux_api::errno::Errno;
use linux_api::fcntl::DescriptorFlags;
use crate::host::descriptor::descriptor_table;
use crate::host::syscall::handler::{SyscallContext, SyscallHandler};
use crate::utility::callback_queue::CallbackQueue;
impl SyscallHandler {
log_syscall!(
close_range,
std::ffi::c_int,
std::ffi::c_uint,
std::ffi::c_uint,
CloseRangeFlags,
);
pub fn close_range(
ctx: &mut SyscallContext,
first: std::ffi::c_uint,
last: std::ffi::c_uint,
flags: std::ffi::c_uint,
) -> Result<(), Errno> {
if first > last {
return Err(Errno::EINVAL);
}
if first > descriptor_table::FD_MAX {
return Ok(());
}
let last = std::cmp::min(last, descriptor_table::FD_MAX);
let first = first.try_into().unwrap();
let last = last.try_into().unwrap();
let range = first..=last;
let Some(flags) = CloseRangeFlags::from_bits(flags) else {
log::debug!("Invalid close_range flags: {flags}");
return Err(Errno::EINVAL);
};
if flags.contains(CloseRangeFlags::CLOSE_RANGE_UNSHARE) {
log::debug!("The CLOSE_RANGE_UNSHARE flag is not implemented");
return Err(Errno::EINVAL);
}
let mut desc_table = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
if flags.contains(CloseRangeFlags::CLOSE_RANGE_CLOEXEC) {
for (fd, desc) in desc_table.iter_mut() {
if range.contains(fd) {
desc.set_flags(desc.flags() | DescriptorFlags::FD_CLOEXEC);
}
}
} else {
let descriptors = desc_table.remove_range(range);
CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
for desc in descriptors {
let _ = desc.close(ctx.objs.host, cb_queue);
}
});
}
Ok(())
}
}