Skip to content

Commit a918beb

Browse files
committed
intro crate signal and signal-impl; add getpid()
1 parent 5c05db3 commit a918beb

File tree

16 files changed

+510
-1
lines changed

16 files changed

+510
-1
lines changed

Cargo.lock

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ members = [
1717
"kernel-vm",
1818
"utils",
1919
"easy-fs",
20+
"signal",
21+
"signal-impl",
2022
]
2123
default-members = ["xtask"]
2224

ch7/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ kernel-vm = { path = "../kernel-vm" }
2020
syscall = { path = "../syscall", features = ["kernel"] }
2121
task-manage = { path = "../task-manage" }
2222
easy-fs = { path = "../easy-fs" }
23+
signal = { path = "../signal" }
24+
signal-impl = { path = "../signal-impl" }
2325

2426
[build-dependencies]
2527
linker = { path = "../linker" }

ch7/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,11 @@ mod impls {
521521
}
522522
}
523523
}
524+
525+
fn getpid(&self, _caller: Caller) -> isize {
526+
let current = unsafe { PROCESSOR.current().unwrap() };
527+
current.pid.get_val() as _
528+
}
524529
}
525530

526531
impl Scheduling for SyscallContext {

kernel-context/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ impl LocalContext {
9595
self.sepc
9696
}
9797

98+
/// 修改上下文的 pc。
99+
#[inline]
100+
pub fn pc_mut(&mut self) -> &mut usize {
101+
&mut self.sepc
102+
}
103+
98104
/// 将 pc 移至下一条指令。
99105
///
100106
/// # Notice

signal-impl/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "signal-impl"
3+
version = "0.1.0"
4+
edition = "2021"
5+
authors = ["scPointer <[email protected]>"]
6+
7+
[dependencies]
8+
kernel-context = { path = "../kernel-context" }
9+
signal = { path = "../signal" }

signal-impl/src/default_action.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use super::{SignalNo, SignalResult};
2+
3+
/// 没有处理函数时的默认行为。
4+
/// 参见 `https://venam.nixers.net/blog/unix/2016/10/21/unix-signals.html`
5+
pub enum DefaultAction {
6+
Terminate(i32), // 结束进程。其实更标准的实现应该细分为 terminate / terminate(core dump) / stop
7+
Ignore, // 忽略信号
8+
}
9+
10+
impl From<SignalNo> for DefaultAction {
11+
fn from(signal_no: SignalNo) -> Self {
12+
match signal_no {
13+
SignalNo::SIGCHLD | SignalNo::SIGURG => Self::Ignore,
14+
_ => Self::Terminate(-(signal_no as i32)),
15+
}
16+
}
17+
}
18+
19+
impl Into<SignalResult> for DefaultAction {
20+
fn into(self) -> SignalResult {
21+
match self {
22+
Self::Terminate(exit_code) => SignalResult::ProcessKilled(exit_code),
23+
Self::Ignore => SignalResult::Ignored,
24+
}
25+
}
26+
}

signal-impl/src/lib.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
//! 一种信号模块的实现
2+
3+
#![no_std]
4+
5+
extern crate alloc;
6+
use alloc::boxed::Box;
7+
use signal::{Signal, SignalResult, SignalAction, SignalNo, MAX_SIG};
8+
use kernel_context::LocalContext;
9+
10+
mod default_action;
11+
use default_action::DefaultAction;
12+
mod signal_set;
13+
use signal_set::SignalSet;
14+
15+
/// 正在处理的信号
16+
pub enum HandlingSignal {
17+
Frozen, // 是内核信号,需要暂停当前进程
18+
UserSignal(LocalContext), // 是用户信号,需要保存之前的用户栈
19+
}
20+
21+
/// 管理一个进程中的信号
22+
pub struct SignalImpl {
23+
/// 已收到的信号
24+
pub received: SignalSet,
25+
/// 屏蔽的信号掩码
26+
pub mask: SignalSet,
27+
/// 在信号处理函数中,保存之前的用户栈
28+
pub handling: Option<HandlingSignal>,
29+
/// 当前任务的信号处理函数集
30+
pub actions: [Option<SignalAction>; MAX_SIG + 1],
31+
}
32+
33+
impl SignalImpl {
34+
pub fn new() -> Self {
35+
Self {
36+
received: SignalSet::empty(),
37+
mask: SignalSet::empty(),
38+
handling: None,
39+
actions: [None; MAX_SIG + 1],
40+
}
41+
}
42+
}
43+
44+
impl SignalImpl {
45+
/// 获取一个没有被 mask 屏蔽的信号,并从已收到的信号集合中删除它。如果没有这样的信号,则返回空
46+
fn fetch_signal(&mut self) -> Option<SignalNo> {
47+
// 在已收到的信号中,寻找一个没有被 mask 屏蔽的信号
48+
self.received.find_first_one(self.mask).map(|num| {
49+
self.received.remove_bit(num);
50+
num.into()
51+
})
52+
}
53+
54+
/// 检查是否收到一个信号,如果是,则接收并删除它
55+
fn fetch_and_remove(&mut self, signal_no: SignalNo) -> bool {
56+
if self.received.contain_bit(signal_no as usize)
57+
&& !self.mask.contain_bit(signal_no as usize) {
58+
self.received.remove_bit(signal_no as usize);
59+
true
60+
} else {
61+
false
62+
}
63+
}
64+
}
65+
66+
impl Signal for SignalImpl {
67+
fn from_fork(&mut self) -> Box<dyn Signal> {
68+
Box::new(Self {
69+
received: SignalSet::empty(),
70+
mask: self.mask,
71+
handling: None,
72+
actions: {
73+
let mut actions = [None; MAX_SIG + 1];
74+
actions.copy_from_slice(&self.actions);
75+
actions
76+
},
77+
78+
})
79+
}
80+
81+
fn clear(&mut self) {
82+
for action in &mut self.actions {
83+
action.take();
84+
}
85+
}
86+
87+
/// 添加一个信号
88+
fn add_signal(&mut self, signal: SignalNo) {
89+
self.received.add_bit(signal as usize)
90+
}
91+
92+
/// 是否当前正在处理信号
93+
fn is_handling_signal(&self) -> bool {
94+
self.handling.is_some()
95+
}
96+
97+
/// 设置一个信号处理函数。`sys_sigaction` 会使用
98+
fn set_action(&mut self, signum: SignalNo, action: &SignalAction) -> bool {
99+
if signum == SignalNo::SIGKILL || signum == SignalNo::SIGSTOP {
100+
false
101+
} else {
102+
self.actions[signum as usize] = Some(*action);
103+
true
104+
}
105+
}
106+
107+
/// 获取一个信号处理函数的值。`sys_sigaction` 会使用
108+
fn get_action_ref(&self, signum: SignalNo) -> Option<SignalAction> {
109+
if signum == SignalNo::SIGKILL || signum == SignalNo::SIGSTOP {
110+
None
111+
} else {
112+
Some(self.actions[signum as usize].unwrap_or(SignalAction::default()))
113+
}
114+
}
115+
116+
/// 设置信号掩码,并获取旧的信号掩码,`sys_procmask` 会使用
117+
fn update_mask(&mut self, mask: usize) -> usize {
118+
self.mask.set_new(mask.into())
119+
}
120+
121+
fn handle_signals(&mut self, current_context: &mut LocalContext) -> SignalResult {
122+
if self.is_handling_signal() {
123+
match self.handling.as_ref().unwrap() {
124+
// 如果当前正在暂停状态
125+
HandlingSignal::Frozen => {
126+
// 则检查是否收到 SIGCONT,如果收到则当前任务需要从暂停状态中恢复
127+
if self.fetch_and_remove(SignalNo::SIGCONT) {
128+
self.handling.take();
129+
SignalResult::Handled
130+
} else { // 否则,继续暂停
131+
SignalResult::ProcessSuspended
132+
}
133+
}, // 其他情况下,需要等待当前信号处理结束
134+
_ => SignalResult::IsHandlingSignal,
135+
}
136+
} else if let Some(signal) = self.fetch_signal() {
137+
match signal {
138+
// SIGKILL 信号不能被捕获或忽略
139+
SignalNo::SIGKILL => SignalResult::ProcessKilled(-(signal as i32)),
140+
SignalNo::SIGSTOP => {
141+
self.handling = Some(HandlingSignal::Frozen);
142+
SignalResult::ProcessSuspended
143+
},
144+
_ => {
145+
if let Some(action) = self.actions[signal as usize] {
146+
// 如果用户给定了处理方式,则按照 SignalAction 中的描述处理
147+
// 保存原来用户程序的上下文信息
148+
self.handling = Some(HandlingSignal::UserSignal(current_context.clone()));
149+
// 修改返回后的 pc 值为 handler,修改 a0 为信号编号
150+
//println!("handle pre {:x}, after {:x}", current_context.pc(), action.handler);
151+
*current_context.pc_mut() = action.handler;
152+
*current_context.a_mut(0) = signal as usize;
153+
SignalResult::Handled
154+
} else {
155+
// 否则,使用自定义的 DefaultAction 类来处理
156+
// 然后再转换成 SignalResult
157+
DefaultAction::from(signal).into()
158+
}
159+
},
160+
}
161+
} else {
162+
SignalResult::NoSignal
163+
}
164+
}
165+
166+
fn sig_return(&mut self, current_context: &mut LocalContext) -> bool {
167+
let handling_signal = self.handling.take();
168+
match handling_signal {
169+
Some(HandlingSignal::UserSignal(old_ctx)) => {
170+
//println!("return to {:x} a0 {}", old_ctx.pc(), old_ctx.a(0));
171+
*current_context = old_ctx;
172+
true
173+
},
174+
// 如果当前在处理内核信号,或者没有在处理信号,也就谈不上“返回”了
175+
_ => {
176+
self.handling = handling_signal;
177+
false
178+
},
179+
}
180+
}
181+
}

signal-impl/src/signal_set.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//! 字符数组。可取并集和差集,也可对给定的 mask 取首位
2+
//!
3+
4+
#[derive(Clone, Copy, Debug)]
5+
/// bit数组
6+
pub struct SignalSet(pub usize);
7+
8+
impl SignalSet {
9+
/// 新建一个空的数组
10+
pub fn empty() -> Self {
11+
Self(0)
12+
}
13+
/// 新建一个数组,长为 usize = 8Byte
14+
pub fn new(v: usize) -> Self {
15+
Self(v)
16+
}
17+
/// 直接暴力写入 SignalSet
18+
pub fn reset(&mut self, v: usize) {
19+
self.0 = v;
20+
}
21+
/// 清空 SignalSet
22+
pub fn clear(&mut self) {
23+
self.0 = 0;
24+
}
25+
/// 是否包含第 k 个 bit
26+
pub fn contain_bit(&self, kth: usize) -> bool {
27+
((self.0 >> kth) & 1) > 0
28+
}
29+
/// 新增一个 bit
30+
pub fn add_bit(&mut self, kth: usize) {
31+
self.0 |= 1 << kth;
32+
}
33+
/// 删除一个 bit
34+
pub fn remove_bit(&mut self, kth: usize) {
35+
self.0 &= !(1 << kth);
36+
}
37+
/// 取交集
38+
pub fn get_union(&mut self, set: SignalSet) {
39+
self.0 |= set.0;
40+
}
41+
/// 取差集,即去掉 set 中的内容
42+
pub fn get_difference(&mut self, set: SignalSet) {
43+
self.0 &= !(set.0);
44+
}
45+
/// 直接设置为新值
46+
pub fn set_new(&mut self, set: SignalSet) -> usize {
47+
let old = self.0;
48+
self.0 = set.0;
49+
old
50+
}
51+
/// 获取后缀0个数,可以用来寻找最小的1
52+
pub fn get_trailing_zeros(&self) -> u32 {
53+
self.0.trailing_zeros()
54+
}
55+
/// 寻找不在mask中的最小的 1 的位置,如果有,返回其位置,如没有则返回 None。
56+
pub fn find_first_one(&self, mask: SignalSet) -> Option<usize> {
57+
let ans = (self.0 & !mask.0).trailing_zeros() as usize;
58+
if ans == 64 {
59+
None
60+
} else {
61+
Some(ans)
62+
}
63+
}
64+
}
65+
66+
impl From<usize> for SignalSet {
67+
fn from(v: usize) -> Self {
68+
Self(v)
69+
}
70+
}

signal/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "signal"
3+
version = "0.1.0"
4+
edition = "2021"
5+
authors = ["scPointer <[email protected]>"]
6+
7+
[dependencies]
8+
kernel-context = { path = "../kernel-context" }
9+
numeric-enum-macro = "0.2.0"

0 commit comments

Comments
 (0)