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