Enable syscall restart

This commit is contained in:
Zejun Zhao 2024-12-16 11:32:37 +08:00 committed by Tate, Hongliang Tian
parent ced0023d6b
commit 1b56a8b600
15 changed files with 103 additions and 38 deletions

View File

@ -49,7 +49,11 @@ fn do_accept(
) -> Result<FileDesc> {
let (connected_socket, socket_addr) = {
let socket = get_socket_from_fd(sockfd)?;
socket.accept()?
socket.accept().map_err(|err| match err.error() {
// FIXME: `accept` should not be restarted if a timeout has been set on the socket using `setsockopt`.
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?
};
if flags.contains(Flags::SOCK_NONBLOCK) {

View File

@ -17,6 +17,12 @@ pub fn sys_connect(
debug!("fd = {sockfd}, socket_addr = {socket_addr:?}");
let socket = get_socket_from_fd(sockfd)?;
socket.connect(socket_addr)?;
socket
.connect(socket_addr)
.map_err(|err| match err.error() {
// FIXME: `connect` should not be restarted if a timeout has been set on the socket using `setsockopt`.
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Ok(SyscallReturn::Return(0))
}

View File

@ -26,7 +26,10 @@ pub fn sys_fcntl(fd: FileDesc, cmd: i32, arg: u64, ctx: &Context) -> Result<Sysc
FcntlCmd::F_SETFL => handle_setfl(fd, arg, ctx),
FcntlCmd::F_GETLK => handle_getlk(fd, arg, ctx),
FcntlCmd::F_SETLK => handle_setlk(fd, arg, true, ctx),
FcntlCmd::F_SETLKW => handle_setlk(fd, arg, false, ctx),
FcntlCmd::F_SETLKW => handle_setlk(fd, arg, false, ctx).map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
}),
FcntlCmd::F_GETOWN => handle_getown(fd, ctx),
FcntlCmd::F_SETOWN => handle_setown(fd, arg, ctx),
}

View File

@ -30,7 +30,12 @@ pub fn sys_flock(fd: FileDesc, ops: i32, ctx: &Context) -> Result<SyscallReturn>
let type_ = FlockType::from(ops);
FlockItem::new(&file, type_)
};
inode_file.set_flock(flock, is_nonblocking)?;
inode_file
.set_flock(flock, is_nonblocking)
.map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
}
Ok(SyscallReturn::Return(0))
}

View File

@ -136,13 +136,10 @@ pub fn sys_futex(
return_errno_with_message!(Errno::EINVAL, "unsupported futex op");
}
}
.map_err(|e| {
// From Linux manual, Futex returns `ETIMEDOUT` instead of `ETIME`
if e.error() == Errno::ETIME {
Error::with_message(Errno::ETIMEDOUT, "futex wait timeout")
} else {
e
}
.map_err(|err| match err.error() {
Errno::ETIME => Error::new(Errno::ETIMEDOUT),
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
debug!("futex returns, tid= {} ", ctx.posix_thread.tid());

View File

@ -56,6 +56,7 @@ pub fn sys_ioctl(fd: FileDesc, cmd: u32, arg: Vaddr, ctx: &Context) -> Result<Sy
entry.set_flags(entry.flags() & (!FdFlags::CLOEXEC));
0
}
// FIXME: ioctl operations involving blocking I/O should be able to restart if interrupted
_ => file.ioctl(ioctl_cmd, arg)?,
};
Ok(SyscallReturn::Return(res as _))

View File

@ -33,7 +33,11 @@ pub fn sys_openat(
.fs()
.resolver()
.read()
.open(&fs_path, flags, mask_mode)?;
.open(&fs_path, flags, mask_mode)
.map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Arc::new(inode_handle)
};
let mut file_table = current.file_table().lock();

View File

@ -22,16 +22,22 @@ pub fn sys_read(
// According to <https://man7.org/linux/man-pages/man2/read.2.html>, if
// the user specified an empty buffer, we should detect errors by checking
// the file descriptor. If no errors detected, return 0 successfully.
let read_len = if buf_len != 0 {
let mut writer = ctx
.process
.root_vmar()
.vm_space()
.writer(user_buf_addr, buf_len)?;
file.read(&mut writer)?
} else {
file.read_bytes(&mut [])?
};
let read_len = {
if buf_len != 0 {
let mut writer = ctx
.process
.root_vmar()
.vm_space()
.writer(user_buf_addr, buf_len)?;
file.read(&mut writer)
} else {
file.read_bytes(&mut [])
}
}
.map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Ok(SyscallReturn::Return(read_len as _))
}

View File

@ -27,7 +27,14 @@ pub fn sys_recvfrom(
vm_space.writer(buf, len)?
};
let (recv_size, message_header) = socket.recvmsg(&mut writers, flags)?;
let (recv_size, message_header) =
socket
.recvmsg(&mut writers, flags)
.map_err(|err| match err.error() {
// FIXME: `recvfrom` should not be restarted if a timeout has been set on the socket using `setsockopt`.
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
if let Some(socket_addr) = message_header.addr()
&& src_addr != 0

View File

@ -25,7 +25,13 @@ pub fn sys_recvmsg(
let (total_bytes, message_header) = {
let socket = get_socket_from_fd(sockfd)?;
let mut io_vec_writer = c_user_msghdr.copy_writer_array_from_user(ctx)?;
socket.recvmsg(&mut io_vec_writer, flags)?
socket
.recvmsg(&mut io_vec_writer, flags)
.map_err(|err| match err.error() {
// FIXME: `recvmsg` should not be restarted if a timeout has been set on the socket using `setsockopt`.
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?
};
if let Some(addr) = message_header.addr() {

View File

@ -39,7 +39,13 @@ pub fn sys_sendmsg(
(io_vec_reader, MessageHeader::new(addr, control_message))
};
let total_bytes = socket.sendmsg(&mut io_vec_reader, message_header, flags)?;
let total_bytes = socket
.sendmsg(&mut io_vec_reader, message_header, flags)
.map_err(|err| match err.error() {
// FIXME: `sendmsg` should not be restarted if a timeout has been set on the socket using `setsockopt`.
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Ok(SyscallReturn::Return(total_bytes as _))
}

View File

@ -34,7 +34,13 @@ pub fn sys_sendto(
let vm_space = ctx.process.root_vmar().vm_space();
vm_space.reader(buf, len)?
};
let send_size = socket.sendmsg(&mut reader, message_header, flags)?;
let send_size = socket
.sendmsg(&mut reader, message_header, flags)
.map_err(|err| match err.error() {
// FIXME: `sendto` should not be restarted if a timeout has been set on the socket using `setsockopt`.
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Ok(SyscallReturn::Return(send_size as _))
}

View File

@ -22,7 +22,11 @@ pub fn sys_wait4(
debug!("wait4 current pid = {}", ctx.process.pid());
let process_filter = ProcessFilter::from_id(wait_pid as _);
let waited_process = wait_child_exit(process_filter, wait_options, ctx)?;
let waited_process =
wait_child_exit(process_filter, wait_options, ctx).map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
let Some(process) = waited_process else {
return Ok(SyscallReturn::Return(0 as _));
};

View File

@ -18,7 +18,11 @@ pub fn sys_waitid(
let process_filter = ProcessFilter::from_which_and_id(which, upid)?;
let wait_options = WaitOptions::from_bits(options as u32)
.ok_or(Error::with_message(Errno::EINVAL, "invalid options"))?;
let waited_process = wait_child_exit(process_filter, wait_options, ctx)?;
let waited_process =
wait_child_exit(process_filter, wait_options, ctx).map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
let pid = waited_process.map_or(0, |process| process.pid());
Ok(SyscallReturn::Return(pid as _))
}

View File

@ -22,16 +22,22 @@ pub fn sys_write(
// According to <https://man7.org/linux/man-pages/man2/write.2.html>, if
// the user specified an empty buffer, we should detect errors by checking
// the file descriptor. If no errors detected, return 0 successfully.
let write_len = if user_buf_len != 0 {
let mut reader = ctx
.process
.root_vmar()
.vm_space()
.reader(user_buf_ptr, user_buf_len)?;
file.write(&mut reader)?
} else {
file.write_bytes(&[])?
};
let write_len = {
if user_buf_len != 0 {
let mut reader = ctx
.process
.root_vmar()
.vm_space()
.reader(user_buf_ptr, user_buf_len)?;
file.write(&mut reader)
} else {
file.write_bytes(&[])
}
}
.map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Ok(SyscallReturn::Return(write_len as _))
}