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> { ) -> Result<FileDesc> {
let (connected_socket, socket_addr) = { let (connected_socket, socket_addr) = {
let socket = get_socket_from_fd(sockfd)?; 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) { if flags.contains(Flags::SOCK_NONBLOCK) {

View File

@ -17,6 +17,12 @@ pub fn sys_connect(
debug!("fd = {sockfd}, socket_addr = {socket_addr:?}"); debug!("fd = {sockfd}, socket_addr = {socket_addr:?}");
let socket = get_socket_from_fd(sockfd)?; 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)) 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_SETFL => handle_setfl(fd, arg, ctx),
FcntlCmd::F_GETLK => handle_getlk(fd, arg, ctx), FcntlCmd::F_GETLK => handle_getlk(fd, arg, ctx),
FcntlCmd::F_SETLK => handle_setlk(fd, arg, true, 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_GETOWN => handle_getown(fd, ctx),
FcntlCmd::F_SETOWN => handle_setown(fd, arg, 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); let type_ = FlockType::from(ops);
FlockItem::new(&file, type_) 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)) Ok(SyscallReturn::Return(0))
} }

View File

@ -136,13 +136,10 @@ pub fn sys_futex(
return_errno_with_message!(Errno::EINVAL, "unsupported futex op"); return_errno_with_message!(Errno::EINVAL, "unsupported futex op");
} }
} }
.map_err(|e| { .map_err(|err| match err.error() {
// From Linux manual, Futex returns `ETIMEDOUT` instead of `ETIME` Errno::ETIME => Error::new(Errno::ETIMEDOUT),
if e.error() == Errno::ETIME { Errno::EINTR => Error::new(Errno::ERESTARTSYS),
Error::with_message(Errno::ETIMEDOUT, "futex wait timeout") _ => err,
} else {
e
}
})?; })?;
debug!("futex returns, tid= {} ", ctx.posix_thread.tid()); 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)); entry.set_flags(entry.flags() & (!FdFlags::CLOEXEC));
0 0
} }
// FIXME: ioctl operations involving blocking I/O should be able to restart if interrupted
_ => file.ioctl(ioctl_cmd, arg)?, _ => file.ioctl(ioctl_cmd, arg)?,
}; };
Ok(SyscallReturn::Return(res as _)) Ok(SyscallReturn::Return(res as _))

View File

@ -33,7 +33,11 @@ pub fn sys_openat(
.fs() .fs()
.resolver() .resolver()
.read() .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) Arc::new(inode_handle)
}; };
let mut file_table = current.file_table().lock(); 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 // 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 user specified an empty buffer, we should detect errors by checking
// the file descriptor. If no errors detected, return 0 successfully. // the file descriptor. If no errors detected, return 0 successfully.
let read_len = if buf_len != 0 { let read_len = {
let mut writer = ctx if buf_len != 0 {
.process let mut writer = ctx
.root_vmar() .process
.vm_space() .root_vmar()
.writer(user_buf_addr, buf_len)?; .vm_space()
file.read(&mut writer)? .writer(user_buf_addr, buf_len)?;
} else { file.read(&mut writer)
file.read_bytes(&mut [])? } else {
}; file.read_bytes(&mut [])
}
}
.map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Ok(SyscallReturn::Return(read_len as _)) Ok(SyscallReturn::Return(read_len as _))
} }

View File

@ -27,7 +27,14 @@ pub fn sys_recvfrom(
vm_space.writer(buf, len)? 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() if let Some(socket_addr) = message_header.addr()
&& src_addr != 0 && src_addr != 0

View File

@ -25,7 +25,13 @@ pub fn sys_recvmsg(
let (total_bytes, message_header) = { let (total_bytes, message_header) = {
let socket = get_socket_from_fd(sockfd)?; let socket = get_socket_from_fd(sockfd)?;
let mut io_vec_writer = c_user_msghdr.copy_writer_array_from_user(ctx)?; 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() { 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)) (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 _)) 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(); let vm_space = ctx.process.root_vmar().vm_space();
vm_space.reader(buf, len)? 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 _)) Ok(SyscallReturn::Return(send_size as _))
} }

View File

@ -22,7 +22,11 @@ pub fn sys_wait4(
debug!("wait4 current pid = {}", ctx.process.pid()); debug!("wait4 current pid = {}", ctx.process.pid());
let process_filter = ProcessFilter::from_id(wait_pid as _); 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 { let Some(process) = waited_process else {
return Ok(SyscallReturn::Return(0 as _)); 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 process_filter = ProcessFilter::from_which_and_id(which, upid)?;
let wait_options = WaitOptions::from_bits(options as u32) let wait_options = WaitOptions::from_bits(options as u32)
.ok_or(Error::with_message(Errno::EINVAL, "invalid options"))?; .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()); let pid = waited_process.map_or(0, |process| process.pid());
Ok(SyscallReturn::Return(pid as _)) 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 // 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 user specified an empty buffer, we should detect errors by checking
// the file descriptor. If no errors detected, return 0 successfully. // the file descriptor. If no errors detected, return 0 successfully.
let write_len = if user_buf_len != 0 { let write_len = {
let mut reader = ctx if user_buf_len != 0 {
.process let mut reader = ctx
.root_vmar() .process
.vm_space() .root_vmar()
.reader(user_buf_ptr, user_buf_len)?; .vm_space()
file.write(&mut reader)? .reader(user_buf_ptr, user_buf_len)?;
} else { file.write(&mut reader)
file.write_bytes(&[])? } else {
}; file.write_bytes(&[])
}
}
.map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Ok(SyscallReturn::Return(write_len as _)) Ok(SyscallReturn::Return(write_len as _))
} }