mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 13:06:33 +00:00
Optimize the latency of lmbench-signal-prot
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
7b58d97aa2
commit
a72c7dadf3
@ -168,7 +168,7 @@ fn init_thread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: exit via qemu isa debug device should not be the only way.
|
// TODO: exit via qemu isa debug device should not be the only way.
|
||||||
let exit_code = if initproc.exit_code().unwrap() == 0 {
|
let exit_code = if initproc.exit_code() == 0 {
|
||||||
QemuExitCode::Success
|
QemuExitCode::Success
|
||||||
} else {
|
} else {
|
||||||
QemuExitCode::Failed
|
QemuExitCode::Failed
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
use super::{
|
use super::{
|
||||||
posix_thread::PosixThreadExt,
|
posix_thread::PosixThreadExt,
|
||||||
process_table,
|
process_table,
|
||||||
signal::signals::{user::UserSignal, Signal},
|
signal::{
|
||||||
|
constants::SIGCONT,
|
||||||
|
sig_num::SigNum,
|
||||||
|
signals::{user::UserSignal, Signal},
|
||||||
|
},
|
||||||
Pgid, Pid, Process, Sid, Uid,
|
Pgid, Pid, Process, Sid, Uid,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -18,11 +22,27 @@ use crate::{
|
|||||||
///
|
///
|
||||||
/// If `signal` is `None`, this method will only check permission without sending
|
/// If `signal` is `None`, this method will only check permission without sending
|
||||||
/// any signal.
|
/// any signal.
|
||||||
pub fn kill(pid: Pid, signal: Option<UserSignal>) -> Result<()> {
|
pub fn kill(pid: Pid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||||
|
// Fast path: If the signal is sent to self, we can skip most check.
|
||||||
|
if pid == ctx.process.pid() {
|
||||||
|
let Some(signal) = signal else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
if !ctx.posix_thread.has_signal_blocked(signal.num()) {
|
||||||
|
ctx.posix_thread.enqueue_signal(Box::new(signal));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
return kill_process(ctx.process, Some(signal), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slow path
|
||||||
|
|
||||||
let process = process_table::get_process(pid)
|
let process = process_table::get_process(pid)
|
||||||
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process does not exist"))?;
|
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process does not exist"))?;
|
||||||
|
|
||||||
kill_process(&process, signal)
|
kill_process(&process, signal, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a signal to all processes in a group, using the current process
|
/// Sends a signal to all processes in a group, using the current process
|
||||||
@ -33,13 +53,13 @@ pub fn kill(pid: Pid, signal: Option<UserSignal>) -> Result<()> {
|
|||||||
///
|
///
|
||||||
/// If `signal` is `None`, this method will only check permission without sending
|
/// If `signal` is `None`, this method will only check permission without sending
|
||||||
/// any signal.
|
/// any signal.
|
||||||
pub fn kill_group(pgid: Pgid, signal: Option<UserSignal>) -> Result<()> {
|
pub fn kill_group(pgid: Pgid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||||
let process_group = process_table::get_process_group(&pgid)
|
let process_group = process_table::get_process_group(&pgid)
|
||||||
.ok_or_else(|| Error::with_message(Errno::ESRCH, "target group does not exist"))?;
|
.ok_or_else(|| Error::with_message(Errno::ESRCH, "target group does not exist"))?;
|
||||||
|
|
||||||
let inner = process_group.inner.lock();
|
let inner = process_group.inner.lock();
|
||||||
for process in inner.processes.values() {
|
for process in inner.processes.values() {
|
||||||
kill_process(process, signal)?;
|
kill_process(process, signal, ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -50,7 +70,7 @@ pub fn kill_group(pgid: Pgid, signal: Option<UserSignal>) -> Result<()> {
|
|||||||
///
|
///
|
||||||
/// If `signal` is `None`, this method will only check permission without sending
|
/// If `signal` is `None`, this method will only check permission without sending
|
||||||
/// any signal.
|
/// any signal.
|
||||||
pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>) -> Result<()> {
|
pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||||
let thread = thread_table::get_thread(tid)
|
let thread = thread_table::get_thread(tid)
|
||||||
.ok_or_else(|| Error::with_message(Errno::ESRCH, "target thread does not exist"))?;
|
.ok_or_else(|| Error::with_message(Errno::ESRCH, "target thread does not exist"))?;
|
||||||
|
|
||||||
@ -71,7 +91,7 @@ pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>) -> Result<()> {
|
|||||||
|
|
||||||
// Check permission
|
// Check permission
|
||||||
let signum = signal.map(|signal| signal.num());
|
let signum = signal.map(|signal| signal.num());
|
||||||
let sender = current_thread_sender_ids();
|
let sender = current_thread_sender_ids(signum.as_ref(), ctx);
|
||||||
posix_thread.check_signal_perm(signum.as_ref(), &sender)?;
|
posix_thread.check_signal_perm(signum.as_ref(), &sender)?;
|
||||||
|
|
||||||
if let Some(signal) = signal {
|
if let Some(signal) = signal {
|
||||||
@ -86,66 +106,74 @@ pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>) -> Result<()> {
|
|||||||
///
|
///
|
||||||
/// The credentials of the current process will be checked to determine
|
/// The credentials of the current process will be checked to determine
|
||||||
/// if it is authorized to send the signal to the target group.
|
/// if it is authorized to send the signal to the target group.
|
||||||
pub fn kill_all(signal: Option<UserSignal>) -> Result<()> {
|
pub fn kill_all(signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
for process in process_table::process_table().iter() {
|
for process in process_table::process_table().iter() {
|
||||||
if Arc::ptr_eq(¤t, process) || process.is_init_process() {
|
if Arc::ptr_eq(¤t, process) || process.is_init_process() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
kill_process(process, signal)?;
|
kill_process(process, signal, ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill_process(process: &Process, signal: Option<UserSignal>) -> Result<()> {
|
fn kill_process(process: &Process, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||||
let threads = process.threads().lock();
|
let threads = process.threads().lock();
|
||||||
let posix_threads = threads
|
|
||||||
.iter()
|
|
||||||
.map(|thread| thread.as_posix_thread().unwrap());
|
|
||||||
|
|
||||||
// First check permission
|
|
||||||
let signum = signal.map(|signal| signal.num());
|
let signum = signal.map(|signal| signal.num());
|
||||||
let sender_ids = current_thread_sender_ids();
|
let sender_ids = current_thread_sender_ids(signum.as_ref(), ctx);
|
||||||
let mut permitted_threads = {
|
|
||||||
posix_threads.clone().filter(|posix_thread| {
|
|
||||||
posix_thread
|
|
||||||
.check_signal_perm(signum.as_ref(), &sender_ids)
|
|
||||||
.is_ok()
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
if permitted_threads.clone().count() == 0 {
|
let mut permitted_thread = None;
|
||||||
return_errno_with_message!(Errno::EPERM, "cannot send signal to the target process");
|
for thread in threads.iter() {
|
||||||
}
|
let posix_thread = thread.as_posix_thread().unwrap();
|
||||||
|
|
||||||
let Some(signal) = signal else { return Ok(()) };
|
// First check permission
|
||||||
|
if posix_thread
|
||||||
|
.check_signal_perm(signum.as_ref(), &sender_ids)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
let Some(ref signum) = signum else {
|
||||||
|
// If signal is None, only permission check is required
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
// Send signal to any thread that does not blocks the signal.
|
if !posix_thread.has_signal_blocked(*signum) {
|
||||||
for thread in permitted_threads.clone() {
|
// Send signal to any thread that does not blocks the signal.
|
||||||
if !thread.has_signal_blocked(&signal) {
|
let signal = signal.unwrap();
|
||||||
thread.enqueue_signal(Box::new(signal));
|
posix_thread.enqueue_signal(Box::new(signal));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
} else if permitted_thread.is_none() {
|
||||||
|
permitted_thread = Some(posix_thread);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Some(permitted_thread) = permitted_thread else {
|
||||||
|
return_errno_with_message!(Errno::EPERM, "cannot send signal to the target process");
|
||||||
|
};
|
||||||
|
|
||||||
|
// If signal is None, only permission check is required
|
||||||
|
let Some(signal) = signal else { return Ok(()) };
|
||||||
|
|
||||||
// If all threads block the signal, send signal to the first thread.
|
// If all threads block the signal, send signal to the first thread.
|
||||||
let first_thread = permitted_threads.next().unwrap();
|
permitted_thread.enqueue_signal(Box::new(signal));
|
||||||
first_thread.enqueue_signal(Box::new(signal));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_thread_sender_ids() -> SignalSenderIds {
|
fn current_thread_sender_ids(signum: Option<&SigNum>, ctx: &Context) -> SignalSenderIds {
|
||||||
let current_thread = current_thread!();
|
let credentials = ctx.posix_thread.credentials();
|
||||||
let current_posix_thread = current_thread.as_posix_thread().unwrap();
|
|
||||||
let current_process = current_posix_thread.process();
|
|
||||||
|
|
||||||
let credentials = current_posix_thread.credentials();
|
|
||||||
let ruid = credentials.ruid();
|
let ruid = credentials.ruid();
|
||||||
let euid = credentials.euid();
|
let euid = credentials.euid();
|
||||||
let sid = current_process.session().unwrap().sid();
|
let sid = signum.and_then(|signum| {
|
||||||
|
if *signum == SIGCONT {
|
||||||
|
Some(ctx.process.session().unwrap().sid())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
SignalSenderIds::new(ruid, euid, sid)
|
SignalSenderIds::new(ruid, euid, sid)
|
||||||
}
|
}
|
||||||
@ -156,11 +184,11 @@ fn current_thread_sender_ids() -> SignalSenderIds {
|
|||||||
pub(super) struct SignalSenderIds {
|
pub(super) struct SignalSenderIds {
|
||||||
ruid: Uid,
|
ruid: Uid,
|
||||||
euid: Uid,
|
euid: Uid,
|
||||||
sid: Sid,
|
sid: Option<Sid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignalSenderIds {
|
impl SignalSenderIds {
|
||||||
fn new(ruid: Uid, euid: Uid, sid: Sid) -> Self {
|
fn new(ruid: Uid, euid: Uid, sid: Option<Sid>) -> Self {
|
||||||
Self { ruid, euid, sid }
|
Self { ruid, euid, sid }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +200,7 @@ impl SignalSenderIds {
|
|||||||
self.euid
|
self.euid
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn sid(&self) -> Sid {
|
pub(super) fn sid(&self) -> Option<Sid> {
|
||||||
self.sid
|
self.sid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,9 @@ impl PosixThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the signal is blocked by the thread.
|
/// Returns whether the signal is blocked by the thread.
|
||||||
pub(in crate::process) fn has_signal_blocked(&self, signal: &dyn Signal) -> bool {
|
pub(in crate::process) fn has_signal_blocked(&self, signum: SigNum) -> bool {
|
||||||
self.sig_mask.contains(signal.num(), Ordering::Relaxed)
|
// FIMXE: Some signals cannot be blocked, even set in sig_mask.
|
||||||
|
self.sig_mask.contains(signum, Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether the signal can be delivered to the thread.
|
/// Checks whether the signal can be delivered to the thread.
|
||||||
@ -141,7 +142,7 @@ impl PosixThread {
|
|||||||
&& *signum == SIGCONT
|
&& *signum == SIGCONT
|
||||||
{
|
{
|
||||||
let receiver_sid = self.process().session().unwrap().sid();
|
let receiver_sid = self.process().session().unwrap().sid();
|
||||||
if receiver_sid == sender.sid() {
|
if receiver_sid == sender.sid().unwrap() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ pub struct Process {
|
|||||||
/// The threads
|
/// The threads
|
||||||
threads: Mutex<Vec<Arc<Thread>>>,
|
threads: Mutex<Vec<Arc<Thread>>>,
|
||||||
/// Process status
|
/// Process status
|
||||||
status: Mutex<ProcessStatus>,
|
status: ProcessStatus,
|
||||||
/// Parent process
|
/// Parent process
|
||||||
pub(super) parent: Mutex<Weak<Process>>,
|
pub(super) parent: Mutex<Weak<Process>>,
|
||||||
/// Children processes
|
/// Children processes
|
||||||
@ -140,7 +140,7 @@ impl Process {
|
|||||||
executable_path: RwLock::new(executable_path),
|
executable_path: RwLock::new(executable_path),
|
||||||
process_vm,
|
process_vm,
|
||||||
children_pauser,
|
children_pauser,
|
||||||
status: Mutex::new(ProcessStatus::Uninit),
|
status: ProcessStatus::new_uninit(),
|
||||||
parent: Mutex::new(parent),
|
parent: Mutex::new(parent),
|
||||||
children: Mutex::new(BTreeMap::new()),
|
children: Mutex::new(BTreeMap::new()),
|
||||||
process_group: Mutex::new(Weak::new()),
|
process_group: Mutex::new(Weak::new()),
|
||||||
@ -589,7 +589,7 @@ impl Process {
|
|||||||
let threads = self.threads.lock();
|
let threads = self.threads.lock();
|
||||||
for thread in threads.iter() {
|
for thread in threads.iter() {
|
||||||
let posix_thread = thread.as_posix_thread().unwrap();
|
let posix_thread = thread.as_posix_thread().unwrap();
|
||||||
if !posix_thread.has_signal_blocked(&signal) {
|
if !posix_thread.has_signal_blocked(signal.num()) {
|
||||||
posix_thread.enqueue_signal(Box::new(signal));
|
posix_thread.enqueue_signal(Box::new(signal));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -622,26 +622,23 @@ impl Process {
|
|||||||
// ******************* Status ********************
|
// ******************* Status ********************
|
||||||
|
|
||||||
fn set_runnable(&self) {
|
fn set_runnable(&self) {
|
||||||
self.status.lock().set_runnable();
|
self.status.set_runnable();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_runnable(&self) -> bool {
|
fn is_runnable(&self) -> bool {
|
||||||
self.status.lock().is_runnable()
|
self.status.is_runnable()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_zombie(&self) -> bool {
|
pub fn is_zombie(&self) -> bool {
|
||||||
self.status.lock().is_zombie()
|
self.status.is_zombie()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_zombie(&self, term_status: TermStatus) {
|
pub fn set_zombie(&self, term_status: TermStatus) {
|
||||||
*self.status.lock() = ProcessStatus::Zombie(term_status);
|
self.status.set_zombie(term_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit_code(&self) -> Option<ExitCode> {
|
pub fn exit_code(&self) -> ExitCode {
|
||||||
match &*self.status.lock() {
|
self.status.exit_code()
|
||||||
ProcessStatus::Runnable | ProcessStatus::Uninit => None,
|
|
||||||
ProcessStatus::Zombie(term_status) => Some(term_status.as_u32()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,32 +4,56 @@
|
|||||||
|
|
||||||
//! The process status
|
//! The process status
|
||||||
|
|
||||||
use super::TermStatus;
|
use core::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
use super::{ExitCode, TermStatus};
|
||||||
pub enum ProcessStatus {
|
|
||||||
// Not ready to run
|
/// The status of process.
|
||||||
Uninit,
|
///
|
||||||
/// Can be scheduled to run
|
/// The `ProcessStatus` can be viewed as two parts,
|
||||||
Runnable,
|
/// the highest 32 bits is the value of `TermStatus`, if any,
|
||||||
/// Exit while not reaped by parent
|
/// the lowest 32 bits is the value of status.
|
||||||
Zombie(TermStatus),
|
#[derive(Debug)]
|
||||||
|
pub struct ProcessStatus(AtomicU64);
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Status {
|
||||||
|
Uninit = 0,
|
||||||
|
Runnable = 1,
|
||||||
|
Zombie = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessStatus {
|
impl ProcessStatus {
|
||||||
pub fn set_zombie(&mut self, term_status: TermStatus) {
|
const LOW_MASK: u64 = 0xffff_ffff;
|
||||||
*self = ProcessStatus::Zombie(term_status);
|
|
||||||
|
pub fn new_uninit() -> Self {
|
||||||
|
Self(AtomicU64::new(Status::Uninit as u64))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_zombie(&self, term_status: TermStatus) {
|
||||||
|
let new_val = (term_status.as_u32() as u64) << 32 | Status::Zombie as u64;
|
||||||
|
self.0.store(new_val, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_zombie(&self) -> bool {
|
pub fn is_zombie(&self) -> bool {
|
||||||
matches!(self, ProcessStatus::Zombie(_))
|
self.0.load(Ordering::Relaxed) & Self::LOW_MASK == Status::Zombie as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_runnable(&mut self) {
|
pub fn set_runnable(&self) {
|
||||||
*self = ProcessStatus::Runnable;
|
let new_val = Status::Runnable as u64;
|
||||||
|
self.0.store(new_val, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_runnable(&self) -> bool {
|
pub fn is_runnable(&self) -> bool {
|
||||||
*self == ProcessStatus::Runnable
|
self.0.load(Ordering::Relaxed) & Self::LOW_MASK == Status::Runnable as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the exit code.
|
||||||
|
///
|
||||||
|
/// If the process is not exited, the exit code is zero.
|
||||||
|
/// But if exit code is zero, the process may or may not exit.
|
||||||
|
pub fn exit_code(&self) -> ExitCode {
|
||||||
|
let val = self.0.load(Ordering::Relaxed);
|
||||||
|
(val >> 32 & Self::LOW_MASK) as ExitCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,5 +109,5 @@ fn reap_zombie_child(process: &Process, pid: Pid) -> ExitCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
process_table_mut.remove(&child_process.pid());
|
process_table_mut.remove(&child_process.pid());
|
||||||
child_process.exit_code().unwrap()
|
child_process.exit_code()
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,9 @@ pub fn do_sys_kill(filter: ProcessFilter, sig_num: Option<SigNum>, ctx: &Context
|
|||||||
});
|
});
|
||||||
|
|
||||||
match filter {
|
match filter {
|
||||||
ProcessFilter::Any => kill_all(signal)?,
|
ProcessFilter::Any => kill_all(signal, ctx)?,
|
||||||
ProcessFilter::WithPid(pid) => kill(pid, signal)?,
|
ProcessFilter::WithPid(pid) => kill(pid, signal, ctx)?,
|
||||||
ProcessFilter::WithPgid(pgid) => kill_group(pgid, signal)?,
|
ProcessFilter::WithPgid(pgid) => kill_group(pgid, signal, ctx)?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,6 @@ pub fn sys_tgkill(tgid: Pid, tid: Tid, sig_num: u8, ctx: &Context) -> Result<Sys
|
|||||||
let uid = ctx.posix_thread.credentials().ruid();
|
let uid = ctx.posix_thread.credentials().ruid();
|
||||||
UserSignal::new(sig_num, UserSignalKind::Tkill, pid, uid)
|
UserSignal::new(sig_num, UserSignalKind::Tkill, pid, uid)
|
||||||
});
|
});
|
||||||
tgkill(tid, tgid, signal)?;
|
tgkill(tid, tgid, signal, ctx)?;
|
||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ pub fn sys_wait4(
|
|||||||
return Ok(SyscallReturn::Return(0 as _));
|
return Ok(SyscallReturn::Return(0 as _));
|
||||||
};
|
};
|
||||||
|
|
||||||
let (return_pid, exit_code) = (process.pid(), process.exit_code().unwrap());
|
let (return_pid, exit_code) = (process.pid(), process.exit_code());
|
||||||
if exit_status_ptr != 0 {
|
if exit_status_ptr != 0 {
|
||||||
ctx.get_user_space()
|
ctx.get_user_space()
|
||||||
.write_val(exit_status_ptr as _, &exit_code)?;
|
.write_val(exit_status_ptr as _, &exit_code)?;
|
||||||
|
@ -19,12 +19,12 @@ pub fn handle_exception(ctx: &Context, context: &UserContext) {
|
|||||||
match *exception {
|
match *exception {
|
||||||
PAGE_FAULT => {
|
PAGE_FAULT => {
|
||||||
if handle_page_fault(root_vmar.vm_space(), trap_info).is_err() {
|
if handle_page_fault(root_vmar.vm_space(), trap_info).is_err() {
|
||||||
generate_fault_signal(trap_info);
|
generate_fault_signal(trap_info, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// We current do nothing about other exceptions
|
// We current do nothing about other exceptions
|
||||||
generate_fault_signal(trap_info);
|
generate_fault_signal(trap_info, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,13 +42,14 @@ pub(crate) fn handle_page_fault(
|
|||||||
trap_info.error_code,
|
trap_info.error_code,
|
||||||
page_fault_addr
|
page_fault_addr
|
||||||
);
|
);
|
||||||
|
|
||||||
let not_present = trap_info.error_code & PAGE_NOT_PRESENT_ERROR_MASK == 0;
|
let not_present = trap_info.error_code & PAGE_NOT_PRESENT_ERROR_MASK == 0;
|
||||||
let write = trap_info.error_code & WRITE_ACCESS_MASK != 0;
|
let write = trap_info.error_code & WRITE_ACCESS_MASK != 0;
|
||||||
if not_present || write {
|
if not_present || write {
|
||||||
// If page is not present or due to write access, we should ask the vmar try to commit this page
|
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let root_vmar = current.root_vmar();
|
let root_vmar = current.root_vmar();
|
||||||
|
|
||||||
|
// If page is not present or due to write access, we should ask the vmar try to commit this page
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
Arc::as_ptr(root_vmar.vm_space()),
|
Arc::as_ptr(root_vmar.vm_space()),
|
||||||
vm_space as *const VmSpace
|
vm_space as *const VmSpace
|
||||||
@ -69,10 +70,9 @@ pub(crate) fn handle_page_fault(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// generate a fault signal for current process.
|
/// generate a fault signal for current process.
|
||||||
fn generate_fault_signal(trap_info: &CpuExceptionInfo) {
|
fn generate_fault_signal(trap_info: &CpuExceptionInfo, ctx: &Context) {
|
||||||
let current = current!();
|
|
||||||
let signal = FaultSignal::new(trap_info);
|
let signal = FaultSignal::new(trap_info);
|
||||||
current.enqueue_signal(signal);
|
ctx.posix_thread.enqueue_signal(Box::new(signal));
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! log_trap_common {
|
macro_rules! log_trap_common {
|
||||||
|
@ -7,4 +7,4 @@ set -e
|
|||||||
echo "*** Running the LMbench protection fault latency test ***"
|
echo "*** Running the LMbench protection fault latency test ***"
|
||||||
|
|
||||||
dd if=/dev/zero of=/ext2/test_file bs=1M count=256
|
dd if=/dev/zero of=/ext2/test_file bs=1M count=256
|
||||||
/benchmark/bin/lmbench/lat_sig prot /ext2/test_file
|
/benchmark/bin/lmbench/lat_sig -N 100 prot /ext2/test_file
|
Reference in New Issue
Block a user