mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Introduce a syscall restart mechanism
This commit is contained in:
parent
b70c4784ed
commit
ced0023d6b
@ -22,6 +22,10 @@ impl LinuxAbi for UserContext {
|
||||
self.rax()
|
||||
}
|
||||
|
||||
fn set_syscall_num(&mut self, num: usize) {
|
||||
self.set_rax(num);
|
||||
}
|
||||
|
||||
fn set_syscall_ret(&mut self, ret: usize) {
|
||||
self.set_rax(ret);
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ pub trait LinuxAbi {
|
||||
/// Get return value of syscall
|
||||
fn syscall_ret(&self) -> usize;
|
||||
|
||||
/// Set number of syscall
|
||||
fn set_syscall_num(&mut self, num: usize);
|
||||
|
||||
/// Set return value of syscall
|
||||
fn set_syscall_ret(&mut self, ret: usize);
|
||||
|
||||
|
@ -150,6 +150,8 @@ pub enum Errno {
|
||||
ERFKILL = 132, /* Operation not possible due to RF-kill */
|
||||
|
||||
EHWPOISON = 133, /* Memory page has hardware error */
|
||||
|
||||
ERESTARTSYS = 512, /* Restart of an interrupted system call. For kernel internal use only. */
|
||||
}
|
||||
|
||||
/// error used in this crate
|
||||
|
@ -10,6 +10,7 @@ use ostd::sync::Waker;
|
||||
use super::{
|
||||
kill::SignalSenderIds,
|
||||
signal::{
|
||||
sig_action::SigAction,
|
||||
sig_mask::{AtomicSigMask, SigMask, SigSet},
|
||||
sig_num::SigNum,
|
||||
sig_queues::SigQueues,
|
||||
@ -220,8 +221,11 @@ impl PosixThread {
|
||||
/// Enqueues a thread-directed signal. This method should only be used for enqueue kernel
|
||||
/// signal and fault signal.
|
||||
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
||||
let signal_number = signal.num();
|
||||
self.sig_queues.enqueue(signal);
|
||||
if let Some(waker) = &*self.signalled_waker.lock() {
|
||||
if self.process().sig_dispositions().lock().get(signal_number) != SigAction::Ign
|
||||
&& let Some(waker) = &*self.signalled_waker.lock()
|
||||
{
|
||||
waker.wake_up();
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ pub use sig_stack::{SigStack, SigStackFlags};
|
||||
|
||||
use super::posix_thread::PosixThread;
|
||||
use crate::{
|
||||
cpu::LinuxAbi,
|
||||
current_userspace,
|
||||
prelude::*,
|
||||
process::{do_exit_group, TermStatus},
|
||||
@ -41,7 +42,11 @@ pub trait SignalContext {
|
||||
// TODO: This interface of this method is error prone.
|
||||
// The method takes an argument for the current thread to optimize its efficiency.
|
||||
/// Handle pending signal for current process.
|
||||
pub fn handle_pending_signal(user_ctx: &mut UserContext, ctx: &Context) -> Result<()> {
|
||||
pub fn handle_pending_signal(
|
||||
user_ctx: &mut UserContext,
|
||||
ctx: &Context,
|
||||
syscall_number: Option<usize>,
|
||||
) -> Result<()> {
|
||||
// We first deal with signal in current thread, then signal in current process.
|
||||
let posix_thread = ctx.posix_thread;
|
||||
let signal = {
|
||||
@ -69,6 +74,17 @@ pub fn handle_pending_signal(user_ctx: &mut UserContext, ctx: &Context) -> Resul
|
||||
restorer_addr,
|
||||
mask,
|
||||
} => {
|
||||
if let Some(syscall_number) = syscall_number
|
||||
&& user_ctx.syscall_ret() == -(Errno::ERESTARTSYS as i32) as usize
|
||||
{
|
||||
if flags.contains(SigActionFlags::SA_RESTART) {
|
||||
user_ctx.set_syscall_num(syscall_number);
|
||||
user_ctx.set_instruction_pointer(user_ctx.instruction_pointer() - 2);
|
||||
} else {
|
||||
user_ctx.set_syscall_ret(-(Errno::EINTR as i32) as usize);
|
||||
}
|
||||
}
|
||||
|
||||
if flags.contains(SigActionFlags::SA_RESETHAND) {
|
||||
// In Linux, SA_RESETHAND corresponds to SA_ONESHOT,
|
||||
// which means the user handler will be executed only once and then reset to the default.
|
||||
|
@ -90,9 +90,6 @@ impl TryFrom<u32> for SigActionFlags {
|
||||
fn try_from(bits: u32) -> Result<Self> {
|
||||
let flags = SigActionFlags::from_bits(bits)
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid sig action flag"))?;
|
||||
if flags.contains(SigActionFlags::SA_RESTART) {
|
||||
warn!("SA_RESTART is not supported");
|
||||
}
|
||||
Ok(flags)
|
||||
}
|
||||
}
|
||||
|
@ -64,22 +64,26 @@ pub fn create_new_user_task(user_space: Arc<UserSpace>, thread_ref: Arc<Thread>)
|
||||
loop {
|
||||
let return_reason = user_mode.execute(has_kernel_event_fn);
|
||||
let user_ctx = user_mode.context_mut();
|
||||
let mut syscall_number = None;
|
||||
// handle user event:
|
||||
match return_reason {
|
||||
ReturnReason::UserException => handle_exception(&ctx, user_ctx),
|
||||
ReturnReason::UserSyscall => handle_syscall(&ctx, user_ctx),
|
||||
ReturnReason::UserSyscall => {
|
||||
syscall_number = Some(user_ctx.syscall_num());
|
||||
handle_syscall(&ctx, user_ctx);
|
||||
}
|
||||
ReturnReason::KernelEvent => {}
|
||||
};
|
||||
|
||||
if current_thread.is_exited() {
|
||||
break;
|
||||
}
|
||||
handle_pending_signal(user_ctx, &ctx).unwrap();
|
||||
handle_pending_signal(user_ctx, &ctx, syscall_number).unwrap();
|
||||
// If current is suspended, wait for a signal to wake up self
|
||||
while current_thread.is_stopped() {
|
||||
Thread::yield_now();
|
||||
debug!("{} is suspended.", current_posix_thread.tid());
|
||||
handle_pending_signal(user_ctx, &ctx).unwrap();
|
||||
handle_pending_signal(user_ctx, &ctx, None).unwrap();
|
||||
}
|
||||
if current_thread.is_exited() {
|
||||
debug!("exit due to signal");
|
||||
|
@ -18,7 +18,7 @@
|
||||
.code64
|
||||
|
||||
.text
|
||||
# extern "sysv64" fn syscall_return(&mut GeneralRegs)
|
||||
# extern "sysv64" fn syscall_return(&mut UserContext)
|
||||
.global syscall_return
|
||||
syscall_return:
|
||||
# disable interrupt
|
||||
@ -34,7 +34,7 @@ syscall_return:
|
||||
|
||||
push rdi # keep rsp 16 bytes align
|
||||
mov gs:4, rsp # store kernel rsp -> TSS.sp0
|
||||
mov rsp, rdi # set rsp -> GeneralRegs
|
||||
mov rsp, rdi # set rsp -> UserContext
|
||||
|
||||
# restore user gsbase
|
||||
swapgs
|
||||
@ -99,8 +99,8 @@ syscall_entry:
|
||||
swapgs # swap in kernel gs
|
||||
mov gs:12, rsp # store user rsp -> scratch at TSS.sp1
|
||||
mov rsp, gs:4 # load kernel rsp <- TSS.sp0
|
||||
pop rsp # load rsp -> GeneralRegs
|
||||
add rsp, 21*8 # rsp -> error code of GeneralRegs
|
||||
pop rsp # load rsp <- UserContext
|
||||
add rsp, 21*8 # rsp -> error code of UserContext
|
||||
|
||||
push 0x100 # push trap_num
|
||||
sub rsp, 16 # skip fsbase, gsbase
|
||||
|
@ -66,7 +66,7 @@ trap_common:
|
||||
__from_user:
|
||||
/*
|
||||
kernel stack:
|
||||
- ptr to GeneralRegs
|
||||
- ptr to UserContext
|
||||
- ss
|
||||
- rsp
|
||||
- rflags
|
||||
@ -80,8 +80,8 @@ __from_user:
|
||||
mov rax, [rsp + 6*8] # rax = user rsp
|
||||
mov gs:12, rax # store user rsp -> scratch at TSS.sp1
|
||||
|
||||
mov rsp, [rsp + 8*8] # load rsp -> GeneralRegs
|
||||
add rsp, 22*8 # rsp -> top of GeneralRegs
|
||||
mov rsp, [rsp + 8*8] # load rsp <- UserContext
|
||||
add rsp, 22*8 # rsp -> top of UserContext
|
||||
mov rax, gs:4 # rax = kernel stack
|
||||
|
||||
# push trap_num, error_code
|
||||
|
Loading…
x
Reference in New Issue
Block a user