signal的发送(暂时父子进程之间共享信号及相应的结构体) (#89)

* 解决由于spinlock.h中包含preempt_enable()带来的循环include问题

* new: 初步实现signal的数据结构

* new:signal相关数据结构

* fix: 解决bindings.rs报一堆警告的问题

* new: rust下的kdebug kinfo kwarn kBUG kerror宏

* 移动asm.h和cmpxchg.h

* new: signal的发送(暂时只支持父子进程共享信号及处理函数)
This commit is contained in:
login 2022-11-23 11:38:20 +08:00 committed by GitHub
parent 3d729e2069
commit 66f67c6a95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1677 additions and 472 deletions

3
kernel/src/arch/mod.rs Normal file
View File

@ -0,0 +1,3 @@
#[cfg(target_arch="x86_64")]
#[macro_use]
pub mod x86_64;

View File

@ -0,0 +1,18 @@
use crate::include::bindings::bindings::process_control_block;
use core::{arch::asm, sync::atomic::compiler_fence};
/// @brief 获取指向当前进程的pcb的可变引用
#[inline]
pub fn current_pcb() -> &'static mut process_control_block {
let ret: Option<&mut process_control_block>;
unsafe {
let mut tmp: u64 = !(32767u64);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
asm!("and {0}, rsp", inout(reg)(tmp),);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
ret = (tmp as *mut process_control_block).as_mut();
}
ret.unwrap()
}

View File

@ -0,0 +1,24 @@
use core::arch::asm;
#[inline]
pub fn local_irq_save(flags: &mut u64) {
unsafe {
asm!(
"pushfq",
"pop rax",
"mov rax, {0}",
"cli",
out(reg)(*flags),
);
}
}
#[inline]
pub fn local_irq_restore(flags: &u64) {
let x = *flags;
unsafe {
asm!("push r15",
"popfq", in("r15")(x));
}
}

View File

@ -0,0 +1,3 @@
pub mod irqflags;
#[macro_use]
pub mod current;

View File

@ -0,0 +1,16 @@
use core::arch::asm;
/// @brief 获取当前cpu的apic id
#[inline]
pub fn arch_current_apic_id() -> u8 {
let cpuid_res: u32;
unsafe {
asm!(
"mov eax, 1",
"cpuid",
"mov r15, ebx",
lateout("r15") cpuid_res
);
}
return (cpuid_res >> 24) as u8;
}

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <common/compiler.h> #include <common/compiler.h>
#include <arch/x86_64/asm/asm.h> #include <asm/asm.h>
/** /**
* @brief extern不存在的函数 * @brief extern不存在的函数

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <asm/asm.h>
// 保存当前rflags的值到变量x内并关闭中断 // 保存当前rflags的值到变量x内并关闭中断
#define local_irq_save(x) __asm__ __volatile__("pushfq ; popq %0 ; cli" \ #define local_irq_save(x) __asm__ __volatile__("pushfq ; popq %0 ; cli" \
: "=g"(x)::"memory") : "=g"(x)::"memory")

View File

@ -0,0 +1,3 @@
#[macro_use]
pub mod asm;
pub mod cpu;

View File

@ -13,11 +13,8 @@
#include <common/compiler.h> #include <common/compiler.h>
#include <common/list.h> #include <common/list.h>
#if ARCH(I386) || ARCH(X86_64)
#include <arch/x86_64/asm/asm.h> #include <asm/asm.h>
#else
#error Arch not supported.
#endif
/** /**
* @brief member的基地址 * @brief member的基地址

View File

@ -1,11 +1,7 @@
#pragma once #pragma once
#include <common/stddef.h> #include <common/stddef.h>
#if ARCH(I386) || ARCH(X86_64) #include <asm/asm.h>
#include <arch/x86_64/asm/asm.h>
#else
#error Arch not supported.
#endif
//链表数据结构 //链表数据结构
struct List struct List

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <common/atomic.h> #include <common/atomic.h>
// 该结构体需要与libs/refcount.rs的保持一致且以rust版本为准
typedef struct refcount_struct { typedef struct refcount_struct {
atomic_t refs; atomic_t refs;
} refcount_t; } refcount_t;

View File

@ -14,6 +14,46 @@ typedef __signalfn_t *__sighandler_t;
typedef uint64_t sigset_t; typedef uint64_t sigset_t;
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
#define SIGPWR 30
#define SIGSYS 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX MAX_SIG_NUM
// 注意该结构体最大16字节
union __sifields { union __sifields {
/* kill() */ /* kill() */
struct struct
@ -27,8 +67,9 @@ union __sifields {
struct \ struct \
{ \ { \
int32_t si_signo; /* signal number */ \ int32_t si_signo; /* signal number */ \
int32_t code; \ int32_t si_code; \
int32_t si_errno; \ int32_t si_errno; \
uint32_t reserved; /* 保留备用 */ \
union __sifields _sifields; \ union __sifields _sifields; \
} }
@ -80,7 +121,6 @@ struct sighand_struct
/** /**
* @brief * @brief
*
*/ */
struct sigpending struct sigpending
{ {

View File

@ -3,14 +3,21 @@
// todo: 将这里更换为手动编写的ffi绑定 // todo: 将这里更换为手动编写的ffi绑定
use crate::include::bindings::bindings::atomic_t; use crate::include::bindings::bindings::atomic_t;
use crate::include::bindings::bindings::refcount_t;
use crate::include::bindings::bindings::spinlock_t; use crate::include::bindings::bindings::spinlock_t;
use crate::include::bindings::bindings::wait_queue_head_t; use crate::include::bindings::bindings::wait_queue_head_t;
use crate::libs::ffi_convert::FFIBind2Rust;
use crate::libs::ffi_convert::__convert_mut;
use crate::libs::ffi_convert::__convert_ref;
use crate::libs::refcount::RefCount;
/// 请注意sigset_t这个bitmap, 第0位表示sig=1的信号。也就是说SignalNumber-1才是sigset_t中对应的位
pub type sigset_t = u64; pub type sigset_t = u64;
pub type __signalfn_t = ::core::option::Option<unsafe extern "C" fn(arg1: ::core::ffi::c_int)>; pub type __signalfn_t = ::core::option::Option<unsafe extern "C" fn(arg1: ::core::ffi::c_int)>;
pub type __sighandler_t = __signalfn_t; pub type __sighandler_t = __signalfn_t;
// 最大的信号数量改动这个值的时候请同步到signal.h)
pub const MAX_SIG_NUM: i32 = 64;
/// 由于signal_struct总是和sighand_struct一起使用并且信号处理的过程中必定会对sighand加锁 /// 由于signal_struct总是和sighand_struct一起使用并且信号处理的过程中必定会对sighand加锁
/// 因此signal_struct不用加锁 /// 因此signal_struct不用加锁
/// **请将该结构体与`include/DragonOS/signal.h`中的保持同步** /// **请将该结构体与`include/DragonOS/signal.h`中的保持同步**
@ -37,11 +44,17 @@ pub union sigaction__union_u {
>, >,
} }
impl core::fmt::Debug for sigaction__union_u{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("sigaction__union_u")
}
}
/** /**
* @brief * @brief
*/ */
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct sigaction { pub struct sigaction {
pub _u: sigaction__union_u, pub _u: sigaction__union_u,
pub sa_flags: u64, pub sa_flags: u64,
@ -49,6 +62,7 @@ pub struct sigaction {
pub sa_restorer: ::core::option::Option<unsafe extern "C" fn()>, // 暂时未实现该函数 pub sa_restorer: ::core::option::Option<unsafe extern "C" fn()>, // 暂时未实现该函数
} }
/** /**
* sigaction结构体中指向的处理函数 * sigaction结构体中指向的处理函数
*/ */
@ -68,13 +82,15 @@ pub union __siginfo_union {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct __siginfo_union_data { pub struct __siginfo_union_data {
pub si_signo: i32, pub si_signo: i32,
pub code: i32, pub si_code: i32,
pub si_errno: i32, pub si_errno: i32,
pub reserved: u32,
pub _sifields: __sifields, pub _sifields: __sifields,
} }
/** /**
* siginfo中signal的来源不同union中对应了不同的数据 * siginfo中signal的来源不同union中对应了不同的数据./=
* union最大占用16字节
*/ */
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -95,12 +111,12 @@ pub struct __sifields__kill {
* @brief pcb之中 * @brief pcb之中
*/ */
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct sighand_struct { pub struct sighand_struct {
pub siglock: spinlock_t, pub siglock: spinlock_t,
pub count: refcount_t, pub count: RefCount,
pub signal_fd_wqh: wait_queue_head_t, pub signal_fd_wqh: wait_queue_head_t,
pub action: [sigaction; 64usize], pub action: [sigaction; MAX_SIG_NUM as usize],
} }
/** /**
@ -111,3 +127,196 @@ pub struct sighand_struct {
pub struct sigpending { pub struct sigpending {
pub signal: sigset_t, pub signal: sigset_t,
} }
#[allow(dead_code)]
#[repr(i32)]
pub enum si_code_val {
/// sent by kill, sigsend, raise
SI_USER = 0,
/// sent by kernel from somewhere
SI_KERNEL = 0x80,
/// 通过sigqueue发送
SI_QUEUE = -1,
/// 定时器过期时发送
SI_TIMER = -2,
/// 当实时消息队列的状态发生改变时发送
SI_MESGQ = -3,
/// 当异步IO完成时发送
SI_ASYNCIO = -4,
/// sent by queued SIGIO
SI_SIGIO = -5,
}
impl si_code_val {
/// 为si_code_val这个枚举类型实现从i32转换到枚举类型的转换函数
#[allow(dead_code)]
pub fn from_i32(x: i32) -> si_code_val {
match x {
0 => Self::SI_USER,
0x80 => Self::SI_KERNEL,
-1 => Self::SI_QUEUE,
-2 => Self::SI_TIMER,
-3 => Self::SI_MESGQ,
-4 => Self::SI_ASYNCIO,
-5 => Self::SI_SIGIO,
_ => panic!("si code not valid"),
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
#[repr(i32)]
pub enum SignalNumber {
SIGHUP = 1,
SIGINT,
SIGQUIT,
SIGILL,
SIGTRAP,
/// SIGABRT和SIGIOT共用这个号码
SIGABRT_OR_IOT,
SIGBUS,
SIGFPE,
SIGKILL,
SIGUSR1,
SIGSEGV = 11,
SIGUSR2,
SIGPIPE,
SIGALRM,
SIGTERM,
SIGSTKFLT,
SIGCHLD,
SIGCONT,
SIGSTOP,
SIGTSTP,
SIGTTIN = 21,
SIGTTOU,
SIGURG,
SIGXCPU,
SIGXFSZ,
SIGVTALRM,
SIGPROF,
SIGWINCH,
/// SIGIO和SIGPOLL共用这个号码
SIGIO_OR_POLL,
SIGPWR,
SIGSYS = 31,
}
/// 为SignalNumber实现判断相等的trait
impl PartialEq for SignalNumber {
fn eq(&self, other: &SignalNumber) -> bool {
*self as i32 == *other as i32
}
}
impl SignalNumber {
/// @brief 从i32转换为SignalNumber枚举类型如果传入的x不符合要求则返回None
#[allow(dead_code)]
pub fn from_i32(x: i32) -> Option<SignalNumber> {
if Self::valid_signal_number(x) {
let ret: SignalNumber = unsafe { core::mem::transmute(x) };
return Some(ret);
}
return None;
}
/// 判断一个数字是否为可用的信号
fn valid_signal_number(x: i32) -> bool {
if x > 0 && x < MAX_SIG_NUM {
return true;
} else {
return false;
}
}
}
#[allow(dead_code)]
pub const SIGRTMIN: i32 = 32;
#[allow(dead_code)]
pub const SIGRTMAX: i32 = MAX_SIG_NUM;
/// @brief 将给定的signal_struct解析为Rust的signal.rs中定义的signal_struct的引用
///
/// 这么做的主要原因在于由于PCB是通过bindgen生成的FFI因此pcb中的结构体类型都是bindgen自动生成的
impl FFIBind2Rust<crate::include::bindings::bindings::signal_struct> for signal_struct {
fn convert_mut<'a>(
src: *mut crate::include::bindings::bindings::signal_struct,
) -> Option<&'a mut Self> {
return __convert_mut(src);
}
fn convert_ref<'a>(
src: *const crate::include::bindings::bindings::signal_struct,
) -> Option<&'a Self> {
return __convert_ref(src);
}
}
/// @brief 将给定的siginfo解析为Rust的signal.rs中定义的siginfo的引用
///
/// 这么做的主要原因在于由于PCB是通过bindgen生成的FFI因此pcb中的结构体类型都是bindgen自动生成的
impl FFIBind2Rust<crate::include::bindings::bindings::siginfo> for siginfo {
fn convert_mut<'a>(
src: *mut crate::include::bindings::bindings::siginfo,
) -> Option<&'a mut Self> {
return __convert_mut(src);
}
fn convert_ref<'a>(
src: *const crate::include::bindings::bindings::siginfo,
) -> Option<&'a Self> {
return __convert_ref(src)
}
}
/// @brief 将给定的sigset_t解析为Rust的signal.rs中定义的sigset_t的引用
///
/// 这么做的主要原因在于由于PCB是通过bindgen生成的FFI因此pcb中的结构体类型都是bindgen自动生成的
impl FFIBind2Rust<crate::include::bindings::bindings::sigset_t> for sigset_t {
fn convert_mut<'a>(
src: *mut crate::include::bindings::bindings::sigset_t,
) -> Option<&'a mut Self> {
return __convert_mut(src);
}
fn convert_ref<'a>(
src: *const crate::include::bindings::bindings::sigset_t,
) -> Option<&'a Self> {
return __convert_ref(src)
}
}
/// @brief 将给定的sigpending解析为Rust的signal.rs中定义的sigpending的引用
///
/// 这么做的主要原因在于由于PCB是通过bindgen生成的FFI因此pcb中的结构体类型都是bindgen自动生成的
impl FFIBind2Rust<crate::include::bindings::bindings::sigpending> for sigpending {
fn convert_mut<'a>(
src: *mut crate::include::bindings::bindings::sigpending,
) -> Option<&'a mut Self> {
return __convert_mut(src);
}
fn convert_ref<'a>(
src: *const crate::include::bindings::bindings::sigpending,
) -> Option<&'a Self> {
return __convert_ref(src)
}
}
/// @brief 将给定的来自bindgen的sighand_struct解析为Rust的signal.rs中定义的sighand_struct的引用
///
/// 这么做的主要原因在于由于PCB是通过bindgen生成的FFI因此pcb中的结构体类型都是bindgen自动生成的会导致无法自定义功能的问题。
impl FFIBind2Rust<crate::include::bindings::bindings::sighand_struct> for sighand_struct{
fn convert_mut<'a>(
src: *mut crate::include::bindings::bindings::sighand_struct,
) -> Option<&'a mut Self> {
return __convert_mut(src);
}
fn convert_ref<'a>(
src: *const crate::include::bindings::bindings::sighand_struct,
) -> Option<&'a Self> {
return __convert_ref(src)
}
}

View File

@ -27,5 +27,6 @@
#include <include/DragonOS/signal.h> #include <include/DragonOS/signal.h>
#include <mm/mm.h> #include <mm/mm.h>
#include <mm/slab.h> #include <mm/slab.h>
#include <process/process.h>
#include <sched/cfs.h> #include <sched/cfs.h>
#include <sched/sched.h> #include <sched/sched.h>

View File

@ -0,0 +1,402 @@
use core::ptr::read_volatile;
use crate::{
include::{
bindings::bindings::{
pid_t, process_control_block, process_find_pcb_by_pid, pt_regs, spinlock_t, EINVAL,
ENOTSUP, ESRCH, PF_EXITING, PF_KTHREAD, PF_WAKEKILL, PROC_INTERRUPTIBLE,
},
DragonOS::signal::{
si_code_val, sighand_struct, siginfo, signal_struct, sigpending, sigset_t,
SignalNumber, MAX_SIG_NUM, sigaction, sigaction__union_u,
},
},
kBUG, kdebug, kwarn,
libs::{
ffi_convert::FFIBind2Rust,
spinlock::{spin_is_locked, spin_lock_irqsave, spin_unlock_irqrestore},
},
println,
process::{
pid::PidType,
process::{process_is_stopped, process_kick, process_wake_up_state},
},
};
use crate::include::DragonOS::signal::{__siginfo_union, __siginfo_union_data};
/// 默认信号处理程序占位符用于在sighand结构体中的action数组中占位
pub static DEFAULT_SIGACTION: sigaction = sigaction{
_u: sigaction__union_u{
_sa_handler: None,
},
sa_flags:0,
sa_mask:0,
sa_restorer:None
};
/// @brief kill系统调用向指定的进程发送信号
/// @param regs->r8 pid 要接收信号的进程id
/// @param regs->r9 sig 信号
#[no_mangle]
pub extern "C" fn sys_kill(regs: &pt_regs) -> u64 {
println!(
"sys kill, target pid={}, file={}, line={}",
regs.r8,
file!(),
line!()
);
let pid: pid_t = regs.r8 as pid_t;
let sig: Option<SignalNumber> = SignalNumber::from_i32(regs.r9 as i32);
if sig.is_none() {
// 传入的signal数值不合法
kwarn!("Not a valid signal number");
return (-(EINVAL as i64)) as u64;
}
// 初始化signal info
let mut info = siginfo {
_sinfo: __siginfo_union {
data: __siginfo_union_data {
si_signo: sig.unwrap() as i32,
si_code: si_code_val::SI_USER as i32,
si_errno: 0,
reserved: 0,
_sifields: crate::include::DragonOS::signal::__sifields {
_kill: crate::include::DragonOS::signal::__sifields__kill { _pid: pid },
},
},
},
};
return signal_kill_something_info(sig.unwrap(), Some(&mut info), pid) as u64;
}
/// 通过kill的方式向目标进程发送信号
/// @param sig 要发送的信号
/// @param info 要发送的信息
/// @param pid 进程id目前只支持pid>0)
fn signal_kill_something_info(sig: SignalNumber, info: Option<&mut siginfo>, pid: pid_t) -> i32 {
// 暂时不支持特殊的kill操作
if pid <= 0 {
kwarn!("Kill operation not support: pid={}", pid);
return -(ENOTSUP as i32);
}
// kill单个进程
return signal_kill_proc_info(sig, info, pid);
}
fn signal_kill_proc_info(sig: SignalNumber, info: Option<&mut siginfo>, pid: pid_t) -> i32 {
let mut retval: i32 = -(ESRCH as i32);
// step1: 当进程管理模块拥有pcblist_lock之后对其加锁
// step2: 根据pid找到pcb
let pcb = unsafe { process_find_pcb_by_pid(pid).as_mut() };
if pcb.is_none() {
kwarn!("No such process.");
return retval;
}
println!("Target pcb = {:?}", pcb.as_ref().unwrap());
// step3: 调用signal_send_sig_info函数发送信息
retval = signal_send_sig_info(sig, info, pcb.unwrap());
// step4: 解锁
return retval;
}
/// @brief 验证信号的值是否在范围内
#[inline]
fn verify_signal(sig: SignalNumber) -> bool {
return if (sig as i32) <= MAX_SIG_NUM {
true
} else {
false
};
}
/// @brief 在发送信号给指定的进程前,做一些权限检查. 检查是否有权限发送
/// @param sig 要发送的信号
/// @param info 要发送的信息
/// @param target_pcb 信号的接收者
fn signal_send_sig_info(
sig: SignalNumber,
info: Option<&mut siginfo>,
target_pcb: &mut process_control_block,
) -> i32 {
kdebug!("signal_send_sig_info");
// 检查sig是否符合要求如果不符合要求则退出。
if !verify_signal(sig) {
return -(EINVAL as i32);
}
// 信号符合要求,可以发送
let mut retval = -(ESRCH as i32);
let mut flags: u64 = 0;
// 如果上锁成功,则发送信号
if !lock_process_sighand(target_pcb, &mut flags).is_none() {
// 发送信号
retval = send_signal_locked(sig, info, target_pcb, PidType::PID);
kdebug!("flags=0x{:016x}", flags);
// 对sighand放锁
unlock_process_sighand(target_pcb, &flags);
}
return retval;
}
/// @brief 对pcb的sighand结构体中的siglock进行加锁并关闭中断
/// @param pcb 目标pcb
/// @param flags 用来保存rflags的变量
/// @return 指向sighand_struct的可变引用
fn lock_process_sighand<'a>(
pcb: &'a mut process_control_block,
flags: &mut u64,
) -> Option<&'a mut sighand_struct> {
kdebug!("lock_process_sighand");
let x = unsafe { &mut *pcb.sighand };
let sighand_ptr = sighand_struct::convert_mut(unsafe { &mut *pcb.sighand });
// kdebug!("sighand_ptr={:?}", &sighand_ptr);
if !sighand_ptr.is_some() {
kBUG!("Sighand ptr of process {pid} is NULL!", pid = pcb.pid);
return None;
}else{
kdebug!("7777");
}
let lock = {&mut sighand_ptr.unwrap().siglock};
kdebug!("123");
kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)});
spin_lock_irqsave(lock, flags);
kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)});
kdebug!("locked");
let ret = unsafe { ((*pcb).sighand as *mut sighand_struct).as_mut() };
return ret;
}
/// @brief 对pcb的sighand结构体中的siglock进行放锁并恢复之前存储的rflags
/// @param pcb 目标pcb
/// @param flags 用来保存rflags的变量将这个值恢复到rflags寄存器中
fn unlock_process_sighand(pcb: &mut process_control_block, flags: &u64) {
kdebug!("unlock_process_sighand");
let lock = unsafe{&mut (*pcb.sighand).siglock};
kdebug!("lock={:?}", lock);
spin_unlock_irqrestore(lock, flags);
kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)});
kdebug!("123443");
}
/// @brief 判断是否需要强制发送信号,然后发送信号
/// 注意进入该函数前我们应当对pcb.sighand.siglock加锁。
///
/// @return i32 错误码
fn send_signal_locked(
sig: SignalNumber,
info: Option<&mut siginfo>,
pcb: &mut process_control_block,
pt: PidType,
) -> i32 {
kdebug!("send_signal_locked");
// 是否强制发送信号
let mut force_send = false;
// signal的信息为空
if info.is_none() {
// todo: 判断signal是否来自于一个祖先进程的namespace如果是则强制发送信号
} else {
force_send = unsafe { info.as_ref().unwrap()._sinfo.data }.si_code
== (si_code_val::SI_KERNEL as i32);
}
kdebug!("force send={}", force_send);
return __send_signal_locked(sig, info, pcb, pt, force_send);
}
/// @brief 发送信号
/// 注意进入该函数前我们应当对pcb.sighand.siglock加锁。
///
/// @param sig 信号
/// @param _info 信号携带的信息
/// @param pcb 目标进程的pcb
/// @param pt siginfo结构体中pid字段代表的含义
/// @return i32 错误码
fn __send_signal_locked(
sig: SignalNumber,
_info: Option<&mut siginfo>,
pcb: &mut process_control_block,
pt: PidType,
_force_send: bool,
) -> i32 {
kdebug!("__send_signal_locked");
let mut retval = 0;
// 判断该进入该函数时,是否已经持有了锁
println!("locked={}",spin_is_locked(unsafe { &(*pcb.sighand).siglock }));
kdebug!("1234");
let _pending: Option<&mut sigpending> = sigpending::convert_mut(&mut pcb.sig_pending);
kdebug!("567");
// 如果是kill或者目标pcb是内核线程则无需获取sigqueue直接发送信号即可
if sig == SignalNumber::SIGKILL || (pcb.flags & (PF_KTHREAD as u64)) != 0 {
complete_signal(sig, pcb, pt);
} else {
// todo: 如果是其他信号则加入到sigqueue内然后complete_signal
retval = -(ENOTSUP as i32);
}
kdebug!("12342");
return retval;
}
/// @brief 将信号添加到目标进程的sig_pending。在引入进程组后本函数还将负责把信号传递给整个进程组。
///
/// @param sig 信号
/// @param pcb 目标pcb
/// @param pt siginfo结构体中pid字段代表的含义
fn complete_signal(sig: SignalNumber, pcb: &mut process_control_block, pt: PidType) {
// todo: 将信号产生的消息通知到正在监听这个信号的进程引入signalfd之后在这里调用signalfd_notify)
kdebug!("complete_signal");
// 将这个信号加到目标进程的sig_pending中
sigset_add(
sigset_t::convert_mut(&mut pcb.sig_pending.signal).unwrap(),
sig,
);
// ===== 寻找需要wakeup的目标进程 =====
// 备注由于当前没有进程组的概念每个进程只有1个对应的线程因此不需要通知进程组内的每个进程。
// todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。
let _signal: Option<&mut signal_struct> = signal_struct::convert_mut(pcb.signal);
let mut _target: Option<&mut process_control_block> = None;
// 判断目标进程是否想接收这个信号
if wants_signal(sig, pcb) {
_target = Some(pcb);
} else if pt == PidType::PID {
/*
* There is just one thread and it does not need to be woken.
* It will dequeue unblocked signals before it runs again.
*/
return;
} else {
/*
* Otherwise try to find a suitable thread.
* 1线dequeue操作不需要考虑同步阻塞的问题
*/
return;
}
// todo:引入进程组后,在这里挑选一个进程来唤醒,让它执行相应的操作。
// todo!();
// todo: 到这里信号已经被放置在共享的pending队列中我们在这里把目标进程唤醒。
if _target.is_some() {
signal_wake_up(pcb, sig == SignalNumber::SIGKILL);
}
}
/// @brief 本函数用于检测指定的进程是否想要接收SIG这个信号。
/// 当我们对于进程组中的所有进程都运行了这个检查之后,我们将可以找到组内愿意接收信号的进程。
/// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。
#[inline]
fn wants_signal(sig: SignalNumber, pcb: &process_control_block) -> bool {
// 如果改进程屏蔽了这个signal则不能接收
if sig_is_member(sigset_t::convert_ref(&pcb.sig_blocked).unwrap(), sig) {
return false;
}
// 如果进程正在退出,则不能接收信号
if (pcb.flags & (PF_EXITING as u64)) > 0 {
return false;
}
if sig == SignalNumber::SIGKILL {
return true;
}
if process_is_stopped(pcb) {
return false;
}
// todo: 检查目标进程是否正在一个cpu上执行如果是则返回true否则继续检查下一项
// 检查目标进程是否有信号正在等待处理如果是则返回false否则返回true
return !has_sig_pending(pcb);
}
/// @brief 判断指定的信号在sigset中的对应位是否被置位
/// @return true: 给定的信号在sigset中被置位
/// @return false: 给定的信号在sigset中没有被置位
#[inline]
fn sig_is_member(set: &sigset_t, _sig: SignalNumber) -> bool {
return if 1 & (set >> ((_sig as u32) - 1)) != 0 {
true
} else {
false
};
}
/// @brief 将指定的信号在sigset中的对应bit进行置位
#[inline]
fn sigset_add(set: &mut sigset_t, _sig: SignalNumber) {
*set |= 1 << ((_sig as u32) - 1);
}
/// @brief 判断signal的处理是否可能使得整个进程组退出
/// @return true 可能会导致退出(不一定)
#[allow(dead_code)]
#[inline]
fn sig_fatal(pcb: &process_control_block, sig: SignalNumber) -> bool {
let handler = unsafe {
sighand_struct::convert_ref(pcb.sighand).unwrap().action[(sig as usize) - 1]
._u
._sa_handler
};
// 如果handler是空采用默认函数signal处理可能会导致进程退出。
if handler.is_none() {
return true;
} else {
return false;
}
// todo: 参照linux的sig_fatal实现完整功能
}
/// @brief 判断某个进程是否有信号正在等待处理
#[inline]
fn has_sig_pending(pcb: &process_control_block) -> bool {
let ptr = &sigpending::convert_ref(&(*pcb).sig_pending).unwrap().signal;
if unsafe { read_volatile(ptr) } != 0 {
return true;
} else {
return false;
}
}
#[inline]
fn signal_wake_up(pcb: &mut process_control_block, fatal: bool) {
let mut state: u64 = 0;
if fatal {
state = PF_WAKEKILL as u64;
}
signal_wake_up_state(pcb, state);
}
fn signal_wake_up_state(pcb: &mut process_control_block, state: u64) {
assert!(spin_is_locked(&unsafe { *pcb.sighand }.siglock));
// todo: 设置线程结构体的标志位为TIF_SIGPENDING
// 如果目标进程已经在运行则发起一个ipi使得它陷入内核
if !process_wake_up_state(pcb, state | (PROC_INTERRUPTIBLE as u64)) {
process_kick(pcb);
}
}

View File

@ -2,27 +2,32 @@
#![no_main] // <1> #![no_main] // <1>
#![feature(core_intrinsics)] // <2> #![feature(core_intrinsics)] // <2>
#![feature(alloc_error_handler)] #![feature(alloc_error_handler)]
#![feature(panic_info_message)]
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
use core::intrinsics; // <2>
use core::panic::PanicInfo; use core::panic::PanicInfo;
#[macro_use]
mod arch;
#[macro_use]
mod include;
mod ipc;
#[macro_use] #[macro_use]
mod mm;
mod include;
mod libs; mod libs;
mod ipc; mod mm;
mod process;
mod sched;
mod smp;
extern crate alloc; extern crate alloc;
use mm::allocator::KernelAllocator; use mm::allocator::KernelAllocator;
// <3> // <3>
use crate::include::bindings::bindings::{BLACK, GREEN}; use crate::{include::bindings::bindings::{process_do_exit, BLACK, GREEN}, arch::x86_64::asm::current::current_pcb};
// 声明全局的slab分配器 // 声明全局的slab分配器
#[cfg_attr(not(test), global_allocator)] #[cfg_attr(not(test), global_allocator)]
@ -31,14 +36,44 @@ pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator {};
/// 全局的panic处理函数 /// 全局的panic处理函数
#[panic_handler] #[panic_handler]
#[no_mangle] #[no_mangle]
pub fn panic(_info: &PanicInfo) -> ! { pub fn panic(info: &PanicInfo) -> ! {
intrinsics::abort(); // <4> kerror!("Kernel Panic Occurred.");
match info.location() {
Some(loc) => {
println!(
"Location:\n\tFile: {}\n\tLine: {}, Column: {}",
loc.file(),
loc.line(),
loc.column()
);
}
None => {
println!("No location info");
}
}
match info.message() {
Some(msg) => {
println!("Message:\n\t{}", msg);
}
None => {
println!("No panic message.");
}
}
println!("Current PCB:\n\t{:?}", current_pcb());
unsafe {
process_do_exit(u64::MAX);
};
loop {
}
} }
/// 该函数用作测试在process.c的initial_kernel_thread()中调用了此函数 /// 该函数用作测试在process.c的initial_kernel_thread()中调用了此函数
#[no_mangle] #[no_mangle]
pub extern "C" fn __rust_demo_func() -> i32 { pub extern "C" fn __rust_demo_func() -> i32 {
printk_color!(GREEN, BLACK, "__rust_demo_func()\n"); printk_color!(GREEN, BLACK, "__rust_demo_func()\n");
return 0; return 0;

11
kernel/src/libs/atomic.rs Normal file
View File

@ -0,0 +1,11 @@
use core::ptr::read_volatile;
use crate::include::bindings::bindings::atomic_t;
/// @brief 原子的读取指定的原子变量的值
#[inline]
pub fn atomic_read(ato:*const atomic_t)-> i64{
unsafe{
return read_volatile(&(*ato).value);
}
}

View File

@ -0,0 +1,29 @@
/// @brief 由bindgen生成的结构体转换成rust原生定义的结构体的特性
pub trait FFIBind2Rust<T> {
/// 转换为不可变引用
fn convert_ref<'a>(src: *const T) -> Option<&'a Self>;
/// 转换为可变引用
fn convert_mut<'a>(src: *mut T) -> Option<&'a mut Self>;
}
pub fn __convert_mut<'a, S, D>(src:*mut S) ->Option<&'a mut D>{
return unsafe {
core::mem::transmute::<
*mut S,
*mut D,
>(src)
.as_mut()
};
}
pub fn __convert_ref<'a, S, D>(src:*const S) ->Option<&'a D>{
return unsafe {
core::mem::transmute::<
*const S,
*const D,
>(src)
.as_ref()
};
}

View File

@ -2,7 +2,7 @@
#include <common/compiler.h> #include <common/compiler.h>
#ifdef __LOCKREF_ENABLE_CMPXCHG__ #ifdef __LOCKREF_ENABLE_CMPXCHG__
#include <arch/x86_64/asm/cmpxchg.h> #include <asm/cmpxchg.h>
#define CMPXCHG_LOOP(__lock_ref, CODE, SUCCESS) \ #define CMPXCHG_LOOP(__lock_ref, CODE, SUCCESS) \
{ \ { \

View File

@ -1 +1,6 @@
pub mod printk; pub mod printk;
pub mod spinlock;
pub mod ffi_convert;
#[macro_use]
pub mod refcount;
pub mod atomic;

View File

@ -0,0 +1,54 @@
use crate::{include::bindings::bindings::{atomic_inc, atomic_t, atomic_dec}, kwarn};
use super::{ffi_convert::{FFIBind2Rust, __convert_mut, __convert_ref}, atomic::atomic_read};
#[derive(Debug, Copy, Clone)]
pub struct RefCount {
pub refs: atomic_t,
}
/// @brief 将给定的来自bindgen的refcount_t解析为Rust的RefCount的引用
impl FFIBind2Rust<crate::include::bindings::bindings::refcount_struct> for RefCount{
fn convert_mut<'a>(
src: *mut crate::include::bindings::bindings::refcount_struct,
) -> Option<&'a mut Self> {
return __convert_mut(src);
}
fn convert_ref<'a>(
src: *const crate::include::bindings::bindings::refcount_struct,
) -> Option<&'a Self> {
return __convert_ref(src)
}
}
macro_rules! REFCOUNT_INIT {
($x:expr) => {
$crate::libs::refcount::RefCount {
refs: atomic_t { value: 0 },
}
};
}
/// @brief 引用计数自增1
#[allow(dead_code)]
#[inline]
pub fn refcount_inc(r: &mut RefCount) {
if atomic_read(&r.refs) == 0{
kwarn!("Refcount increased from 0, may be use-after free");
}
unsafe {
atomic_inc(&mut r.refs);
}
}
/// @brief 引用计数自减1
#[allow(dead_code)]
#[inline]
pub fn refcount_dec(r: &mut RefCount){
unsafe{
atomic_dec(&mut r.refs);
}
}

View File

@ -0,0 +1,30 @@
#![allow(dead_code)]
use core::ptr::read_volatile;
use crate::arch::x86_64::asm::irqflags::{local_irq_restore, local_irq_save};
use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t};
/// @brief 保存中断状态到flags中关闭中断并对自旋锁加锁
pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) {
local_irq_save(flags);
unsafe {
spin_lock(lock);
}
}
/// @brief 恢复rflags以及中断状态并解锁自旋锁
#[no_mangle]
pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: &u64) {
unsafe {
spin_unlock(lock);
}
// kdebug!("123");
local_irq_restore(flags);
}
/// 判断一个自旋锁是否已经被加锁
pub fn spin_is_locked(lock: &spinlock_t) -> bool {
let val = unsafe { read_volatile(&lock.lock as *const i8) };
return if val == 0 { true } else { false };
}

391
kernel/src/process/fork.c Normal file
View File

@ -0,0 +1,391 @@
#include "process.h"
#include <common/err.h>
#include <common/kthread.h>
#include <common/spinlock.h>
extern spinlock_t process_global_pid_write_lock;
extern long process_global_pid;
extern void kernel_thread_func(void);
int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb);
int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb);
int process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb);
int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start,
uint64_t stack_size, struct pt_regs *current_regs);
extern int process_copy_sighand(uint64_t clone_flags, struct process_control_block * pcb);
extern int process_copy_signal(uint64_t clone_flags, struct process_control_block * pcb);
/**
* @brief fork当前进程
*
* @param regs
* @param clone_flags
* @param stack_start
* @param stack_size
* @return unsigned long
*/
unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start,
unsigned long stack_size)
{
int retval = 0;
struct process_control_block *tsk = NULL;
// 为新的进程分配栈空间并将pcb放置在底部
tsk = (struct process_control_block *)kzalloc(STACK_SIZE, 0);
barrier();
if (tsk == NULL)
{
retval = -ENOMEM;
return retval;
}
barrier();
memset(tsk, 0, sizeof(struct process_control_block));
io_mfence();
// 将当前进程的pcb复制到新的pcb内
memcpy(tsk, current_pcb, sizeof(struct process_control_block));
tsk->worker_private = NULL;
io_mfence();
// 初始化进程的循环链表结点
list_init(&tsk->list);
io_mfence();
// 判断是否为内核态调用fork
if ((current_pcb->flags & PF_KTHREAD) && stack_start != 0)
tsk->flags |= PF_KFORK;
if (tsk->flags & PF_KTHREAD)
{
// 对于内核线程设置其worker私有信息
retval = kthread_set_worker_private(tsk);
if (IS_ERR_VALUE(retval))
goto copy_flags_failed;
tsk->virtual_runtime = 0;
}
tsk->priority = 2;
tsk->preempt_count = 0;
// 增加全局的pid并赋值给新进程的pid
spin_lock(&process_global_pid_write_lock);
tsk->pid = process_global_pid++;
barrier();
// 加入到进程链表中
// todo: 对pcb_list_lock加锁
tsk->prev_pcb = &initial_proc_union.pcb;
barrier();
tsk->next_pcb = initial_proc_union.pcb.next_pcb;
barrier();
initial_proc_union.pcb.next_pcb = tsk;
barrier();
tsk->parent_pcb = current_pcb;
barrier();
spin_unlock(&process_global_pid_write_lock);
tsk->cpu_id = proc_current_cpu_id;
tsk->state = PROC_UNINTERRUPTIBLE;
tsk->parent_pcb = current_pcb;
wait_queue_init(&tsk->wait_child_proc_exit, NULL);
barrier();
list_init(&tsk->list);
retval = -ENOMEM;
// 拷贝标志位
retval = process_copy_flags(clone_flags, tsk);
if (retval)
goto copy_flags_failed;
// 拷贝内存空间分布结构体
retval = process_copy_mm(clone_flags, tsk);
if (retval)
goto copy_mm_failed;
// 拷贝文件
retval = process_copy_files(clone_flags, tsk);
if (retval)
goto copy_files_failed;
// 拷贝信号处理函数
retval = process_copy_sighand(clone_flags, tsk);
if(retval)
goto copy_sighand_failed;
retval = process_copy_signal(clone_flags, tsk);
if(retval)
goto copy_signal_failed;
// 拷贝线程结构体
retval = process_copy_thread(clone_flags, tsk, stack_start, stack_size, regs);
if (retval)
goto copy_thread_failed;
// 拷贝成功
retval = tsk->pid;
tsk->flags &= ~PF_KFORK;
// 唤醒进程
process_wakeup(tsk);
return retval;
copy_thread_failed:;
// 回收线程
process_exit_thread(tsk);
copy_files_failed:;
// 回收文件
process_exit_files(tsk);
copy_sighand_failed:;
process_exit_sighand(tsk);
copy_signal_failed:;
process_exit_signal(tsk);
copy_mm_failed:;
// 回收内存空间分布结构体
process_exit_mm(tsk);
copy_flags_failed:;
kfree(tsk);
return retval;
}
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb)
{
if (clone_flags & CLONE_VM)
pcb->flags |= PF_VFORK;
return 0;
}
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb)
{
int retval = 0;
// 如果CLONE_FS被置位那么子进程与父进程共享文件描述符
// 文件描述符已经在复制pcb时被拷贝
if (clone_flags & CLONE_FS)
return retval;
// 为新进程拷贝新的文件描述符
for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
{
if (current_pcb->fds[i] == NULL)
continue;
pcb->fds[i] = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0);
memcpy(pcb->fds[i], current_pcb->fds[i], sizeof(struct vfs_file_t));
}
return retval;
}
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
int process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb)
{
int retval = 0;
// 与父进程共享内存空间
if (clone_flags & CLONE_VM)
{
pcb->mm = current_pcb->mm;
return retval;
}
// 分配新的内存空间分布结构体
struct mm_struct *new_mms = (struct mm_struct *)kmalloc(sizeof(struct mm_struct), 0);
memset(new_mms, 0, sizeof(struct mm_struct));
memcpy(new_mms, current_pcb->mm, sizeof(struct mm_struct));
new_mms->vmas = NULL;
pcb->mm = new_mms;
// 分配顶层页表, 并设置顶层页表的物理地址
new_mms->pgd = (pml4t_t *)virt_2_phys(kmalloc(PAGE_4K_SIZE, 0));
// 由于高2K部分为内核空间在接下来需要覆盖其数据因此不用清零
memset(phys_2_virt(new_mms->pgd), 0, PAGE_4K_SIZE / 2);
// 拷贝内核空间的页表指针
memcpy(phys_2_virt(new_mms->pgd) + 256, phys_2_virt(initial_proc[proc_current_cpu_id]->mm->pgd) + 256,
PAGE_4K_SIZE / 2);
uint64_t *current_pgd = (uint64_t *)phys_2_virt(current_pcb->mm->pgd);
uint64_t *new_pml4t = (uint64_t *)phys_2_virt(new_mms->pgd);
// 拷贝用户空间的vma
struct vm_area_struct *vma = current_pcb->mm->vmas;
while (vma != NULL)
{
if (vma->vm_end > USER_MAX_LINEAR_ADDR || vma->vm_flags & VM_DONTCOPY)
{
vma = vma->vm_next;
continue;
}
int64_t vma_size = vma->vm_end - vma->vm_start;
// kdebug("vma_size=%ld, vm_start=%#018lx", vma_size, vma->vm_start);
if (vma_size > PAGE_2M_SIZE / 2)
{
int page_to_alloc = (PAGE_2M_ALIGN(vma_size)) >> PAGE_2M_SHIFT;
for (int i = 0; i < page_to_alloc; ++i)
{
uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
struct vm_area_struct *new_vma = NULL;
int ret = mm_create_vma(new_mms, vma->vm_start + i * PAGE_2M_SIZE, PAGE_2M_SIZE, vma->vm_flags,
vma->vm_ops, &new_vma);
// 防止内存泄露
if (unlikely(ret == -EEXIST))
free_pages(Phy_to_2M_Page(pa), 1);
else
mm_map_vma(new_vma, pa, 0, PAGE_2M_SIZE);
memcpy((void *)phys_2_virt(pa), (void *)(vma->vm_start + i * PAGE_2M_SIZE),
(vma_size >= PAGE_2M_SIZE) ? PAGE_2M_SIZE : vma_size);
vma_size -= PAGE_2M_SIZE;
}
}
else
{
uint64_t map_size = PAGE_4K_ALIGN(vma_size);
uint64_t va = (uint64_t)kmalloc(map_size, 0);
struct vm_area_struct *new_vma = NULL;
int ret = mm_create_vma(new_mms, vma->vm_start, map_size, vma->vm_flags, vma->vm_ops, &new_vma);
// 防止内存泄露
if (unlikely(ret == -EEXIST))
kfree((void *)va);
else
mm_map_vma(new_vma, virt_2_phys(va), 0, map_size);
memcpy((void *)va, (void *)vma->vm_start, vma_size);
}
vma = vma->vm_next;
}
return retval;
}
/**
* @brief rbp地址
*
* @param new_regs reg
* @param new_pcb pcb
* @return int
*/
static int process_rewrite_rbp(struct pt_regs *new_regs, struct process_control_block *new_pcb)
{
uint64_t new_top = ((uint64_t)new_pcb) + STACK_SIZE;
uint64_t old_top = (uint64_t)(current_pcb) + STACK_SIZE;
uint64_t *rbp = &new_regs->rbp;
uint64_t *tmp = rbp;
// 超出内核栈范围
if ((uint64_t)*rbp >= old_top || (uint64_t)*rbp < (old_top - STACK_SIZE))
return 0;
while (1)
{
// 计算delta
uint64_t delta = old_top - *rbp;
// 计算新的rbp值
uint64_t newVal = new_top - delta;
// 新的值不合法
if (unlikely((uint64_t)newVal >= new_top || (uint64_t)newVal < (new_top - STACK_SIZE)))
break;
// 将新的值写入对应位置
*rbp = newVal;
// 跳转栈帧
rbp = (uint64_t *)*rbp;
}
// 设置内核态fork返回到enter_syscall_int()函数内的时候rsp寄存器的值
new_regs->rsp = new_top - (old_top - new_regs->rsp);
return 0;
}
/**
* @brief 线
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start,
uint64_t stack_size, struct pt_regs *current_regs)
{
// 将线程结构体放置在pcb后方
struct thread_struct *thd = (struct thread_struct *)(pcb + 1);
memset(thd, 0, sizeof(struct thread_struct));
pcb->thread = thd;
struct pt_regs *child_regs = NULL;
// 拷贝栈空间
if (pcb->flags & PF_KFORK) // 内核态下的fork
{
// 内核态下则拷贝整个内核栈
uint32_t size = ((uint64_t)current_pcb) + STACK_SIZE - (uint64_t)(current_regs);
child_regs = (struct pt_regs *)(((uint64_t)pcb) + STACK_SIZE - size);
memcpy(child_regs, (void *)current_regs, size);
barrier();
// 然后重写新的栈中每个栈帧的rbp值
process_rewrite_rbp(child_regs, pcb);
}
else
{
child_regs = (struct pt_regs *)((uint64_t)pcb + STACK_SIZE - sizeof(struct pt_regs));
memcpy(child_regs, current_regs, sizeof(struct pt_regs));
barrier();
child_regs->rsp = stack_start;
}
// 设置子进程的返回值为0
child_regs->rax = 0;
if (pcb->flags & PF_KFORK)
thd->rbp =
(uint64_t)(child_regs + 1); // 设置新的内核线程开始执行时的rbp也就是进入ret_from_system_call时的rbp
else
thd->rbp = (uint64_t)pcb + STACK_SIZE;
// 设置新的内核线程开始执行的时候的rsp
thd->rsp = (uint64_t)child_regs;
thd->fs = current_pcb->thread->fs;
thd->gs = current_pcb->thread->gs;
// 根据是否为内核线程、是否在内核态fork设置进程的开始执行的地址
if (pcb->flags & PF_KFORK)
thd->rip = (uint64_t)ret_from_system_call;
else if (pcb->flags & PF_KTHREAD && (!(pcb->flags & PF_KFORK)))
thd->rip = (uint64_t)kernel_thread_func;
else
thd->rip = (uint64_t)ret_from_system_call;
return 0;
}

View File

@ -0,0 +1,27 @@
use crate::{include::bindings::bindings::{process_control_block, CLONE_SIGHAND}, kdebug, libs::{refcount::{refcount_inc, RefCount}, ffi_convert::FFIBind2Rust}, arch::x86_64::asm::current::current_pcb};
#[no_mangle]
pub extern "C" fn process_copy_sighand(clone_flags: u64, pcb: *mut process_control_block) -> i32 {
kdebug!("process_copy_sighand");
if(clone_flags & (CLONE_SIGHAND as u64)) != 0{
let r = RefCount::convert_mut(unsafe{&mut (*((current_pcb().sighand))).count}).unwrap();
refcount_inc(r);
}
0
}
#[no_mangle]
pub extern "C" fn process_copy_signal(clone_flags: u64, pcb: *mut process_control_block) -> i32 {
kdebug!("process_copy_signal");
0
}
#[no_mangle]
pub extern "C" fn process_exit_signal(pcb: *mut process_control_block){
// todo: 回收进程的信号结构体
}
#[no_mangle]
pub extern "C" fn process_exit_sighand(pcb: *mut process_control_block){
// todo: 回收进程的sighand结构体
}

View File

@ -0,0 +1,26 @@
use crate::{
include::{
bindings::bindings::{atomic_t, spinlock_t, wait_queue_head_t, List},
DragonOS::signal::{sighand_struct, signal_struct, MAX_SIG_NUM},
},
ipc::signal::DEFAULT_SIGACTION,
};
#[no_mangle]
pub static INITIAL_SIGNALS: signal_struct = signal_struct {
sig_cnt: atomic_t { value: 0 },
};
#[no_mangle]
pub static mut INITIAL_SIGHAND: sighand_struct = sighand_struct {
count: REFCOUNT_INIT!(1),
siglock: spinlock_t { lock: 1 },
signal_fd_wqh: wait_queue_head_t {
lock: spinlock_t { lock: 1 },
wait_list: List {
prev: unsafe { &INITIAL_SIGHAND.signal_fd_wqh.wait_list as *const List } as *mut List,
next: unsafe { &INITIAL_SIGHAND.signal_fd_wqh.wait_list as *const List } as *mut List,
},
},
action: [DEFAULT_SIGACTION; MAX_SIG_NUM as usize],
};

View File

@ -0,0 +1,5 @@
pub mod pid;
pub mod process;
pub mod preempt;
pub mod initial_proc;
pub mod fork;

18
kernel/src/process/pid.rs Normal file
View File

@ -0,0 +1,18 @@
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum PidType {
/// pid类型是进程id
PID = 1,
TGID = 2,
PGID = 3,
SID = 4,
MAX = 5,
}
/// 为PidType实现判断相等的trait
impl PartialEq for PidType {
fn eq(&self, other: &PidType) -> bool {
*self as u8 == *other as u8
}
}

View File

@ -0,0 +1,13 @@
use crate::arch::x86_64::asm::current::current_pcb;
/// @brief 增加进程的锁持有计数
#[inline]
pub fn preempt_disable() {
current_pcb().preempt_count += 1;
}
/// @brief 减少进程的锁持有计数
#[inline]
pub fn preempt_enable() {
current_pcb().preempt_count -= 1;
}

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <common/wait_queue.h> #include <stdint.h>
#include <DragonOS/signal.h> #include <DragonOS/signal.h>
#include <common/wait_queue.h>
// 进程最大可拥有的文件描述符数量 // 进程最大可拥有的文件描述符数量
#define PROC_MAX_FD_NUM 16 #define PROC_MAX_FD_NUM 16
@ -12,9 +13,9 @@
// 进程的运行状态 // 进程的运行状态
// 正在运行 // 正在运行
#define PROC_RUNNING (1 << 0) #define PROC_RUNNING (1 << 0)
// 可被 // 可被信号打
#define PROC_INTERRUPTIBLE (1 << 1) #define PROC_INTERRUPTIBLE (1 << 1)
// 不可被 // 不可被信号打
#define PROC_UNINTERRUPTIBLE (1 << 2) #define PROC_UNINTERRUPTIBLE (1 << 2)
// 挂起 // 挂起
#define PROC_ZOMBIE (1 << 3) #define PROC_ZOMBIE (1 << 3)
@ -32,8 +33,9 @@
// 进程初始化时的数据拷贝标志位 // 进程初始化时的数据拷贝标志位
#define CLONE_FS (1UL << 0) // 在进程间共享打开的文件 #define CLONE_FS (1UL << 0) // 在进程间共享打开的文件
#define CLONE_SIGNAL (1UL << 1) #define CLONE_SIGNAL (1UL << 1) // 克隆时,与父进程共享信号结构体
#define CLONE_VM (1UL << 2) // 在进程间共享虚拟内存空间 #define CLONE_VM (1UL << 2) // 在进程间共享虚拟内存空间
#define CLONE_SIGHAND (1UL << 3) // 克隆时,与父进程共享信号处理结构体
#define PCB_NAME_LEN 16 #define PCB_NAME_LEN 16
@ -62,7 +64,8 @@ struct thread_struct
#define PF_VFORK (1UL << 2) // 标志进程是否由于vfork而存在资源共享 #define PF_VFORK (1UL << 2) // 标志进程是否由于vfork而存在资源共享
#define PF_KFORK (1UL << 3) // 标志在内核态下调用fork临时标记do_fork()结束后会将其复位) #define PF_KFORK (1UL << 3) // 标志在内核态下调用fork临时标记do_fork()结束后会将其复位)
#define PF_NOFREEZE (1UL << 4) // 当前进程不能被冻结 #define PF_NOFREEZE (1UL << 4) // 当前进程不能被冻结
#define PF_EXITING (1UL << 5) // 进程正在退出
#define PF_WAKEKILL (1UL << 6) // 进程由于接收到终止信号唤醒
/** /**
* @brief * @brief
* *
@ -70,12 +73,12 @@ struct thread_struct
struct process_control_block struct process_control_block
{ {
// 进程的状态 // 进程的状态
volatile long state; volatile uint64_t state;
// 进程标志:进程、线程、内核线程 // 进程标志:进程、线程、内核线程
unsigned long flags; uint64_t flags;
int64_t preempt_count; // 持有的自旋锁的数量 int32_t preempt_count; // 持有的自旋锁的数量
long cpu_id; // 当前进程在哪个CPU核心上运行 uint32_t cpu_id; // 当前进程在哪个CPU核心上运行
char name[PCB_NAME_LEN]; char name[PCB_NAME_LEN];
// 内存空间分布结构体, 记录内存页表和程序段信息 // 内存空间分布结构体, 记录内存页表和程序段信息
@ -87,7 +90,7 @@ struct process_control_block
// pcb加入调度队列时所使用的链表节点 // pcb加入调度队列时所使用的链表节点
struct List list; struct List list;
//todo:给pcb中加一个spinlock_t成员 // todo:给pcb中加一个spinlock_t成员
//进程自旋锁 //进程自旋锁
// spinlock_t alloc_lock; // spinlock_t alloc_lock;
@ -119,16 +122,14 @@ struct process_control_block
// ==== 信号处理相关 ===== // ==== 信号处理相关 =====
struct signal_struct *signal; struct signal_struct *signal;
struct sighand_struct *sighand; struct sighand_struct *sighand;
// 一个bitmap表示被阻塞的信号 // 一个bitmap表示当前进程被禁用的信号
sigset_t blocked; sigset_t sig_blocked;
// 正在等待的信号的标志位,表示某个信号正在等待处理 // 正在等待的信号的标志位,表示某个信号正在等待处理
struct sigpending sig_pending; struct sigpending sig_pending;
}; };
// 将进程的pcb和内核栈融合到一起,8字节对齐 // 将进程的pcb和内核栈融合到一起,8字节对齐
union proc_union union proc_union {
{
struct process_control_block pcb; struct process_control_block pcb;
ul stack[STACK_SIZE / sizeof(ul)]; ul stack[STACK_SIZE / sizeof(ul)];
} __attribute__((aligned(8))); } __attribute__((aligned(8)));

View File

@ -1,5 +1,6 @@
#include "process.h" #include "process.h"
#include <DragonOS/signal.h>
#include <common/compiler.h> #include <common/compiler.h>
#include <common/completion.h> #include <common/completion.h>
#include <common/elf.h> #include <common/elf.h>
@ -21,13 +22,12 @@
#include <filesystem/devfs/devfs.h> #include <filesystem/devfs/devfs.h>
#include <filesystem/fat32/fat32.h> #include <filesystem/fat32/fat32.h>
#include <filesystem/rootfs/rootfs.h> #include <filesystem/rootfs/rootfs.h>
#include <ktest/ktest.h>
#include <mm/slab.h> #include <mm/slab.h>
#include <sched/sched.h> #include <sched/sched.h>
#include <syscall/syscall.h> #include <syscall/syscall.h>
#include <syscall/syscall_num.h> #include <syscall/syscall_num.h>
#include <ktest/ktest.h>
#include <mm/mmio.h> #include <mm/mmio.h>
#include <common/lz4.h> #include <common/lz4.h>
@ -43,6 +43,19 @@ extern void kernel_thread_func(void);
ul _stack_start; // initial proc的栈基地址虚拟地址 ul _stack_start; // initial proc的栈基地址虚拟地址
extern struct mm_struct initial_mm; extern struct mm_struct initial_mm;
extern struct signal_struct INITIAL_SIGNALS;
extern struct sighand_struct INITIAL_SIGHAND;
// 设置初始进程的PCB
#define INITIAL_PROC(proc) \
{ \
.state = PROC_UNINTERRUPTIBLE, .flags = PF_KTHREAD, .preempt_count = 0, .signal = 0, .cpu_id = 0, \
.mm = &initial_mm, .thread = &initial_thread, .addr_limit = 0xffffffffffffffff, .pid = 0, .priority = 2, \
.virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .prev_pcb = &proc, .parent_pcb = &proc, .exit_code = 0, \
.wait_child_proc_exit = 0, .worker_private = NULL, .policy = SCHED_NORMAL, .sig_blocked = 0, \
.signal = &INITIAL_SIGNALS, .sighand = &INITIAL_SIGHAND, \
}
struct thread_struct initial_thread = { struct thread_struct initial_thread = {
.rbp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), .rbp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),
.rsp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), .rsp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),
@ -62,24 +75,6 @@ struct process_control_block *initial_proc[MAX_CPU_NUM] = {&initial_proc_union.p
// 为每个核心初始化初始进程的tss // 为每个核心初始化初始进程的tss
struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_TSS}; struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_TSS};
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb);
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_files(uint64_t clone_flags, struct process_control_block *pcb);
/** /**
* @brief * @brief
* *
@ -88,15 +83,6 @@ uint64_t process_copy_files(uint64_t clone_flags, struct process_control_block *
*/ */
uint64_t process_exit_files(struct process_control_block *pcb); uint64_t process_exit_files(struct process_control_block *pcb);
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb);
/** /**
* @brief * @brief
* *
@ -105,17 +91,7 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
*/ */
uint64_t process_exit_mm(struct process_control_block *pcb); uint64_t process_exit_mm(struct process_control_block *pcb);
/**
* @brief 线
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start,
uint64_t stack_size, struct pt_regs *current_regs);
void process_exit_thread(struct process_control_block *pcb);
/** /**
* @brief * @brief
@ -644,6 +620,7 @@ void process_init()
// 初始化进程的循环链表 // 初始化进程的循环链表
list_init(&initial_proc_union.pcb.list); list_init(&initial_proc_union.pcb.list);
wait_queue_init(&initial_proc_union.pcb.wait_child_proc_exit, NULL);
// 临时设置IDLE进程的的虚拟运行时间为0防止下面的这些内核线程的虚拟运行时间出错 // 临时设置IDLE进程的的虚拟运行时间为0防止下面的这些内核线程的虚拟运行时间出错
current_pcb->virtual_runtime = 0; current_pcb->virtual_runtime = 0;
@ -660,130 +637,9 @@ void process_init()
current_pcb->virtual_runtime = (1UL << 60); current_pcb->virtual_runtime = (1UL << 60);
} }
/**
* @brief fork当前进程
*
* @param regs
* @param clone_flags
* @param stack_start
* @param stack_size
* @return unsigned long
*/
unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start,
unsigned long stack_size)
{
int retval = 0;
struct process_control_block *tsk = NULL;
// 为新的进程分配栈空间并将pcb放置在底部
tsk = (struct process_control_block *)kzalloc(STACK_SIZE, 0);
barrier();
if (tsk == NULL)
{
retval = -ENOMEM;
return retval;
}
barrier();
memset(tsk, 0, sizeof(struct process_control_block));
io_mfence();
// 将当前进程的pcb复制到新的pcb内
memcpy(tsk, current_pcb, sizeof(struct process_control_block));
tsk->worker_private = NULL;
io_mfence();
// 初始化进程的循环链表结点
list_init(&tsk->list);
io_mfence();
// 判断是否为内核态调用fork
if ((current_pcb->flags & PF_KTHREAD) && stack_start != 0)
tsk->flags |= PF_KFORK;
if (tsk->flags & PF_KTHREAD)
{
// 对于内核线程设置其worker私有信息
retval = kthread_set_worker_private(tsk);
if (IS_ERR_VALUE(retval))
goto copy_flags_failed;
tsk->virtual_runtime = 0;
}
tsk->priority = 2;
tsk->preempt_count = 0;
// 增加全局的pid并赋值给新进程的pid
spin_lock(&process_global_pid_write_lock);
tsk->pid = process_global_pid++;
barrier();
// 加入到进程链表中
// todo: 对pcb_list_lock加锁
tsk->prev_pcb = &initial_proc_union.pcb;
barrier();
tsk->next_pcb = initial_proc_union.pcb.next_pcb;
barrier();
initial_proc_union.pcb.next_pcb = tsk;
barrier();
tsk->parent_pcb = current_pcb;
barrier();
spin_unlock(&process_global_pid_write_lock);
tsk->cpu_id = proc_current_cpu_id;
tsk->state = PROC_UNINTERRUPTIBLE;
tsk->parent_pcb = current_pcb;
wait_queue_init(&tsk->wait_child_proc_exit, NULL);
barrier();
list_init(&tsk->list);
retval = -ENOMEM;
// 拷贝标志位
if (process_copy_flags(clone_flags, tsk))
goto copy_flags_failed;
// 拷贝内存空间分布结构体
if (process_copy_mm(clone_flags, tsk))
goto copy_mm_failed;
// 拷贝文件
if (process_copy_files(clone_flags, tsk))
goto copy_files_failed;
// 拷贝线程结构体
if (process_copy_thread(clone_flags, tsk, stack_start, stack_size, regs))
goto copy_thread_failed;
// 拷贝成功
retval = tsk->pid;
tsk->flags &= ~PF_KFORK;
// 唤醒进程
process_wakeup(tsk);
return retval;
copy_thread_failed:;
// 回收线程
process_exit_thread(tsk);
copy_files_failed:;
// 回收文件
process_exit_files(tsk);
copy_mm_failed:;
// 回收内存空间分布结构体
process_exit_mm(tsk);
copy_flags_failed:;
kfree(tsk);
return retval;
return 0;
}
/** /**
* @brief pid获取进程的pcbpcb时pcb的指针NULL * @brief pid获取进程的pcbpcb时pcb的指针NULL
* * pcblist_lock之后
* @param pid * @param pid
* @return struct process_control_block* * @return struct process_control_block*
*/ */
@ -803,16 +659,19 @@ struct process_control_block *process_find_pcb_by_pid(pid_t pid)
} }
/** /**
* @brief * @brief .
* *
* @param pcb pcb * @param pcb pcb
*
* @return true
* @return false
*/ */
int process_wakeup(struct process_control_block *pcb) int process_wakeup(struct process_control_block *pcb)
{ {
// kdebug("pcb pid = %#018lx", pcb->pid); // kdebug("pcb pid = %#018lx", pcb->pid);
BUG_ON(pcb == NULL); BUG_ON(pcb == NULL);
if (pcb == current_pcb || pcb == NULL) if (pcb == NULL)
return -EINVAL; return -EINVAL;
// 如果pcb正在调度队列中则不重复加入调度队列 // 如果pcb正在调度队列中则不重复加入调度队列
if (pcb->state & PROC_RUNNING) if (pcb->state & PROC_RUNNING)
@ -820,7 +679,7 @@ int process_wakeup(struct process_control_block *pcb)
pcb->state |= PROC_RUNNING; pcb->state |= PROC_RUNNING;
sched_enqueue(pcb); sched_enqueue(pcb);
return 0; return 1;
} }
/** /**
@ -838,47 +697,6 @@ int process_wakeup_immediately(struct process_control_block *pcb)
// 将当前进程标志为需要调度缩短新进程被wakeup的时间 // 将当前进程标志为需要调度缩短新进程被wakeup的时间
current_pcb->flags |= PF_NEED_SCHED; current_pcb->flags |= PF_NEED_SCHED;
} }
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb)
{
if (clone_flags & CLONE_VM)
pcb->flags |= PF_VFORK;
return 0;
}
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_files(uint64_t clone_flags, struct process_control_block *pcb)
{
int retval = 0;
// 如果CLONE_FS被置位那么子进程与父进程共享文件描述符
// 文件描述符已经在复制pcb时被拷贝
if (clone_flags & CLONE_FS)
return retval;
// 为新进程拷贝新的文件描述符
for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
{
if (current_pcb->fds[i] == NULL)
continue;
pcb->fds[i] = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0);
memcpy(pcb->fds[i], current_pcb->fds[i], sizeof(struct vfs_file_t));
}
return retval;
}
/** /**
* @brief * @brief
@ -903,99 +721,6 @@ uint64_t process_exit_files(struct process_control_block *pcb)
memset(pcb->fds, 0, sizeof(struct vfs_file_t *) * PROC_MAX_FD_NUM); memset(pcb->fds, 0, sizeof(struct vfs_file_t *) * PROC_MAX_FD_NUM);
} }
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb)
{
int retval = 0;
// 与父进程共享内存空间
if (clone_flags & CLONE_VM)
{
pcb->mm = current_pcb->mm;
return retval;
}
// 分配新的内存空间分布结构体
struct mm_struct *new_mms = (struct mm_struct *)kmalloc(sizeof(struct mm_struct), 0);
memset(new_mms, 0, sizeof(struct mm_struct));
memcpy(new_mms, current_pcb->mm, sizeof(struct mm_struct));
new_mms->vmas = NULL;
pcb->mm = new_mms;
// 分配顶层页表, 并设置顶层页表的物理地址
new_mms->pgd = (pml4t_t *)virt_2_phys(kmalloc(PAGE_4K_SIZE, 0));
// 由于高2K部分为内核空间在接下来需要覆盖其数据因此不用清零
memset(phys_2_virt(new_mms->pgd), 0, PAGE_4K_SIZE / 2);
// 拷贝内核空间的页表指针
memcpy(phys_2_virt(new_mms->pgd) + 256, phys_2_virt(initial_proc[proc_current_cpu_id]->mm->pgd) + 256,
PAGE_4K_SIZE / 2);
uint64_t *current_pgd = (uint64_t *)phys_2_virt(current_pcb->mm->pgd);
uint64_t *new_pml4t = (uint64_t *)phys_2_virt(new_mms->pgd);
// 拷贝用户空间的vma
struct vm_area_struct *vma = current_pcb->mm->vmas;
while (vma != NULL)
{
if (vma->vm_end > USER_MAX_LINEAR_ADDR || vma->vm_flags & VM_DONTCOPY)
{
vma = vma->vm_next;
continue;
}
int64_t vma_size = vma->vm_end - vma->vm_start;
// kdebug("vma_size=%ld, vm_start=%#018lx", vma_size, vma->vm_start);
if (vma_size > PAGE_2M_SIZE / 2)
{
int page_to_alloc = (PAGE_2M_ALIGN(vma_size)) >> PAGE_2M_SHIFT;
for (int i = 0; i < page_to_alloc; ++i)
{
uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
struct vm_area_struct *new_vma = NULL;
int ret = mm_create_vma(new_mms, vma->vm_start + i * PAGE_2M_SIZE, PAGE_2M_SIZE, vma->vm_flags,
vma->vm_ops, &new_vma);
// 防止内存泄露
if (unlikely(ret == -EEXIST))
free_pages(Phy_to_2M_Page(pa), 1);
else
mm_map_vma(new_vma, pa, 0, PAGE_2M_SIZE);
memcpy((void *)phys_2_virt(pa), (void *)(vma->vm_start + i * PAGE_2M_SIZE),
(vma_size >= PAGE_2M_SIZE) ? PAGE_2M_SIZE : vma_size);
vma_size -= PAGE_2M_SIZE;
}
}
else
{
uint64_t map_size = PAGE_4K_ALIGN(vma_size);
uint64_t va = (uint64_t)kmalloc(map_size, 0);
struct vm_area_struct *new_vma = NULL;
int ret = mm_create_vma(new_mms, vma->vm_start, map_size, vma->vm_flags, vma->vm_ops, &new_vma);
// 防止内存泄露
if (unlikely(ret == -EEXIST))
kfree((void *)va);
else
mm_map_vma(new_vma, virt_2_phys(va), 0, map_size);
memcpy((void *)va, (void *)vma->vm_start, vma_size);
}
vma = vma->vm_next;
}
return retval;
}
/** /**
* @brief * @brief
* *
@ -1059,106 +784,6 @@ uint64_t process_exit_mm(struct process_control_block *pcb)
return 0; return 0;
} }
/**
* @brief rbp地址
*
* @param new_regs reg
* @param new_pcb pcb
* @return int
*/
static int process_rewrite_rbp(struct pt_regs *new_regs, struct process_control_block *new_pcb)
{
uint64_t new_top = ((uint64_t)new_pcb) + STACK_SIZE;
uint64_t old_top = (uint64_t)(current_pcb) + STACK_SIZE;
uint64_t *rbp = &new_regs->rbp;
uint64_t *tmp = rbp;
// 超出内核栈范围
if ((uint64_t)*rbp >= old_top || (uint64_t)*rbp < (old_top - STACK_SIZE))
return 0;
while (1)
{
// 计算delta
uint64_t delta = old_top - *rbp;
// 计算新的rbp值
uint64_t newVal = new_top - delta;
// 新的值不合法
if (unlikely((uint64_t)newVal >= new_top || (uint64_t)newVal < (new_top - STACK_SIZE)))
break;
// 将新的值写入对应位置
*rbp = newVal;
// 跳转栈帧
rbp = (uint64_t *)*rbp;
}
// 设置内核态fork返回到enter_syscall_int()函数内的时候rsp寄存器的值
new_regs->rsp = new_top - (old_top - new_regs->rsp);
return 0;
}
/**
* @brief 线
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start,
uint64_t stack_size, struct pt_regs *current_regs)
{
// 将线程结构体放置在pcb后方
struct thread_struct *thd = (struct thread_struct *)(pcb + 1);
memset(thd, 0, sizeof(struct thread_struct));
pcb->thread = thd;
struct pt_regs *child_regs = NULL;
// 拷贝栈空间
if (pcb->flags & PF_KFORK) // 内核态下的fork
{
// 内核态下则拷贝整个内核栈
uint32_t size = ((uint64_t)current_pcb) + STACK_SIZE - (uint64_t)(current_regs);
child_regs = (struct pt_regs *)(((uint64_t)pcb) + STACK_SIZE - size);
memcpy(child_regs, (void *)current_regs, size);
barrier();
// 然后重写新的栈中每个栈帧的rbp值
process_rewrite_rbp(child_regs, pcb);
}
else
{
child_regs = (struct pt_regs *)((uint64_t)pcb + STACK_SIZE - sizeof(struct pt_regs));
memcpy(child_regs, current_regs, sizeof(struct pt_regs));
barrier();
child_regs->rsp = stack_start;
}
// 设置子进程的返回值为0
child_regs->rax = 0;
if (pcb->flags & PF_KFORK)
thd->rbp =
(uint64_t)(child_regs + 1); // 设置新的内核线程开始执行时的rbp也就是进入ret_from_system_call时的rbp
else
thd->rbp = (uint64_t)pcb + STACK_SIZE;
// 设置新的内核线程开始执行的时候的rsp
thd->rsp = (uint64_t)child_regs;
thd->fs = current_pcb->thread->fs;
thd->gs = current_pcb->thread->gs;
// 根据是否为内核线程、是否在内核态fork设置进程的开始执行的地址
if (pcb->flags & PF_KFORK)
thd->rip = (uint64_t)ret_from_system_call;
else if (pcb->flags & PF_KTHREAD && (!(pcb->flags & PF_KFORK)))
thd->rip = (uint64_t)kernel_thread_func;
else
thd->rip = (uint64_t)ret_from_system_call;
return 0;
}
/** /**
* @brief todo: 线 * @brief todo: 线

View File

@ -22,14 +22,8 @@
#include "proc-types.h" #include "proc-types.h"
// 设置初始进程的PCB extern void process_exit_thread(struct process_control_block *pcb);
#define INITIAL_PROC(proc) \ extern uint64_t process_exit_files(struct process_control_block *pcb);
{ \
.state = PROC_UNINTERRUPTIBLE, .flags = PF_KTHREAD, .preempt_count = 0, .signal = 0, .cpu_id = 0, \
.mm = &initial_mm, .thread = &initial_thread, .addr_limit = 0xffffffffffffffff, .pid = 0, .priority = 2, \
.virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .prev_pcb = &proc, .parent_pcb = &proc, .exit_code = 0, \
.wait_child_proc_exit = 0, .worker_private = NULL, .policy = SCHED_NORMAL \
}
/** /**
* @brief * @brief
@ -96,7 +90,7 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
/** /**
* @brief pid获取进程的pcbpcb时pcb的指针NULL * @brief pid获取进程的pcbpcb时pcb的指针NULL
* * pcblist_lock之后
* @param pid * @param pid
* @return struct process_control_block* * @return struct process_control_block*
*/ */
@ -106,6 +100,8 @@ struct process_control_block *process_find_pcb_by_pid(pid_t pid);
* @brief * @brief
* *
* @param pcb pcb * @param pcb pcb
*
* @return 1,0.pcb为NULL-EINVAL
*/ */
int process_wakeup(struct process_control_block *pcb); int process_wakeup(struct process_control_block *pcb);
@ -197,3 +193,30 @@ extern struct process_control_block *initial_proc[MAX_CPU_NUM];
* @param pcb_name char数组 * @param pcb_name char数组
*/ */
void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_name); void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_name);
/**
* @brief
*
* hint: rust中实现rust版本的注释
*
* @param pcb pcb
* @return true
* @return false
*/
extern bool process_is_stopped(struct process_control_block *pcb);
/**
* @brief
* If (@_state & @pcb->state) @pcb->state = TASK_RUNNING.
*
* hint: rust中实现rust版本的注释
*/
extern int process_try_to_wake_up(struct process_control_block *_pcb, uint64_t _state, int32_t _wake_flags);
/** @brief 当进程,满足 (@state & @pcb->state)时,唤醒进程,并设置: @pcb->state = TASK_RUNNING.
*
* hint: rust中实现rust版本的注释
* @return true
* @return false
*/
extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state);

View File

@ -0,0 +1,103 @@
use core::ptr::{read_volatile, write_volatile};
use crate::{
arch::x86_64::asm::current::current_pcb,
include::bindings::bindings::{
process_control_block, sched_enqueue, PROC_RUNNING, PROC_STOPPED,
},
sched::core::cpu_executing,
smp::core::{smp_get_processor_id, smp_send_reschedule},
};
use super::preempt::{preempt_disable, preempt_enable};
/// 判断进程是否已经停止
#[no_mangle]
pub extern "C" fn process_is_stopped(pcb: *const process_control_block) -> bool {
let state: u64 = unsafe { read_volatile(&(*pcb).state) } as u64;
if (state & (PROC_STOPPED as u64)) != 0 {
return true;
} else {
return false;
}
}
/// @brief 尝试唤醒指定的进程。
/// 本函数的行为If (@_state & @pcb->state) @pcb->state = TASK_RUNNING.
///
/// @param _pcb 要被唤醒的进程的pcb
/// @param _state 如果pcb的state与_state匹配则唤醒这个进程
/// @param _wake_flags 保留暂未使用请置为0
/// @return true: 成功唤醒
/// false: 不符合唤醒条件,无法唤醒
#[no_mangle]
pub extern "C" fn process_try_to_wake_up(
_pcb: *mut process_control_block,
_state: u64,
_wake_flags: i32,
) -> bool {
preempt_disable();
let mut retval = false;
// 获取对pcb的可变引用
let pcb = unsafe { _pcb.as_mut() }.unwrap();
// 如果要唤醒的就是当前的进程
if current_pcb() as *mut process_control_block as usize == _pcb as usize {
unsafe {
write_volatile(&mut pcb.state, PROC_RUNNING as u64);
}
preempt_enable();
retval = true;
return retval;
}
// todo: 将来调度器引入ttwu队列之后需要修改这里的判断条件
// todo: 为pcb引入pi_lock,然后在这里加锁
if unsafe { read_volatile(&pcb.state) } & _state != 0 {
// 可以wakeup
unsafe {
write_volatile(&mut pcb.state, PROC_RUNNING as u64);
sched_enqueue(pcb);
}
retval = true;
}
// todo: 对pcb的pi_lock放锁
preempt_enable();
return retval;
}
/// @brief 当进程,满足 (@state & @pcb->state)时,唤醒进程,并设置: @pcb->state = TASK_RUNNING.
///
/// @return true 唤醒成功
/// @return false 唤醒失败
#[no_mangle]
pub extern "C" fn process_wake_up_state(pcb: *mut process_control_block, state: u64) -> bool {
return process_try_to_wake_up(pcb, state, 0);
}
/// @brief 让一个正在cpu上运行的进程陷入内核
pub fn process_kick(pcb: *mut process_control_block) {
preempt_disable();
let cpu = process_cpu(pcb);
// 如果给定的进程正在别的核心上执行,则立即发送请求,让它陷入内核态,以及时响应信号。
if cpu != smp_get_processor_id() && process_is_executing(pcb) {
smp_send_reschedule(cpu);
}
preempt_enable();
}
/// @brief 获取给定的进程在哪个cpu核心上运行(使用volatile避免编译器优化)
#[inline]
pub fn process_cpu(pcb: *const process_control_block) -> u32 {
unsafe { read_volatile(&(*pcb).cpu_id) }
}
/// @brief 判断给定的进程是否正在处理器上执行
///
/// @param pcb 进程的pcb
#[inline]
pub fn process_is_executing(pcb: *const process_control_block) -> bool {
return cpu_executing(process_cpu(pcb)) == pcb;
}

13
kernel/src/sched/core.rs Normal file
View File

@ -0,0 +1,13 @@
use crate::{include::bindings::bindings::process_control_block, process::process::process_cpu, arch::x86_64::asm::current::current_pcb};
/// @brief 获取指定的cpu上正在执行的进程的pcb
#[inline]
pub fn cpu_executing(cpu_id:u32) -> *const process_control_block{
// todo: 引入per_cpu之后该函数真正执行“返回指定的cpu上正在执行的pcb”的功能
if cpu_id == process_cpu(current_pcb()){
return current_pcb();
}else {
todo!()
}
}

1
kernel/src/sched/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod core;

View File

@ -4,6 +4,7 @@
#include <driver/video/video.h> #include <driver/video/video.h>
#include <sched/cfs.h> #include <sched/cfs.h>
#include <common/string.h> #include <common/string.h>
/** /**
* @brief * @brief
* *

14
kernel/src/smp/core.rs Normal file
View File

@ -0,0 +1,14 @@
/// @brief 获取当前的cpu id
#[inline]
pub fn smp_get_processor_id() -> u32 {
if cfg!(x86_64) {
return crate::arch::x86_64::cpu::arch_current_apic_id() as u32;
} else {
255
}
}
#[inline]
pub fn smp_send_reschedule(_cpu: u32) {
// todo:
}

1
kernel/src/smp/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod core;

View File

@ -1,6 +1,7 @@
#include "syscall.h" #include "syscall.h"
#include <common/errno.h> #include <common/errno.h>
#include <common/fcntl.h> #include <common/fcntl.h>
#include <common/kthread.h>
#include <common/string.h> #include <common/string.h>
#include <driver/disk/ahci/ahci.h> #include <driver/disk/ahci/ahci.h>
#include <exception/gate.h> #include <exception/gate.h>
@ -10,7 +11,6 @@
#include <mm/slab.h> #include <mm/slab.h>
#include <process/process.h> #include <process/process.h>
#include <time/sleep.h> #include <time/sleep.h>
#include <common/kthread.h>
// 导出系统调用入口函数定义在entry.S中 // 导出系统调用入口函数定义在entry.S中
extern void system_call(void); extern void system_call(void);
extern void syscall_int(void); extern void syscall_int(void);
@ -19,6 +19,7 @@ extern uint64_t sys_clock(struct pt_regs *regs);
extern uint64_t sys_mstat(struct pt_regs *regs); extern uint64_t sys_mstat(struct pt_regs *regs);
extern uint64_t sys_open(struct pt_regs *regs); extern uint64_t sys_open(struct pt_regs *regs);
extern uint64_t sys_unlink_at(struct pt_regs *regs); extern uint64_t sys_unlink_at(struct pt_regs *regs);
extern uint64_t sys_kill(struct pt_regs *regs);
/** /**
* @brief * @brief
@ -518,7 +519,7 @@ uint64_t sys_wait4(struct pt_regs *regs)
// 查找pid为指定值的进程 // 查找pid为指定值的进程
// ps: 这里判断子进程的方法没有按照posix 2008来写。 // ps: 这里判断子进程的方法没有按照posix 2008来写。
// todo: 根据进程树判断是否为当前进程的子进程 // todo: 根据进程树判断是否为当前进程的子进程
// todo: 当进程管理模块拥有pcblist_lock之后调用之前应当对其加锁
child_proc = process_find_pcb_by_pid(pid); child_proc = process_find_pcb_by_pid(pid);
if (child_proc == NULL) if (child_proc == NULL)
@ -598,7 +599,7 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = {
[20] = sys_pipe, [20] = sys_pipe,
[21] = sys_mstat, [21] = sys_mstat,
[22] = sys_unlink_at, [22] = sys_unlink_at,
[23 ... 254] = system_call_not_exists, [23] = sys_kill,
[24 ... 254] = system_call_not_exists,
[255] = sys_ahci_end_req, [255] = sys_ahci_end_req,
}; };

View File

@ -34,5 +34,6 @@
#define SYS_MSTAT 21 // 获取系统的内存状态信息 #define SYS_MSTAT 21 // 获取系统的内存状态信息
#define SYS_UNLINK_AT 22 // 删除文件夹/删除文件链接 #define SYS_UNLINK_AT 22 // 删除文件夹/删除文件链接
#define SYS_KILL 23 // kill一个进程(向这个进程发出信号)
#define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用 #define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用

View File

@ -4,6 +4,7 @@
#include <libc/dirent.h> #include <libc/dirent.h>
#include <libc/errno.h> #include <libc/errno.h>
#include <libc/fcntl.h> #include <libc/fcntl.h>
#include <libc/include/signal.h>
#include <libc/stddef.h> #include <libc/stddef.h>
#include <libc/stdio.h> #include <libc/stdio.h>
#include <libc/stdlib.h> #include <libc/stdlib.h>
@ -23,7 +24,7 @@ struct built_in_cmd_t shell_cmds[] = {
{"cd", shell_cmd_cd}, {"cat", shell_cmd_cat}, {"exec", shell_cmd_exec}, {"ls", shell_cmd_ls}, {"cd", shell_cmd_cd}, {"cat", shell_cmd_cat}, {"exec", shell_cmd_exec}, {"ls", shell_cmd_ls},
{"mkdir", shell_cmd_mkdir}, {"pwd", shell_cmd_pwd}, {"rm", shell_cmd_rm}, {"rmdir", shell_cmd_rmdir}, {"mkdir", shell_cmd_mkdir}, {"pwd", shell_cmd_pwd}, {"rm", shell_cmd_rm}, {"rmdir", shell_cmd_rmdir},
{"reboot", shell_cmd_reboot}, {"touch", shell_cmd_touch}, {"about", shell_cmd_about}, {"free", shell_cmd_free}, {"reboot", shell_cmd_reboot}, {"touch", shell_cmd_touch}, {"about", shell_cmd_about}, {"free", shell_cmd_free},
{"help", shell_help}, {"pipe", shell_pipe_test}, {"help", shell_help}, {"pipe", shell_pipe_test}, {"kill", shell_cmd_kill},
}; };
// 总共的内建命令数量 // 总共的内建命令数量
@ -331,11 +332,14 @@ int shell_cmd_touch(int argc, char **argv)
{ {
int path_len = 0; int path_len = 0;
char *file_path; char *file_path;
bool alloc_full_path=false; bool alloc_full_path = false;
if (argv[1][0] == '/') if (argv[1][0] == '/')
file_path = argv[1]; file_path = argv[1];
else else
{file_path = get_target_filepath(argv[1], &path_len);alloc_full_path=true;} {
file_path = get_target_filepath(argv[1], &path_len);
alloc_full_path = true;
}
// 打开文件 // 打开文件
int fd = open(file_path, O_CREAT); int fd = open(file_path, O_CREAT);
@ -351,7 +355,7 @@ int shell_cmd_touch(int argc, char **argv)
close(fd); close(fd);
if (argv != NULL) if (argv != NULL)
free(argv); free(argv);
if(alloc_full_path) if (alloc_full_path)
free(file_path); free(file_path);
return 0; return 0;
} }
@ -498,7 +502,24 @@ int shell_cmd_about(int argc, char **argv)
parse_command(input_buffer, &aac, &aav); parse_command(input_buffer, &aac, &aav);
shell_cmd_exec(aac, aav); return shell_cmd_exec(aac, aav);
}
int shell_cmd_kill(int argc, char **argv)
{
int retval = 0;
if (argc < 2)
{
printf("Usage: Kill <pid>\n");
retval = -EINVAL;
goto out;
}
printf("argc = %d, argv[1]=%s\n", argc, argv[1]);
printf("atoi(argv[1])=%d\n", atoi(argv[1]));
retval = syscall_invoke(SYS_KILL, atoi(argv[1]), SIGKILL, 0, 0, 0, 0, 0, 0);
out:;
free(argv);
return retval;
} }
/** /**

View File

@ -150,3 +150,5 @@ int shell_cmd_free(int argc, char **argv);
* @return int * @return int
*/ */
int parse_command(char *buf, int *argc, char ***argv); int parse_command(char *buf, int *argc, char ***argv);
int shell_cmd_kill(int argc, char **argv);

View File

@ -0,0 +1,40 @@
#pragma once
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
#define SIGPWR 30
#define SIGSYS 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX MAX_SIG_NUM

View File

@ -28,6 +28,7 @@
#define SYS_MSTAT 21 // 获取系统的内存状态信息 #define SYS_MSTAT 21 // 获取系统的内存状态信息
#define SYS_UNLINK_AT 22 // 删除文件夹/删除文件链接 #define SYS_UNLINK_AT 22 // 删除文件夹/删除文件链接
#define SYS_KILL 23 // kill一个进程(向这个进程发出信号)
/** /**
* @brief * @brief