If a process want to notify other process with event semantics, such one-side mechanism called Signal, one process received specific event will pause and implement corresponding operation to handle the notification.
For example, a program could receive the stop event sended by Ctrl+C, and stop itself.
The abstraction of handling of signal:
ignore: do own thing and ignore signal
trap: call corresponding operation of the received signal
stop: stop itself
Now, beside this raw idea, we want to classify such abstraction with specified data.
Signal Data
First, we define raw info for each possible event.
So, what if a process want to omit the signal, what should this process do? We will introduce Mask in bit design, which means higher number contains lower number, indicating higher priority.
In a task block, it should record its current mask and current signal priority and each action corresponding to each flags, so we need a fixed array contains ptrs and its priority. After that, we need to record current flag it should implement.
Then our task know which signal should be implemented, which should be omitted.
Signal Handle
Recall that, each process should receive signal and trap into possible level, some may be in S-level, some may be in U-level. And some of them may be illegal or atrocious that we should stop or frozen to wait. If so, we should backup our trap_ctx, because handler contains different environement.
// Some signals are severe and handled by kernel. fncall_kernel_signal_handler(signal: SignalFlags) { let task = current_task().unwrap(); letmut task_inner = task.inner_exclusive_access(); match signal { SignalFlags::SIGSTOP => { task_inner.frozen = true; task_inner.signals ^= SignalFlags::SIGSTOP; } SignalFlags::SIGCONT => { if task_inner.signals.contains(SignalFlags::SIGCONT) { task_inner.signals ^= SignalFlags::SIGCONT; task_inner.frozen = false; } } _ => { // println!( // "[K] call_kernel_signal_handler:: current task sigflag {:?}", // task_inner.signals // ); task_inner.killed = true; } } }
// Some signals are normal and handled by user. fncall_user_signal_handler(sig: usize, signal: SignalFlags) { let task = current_task().unwrap(); letmut task_inner = task.inner_exclusive_access();
let handler = task_inner.signal_actions.table[sig].handler; if handler != 0 { // register signal into task task_inner.handling_sig = sig asisize; task_inner.signals ^= signal;
fncheck_pending_signals() { for sig in0..(MAX_SIG + 1) { let task = current_task().unwrap(); let task_inner = task.inner_exclusive_access(); let signal = SignalFlags::from_bits(1 << sig).unwrap(); if task_inner.signals.contains(signal) && (!task_inner.signal_mask.contains(signal)) { letmut masked = true; let handling_sig = task_inner.handling_sig; if handling_sig == -1 { masked = false; } else { let handling_sig = handling_sig asusize; if !task_inner.signal_actions.table[handling_sig] .mask .contains(signal) { masked = false; } } if !masked { drop(task_inner); drop(task); if signal == SignalFlags::SIGKILL || signal == SignalFlags::SIGSTOP || signal == SignalFlags::SIGCONT || signal == SignalFlags::SIGDEF { // signal is a kernel signal call_kernel_signal_handler(signal); } else { // signal is a user signal call_user_signal_handler(sig, signal); return; } } } } }
Then record a loop function to handle repeatedly while changing the state of task.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// os/src/task/mod.rs
pubfnhandle_signals() { loop { check_pending_signals(); let (frozen, killed) = { let task = current_task().unwrap(); let task_inner = task.inner_exclusive_access(); (task_inner.frozen, task_inner.killed) }; if !frozen || killed { break; } suspend_current_and_run_next(); } }
System Operation
Finally, we will design sys operations to construct interface.
procmask: set mask of current process
sigaction: set handler of a signal of current process and move original handler to our input old_action ptr.
kill: current process send signal to the other
sigreturn: clear current signal and back to original trap state
We will construct it one by one.
procmask is simple, we just set it directly and return original one.