mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 16:16:16 +04:00
Merge pull request #23 from Loremkang/master
Basically implement System V Semaphores
This commit is contained in:
commit
2ec7f966cd
@ -12,8 +12,7 @@ impl AcpiHandler for Handler {
|
|||||||
) -> PhysicalMapping<T> {
|
) -> PhysicalMapping<T> {
|
||||||
PhysicalMapping {
|
PhysicalMapping {
|
||||||
physical_start: physical_address,
|
physical_start: physical_address,
|
||||||
virtual_start: NonNull::new(phys_to_virt(physical_address) as *mut T)
|
virtual_start: NonNull::new(phys_to_virt(physical_address) as *mut T).unwrap(),
|
||||||
.unwrap(),
|
|
||||||
region_length: size,
|
region_length: size,
|
||||||
mapped_length: size,
|
mapped_length: size,
|
||||||
}
|
}
|
||||||
|
72
kernel/src/ipc/mod.rs
Normal file
72
kernel/src/ipc/mod.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
mod semary;
|
||||||
|
|
||||||
|
pub use self::semary::*;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
/// Semaphore table in a process
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SemProc {
|
||||||
|
/// Semaphore arrays
|
||||||
|
arrays: BTreeMap<SemId, Arc<SemArray>>,
|
||||||
|
/// Undo operations when process terminates
|
||||||
|
undos: BTreeMap<(SemId, SemNum), SemOp>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Semaphore set identifier (in a process)
|
||||||
|
type SemId = usize;
|
||||||
|
|
||||||
|
/// Semaphore number (in an array)
|
||||||
|
type SemNum = u16;
|
||||||
|
|
||||||
|
/// Semaphore operation value
|
||||||
|
type SemOp = i16;
|
||||||
|
|
||||||
|
impl SemProc {
|
||||||
|
/// Insert the `array` and return its ID
|
||||||
|
pub fn add(&mut self, array: Arc<SemArray>) -> SemId {
|
||||||
|
let id = self.get_free_id();
|
||||||
|
self.arrays.insert(id, array);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
/// Get a free ID
|
||||||
|
fn get_free_id(&self) -> SemId {
|
||||||
|
(0..).find(|i| self.arrays.get(i).is_none()).unwrap()
|
||||||
|
}
|
||||||
|
/// Get an semaphore set by `id`
|
||||||
|
pub fn get(&self, id: SemId) -> Option<Arc<SemArray>> {
|
||||||
|
self.arrays.get(&id).map(|a| a.clone())
|
||||||
|
}
|
||||||
|
/// Add an undo operation
|
||||||
|
pub fn add_undo(&mut self, id: SemId, num: SemNum, op: SemOp) {
|
||||||
|
let old_val = *self.undos.get(&(id, num)).unwrap_or(&0);
|
||||||
|
let new_val = old_val - op;
|
||||||
|
self.undos.insert((id, num), new_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fork the semaphore table. Clear undo info.
|
||||||
|
impl Clone for SemProc {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
SemProc {
|
||||||
|
arrays: self.arrays.clone(),
|
||||||
|
undos: BTreeMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto perform semaphores undo on drop
|
||||||
|
impl Drop for SemProc {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
for (&(id, num), &op) in self.undos.iter() {
|
||||||
|
debug!("semundo: id: {}, num: {}, op: {}", id, num, op);
|
||||||
|
let sem_array = self.arrays[&id].clone();
|
||||||
|
let sem = &sem_array[num as usize];
|
||||||
|
match op {
|
||||||
|
1 => sem.release(),
|
||||||
|
0 => {}
|
||||||
|
_ => unimplemented!("Semaphore: semundo.(Not 1)"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
kernel/src/ipc/semary.rs
Normal file
49
kernel/src/ipc/semary.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use crate::sync::Semaphore;
|
||||||
|
use crate::sync::SpinLock as Mutex;
|
||||||
|
use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, sync::Weak, vec::Vec};
|
||||||
|
use core::ops::Index;
|
||||||
|
use spin::RwLock;
|
||||||
|
|
||||||
|
/// A System V semaphore set
|
||||||
|
pub struct SemArray {
|
||||||
|
key: usize,
|
||||||
|
sems: Vec<Semaphore>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for SemArray {
|
||||||
|
type Output = Semaphore;
|
||||||
|
fn index(&self, idx: usize) -> &Semaphore {
|
||||||
|
&self.sems[idx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref KEY2SEM: RwLock<BTreeMap<usize, Weak<SemArray>>> = RwLock::new(BTreeMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SemArray {
|
||||||
|
/// Get the semaphore array with `key`.
|
||||||
|
/// If not exist, create a new one with `nsems` elements.
|
||||||
|
pub fn get_or_create(key: usize, nsems: usize, _flags: usize) -> Arc<Self> {
|
||||||
|
let mut key2sem = KEY2SEM.write();
|
||||||
|
|
||||||
|
// found in the map
|
||||||
|
if let Some(weak_array) = key2sem.get(&key) {
|
||||||
|
if let Some(array) = weak_array.upgrade() {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// not found, create one
|
||||||
|
let mut semaphores = Vec::new();
|
||||||
|
for i in 0..nsems {
|
||||||
|
semaphores.push(Semaphore::new(0));
|
||||||
|
}
|
||||||
|
// insert to global map
|
||||||
|
let array = Arc::new(SemArray {
|
||||||
|
key,
|
||||||
|
sems: semaphores,
|
||||||
|
});
|
||||||
|
key2sem.insert(key, Arc::downgrade(&array));
|
||||||
|
array
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,7 @@ pub mod backtrace;
|
|||||||
pub mod consts;
|
pub mod consts;
|
||||||
pub mod drivers;
|
pub mod drivers;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
pub mod ipc;
|
||||||
pub mod lang;
|
pub mod lang;
|
||||||
pub mod lkm;
|
pub mod lkm;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
|
@ -14,6 +14,7 @@ use xmas_elf::{
|
|||||||
|
|
||||||
use crate::arch::interrupt::{Context, TrapFrame};
|
use crate::arch::interrupt::{Context, TrapFrame};
|
||||||
use crate::fs::{FileHandle, FileLike, OpenOptions, FOLLOW_MAX_DEPTH};
|
use crate::fs::{FileHandle, FileLike, OpenOptions, FOLLOW_MAX_DEPTH};
|
||||||
|
use crate::ipc::SemProc;
|
||||||
use crate::memory::{
|
use crate::memory::{
|
||||||
ByFrame, Delay, File, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet, Read,
|
ByFrame, Delay, File, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet, Read,
|
||||||
};
|
};
|
||||||
@ -64,6 +65,7 @@ pub struct Process {
|
|||||||
pub cwd: String,
|
pub cwd: String,
|
||||||
pub exec_path: String,
|
pub exec_path: String,
|
||||||
futexes: BTreeMap<usize, Arc<Condvar>>,
|
futexes: BTreeMap<usize, Arc<Condvar>>,
|
||||||
|
pub semaphores: SemProc,
|
||||||
|
|
||||||
// relationship
|
// relationship
|
||||||
pub pid: Pid, // i.e. tgid, usually the tid of first thread
|
pub pid: Pid, // i.e. tgid, usually the tid of first thread
|
||||||
@ -124,6 +126,7 @@ impl Thread {
|
|||||||
files: BTreeMap::default(),
|
files: BTreeMap::default(),
|
||||||
cwd: String::from("/"),
|
cwd: String::from("/"),
|
||||||
exec_path: String::new(),
|
exec_path: String::new(),
|
||||||
|
semaphores: SemProc::default(),
|
||||||
futexes: BTreeMap::default(),
|
futexes: BTreeMap::default(),
|
||||||
pid: Pid(0),
|
pid: Pid(0),
|
||||||
parent: Weak::new(),
|
parent: Weak::new(),
|
||||||
@ -308,6 +311,7 @@ impl Thread {
|
|||||||
cwd: String::from("/"),
|
cwd: String::from("/"),
|
||||||
exec_path: String::from(exec_path),
|
exec_path: String::from(exec_path),
|
||||||
futexes: BTreeMap::default(),
|
futexes: BTreeMap::default(),
|
||||||
|
semaphores: SemProc::default(),
|
||||||
pid: Pid(0),
|
pid: Pid(0),
|
||||||
parent: Weak::new(),
|
parent: Weak::new(),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
@ -334,6 +338,7 @@ impl Thread {
|
|||||||
cwd: proc.cwd.clone(),
|
cwd: proc.cwd.clone(),
|
||||||
exec_path: proc.exec_path.clone(),
|
exec_path: proc.exec_path.clone(),
|
||||||
futexes: BTreeMap::default(),
|
futexes: BTreeMap::default(),
|
||||||
|
semaphores: proc.semaphores.clone(),
|
||||||
pid: Pid(0),
|
pid: Pid(0),
|
||||||
parent: Arc::downgrade(&self.proc),
|
parent: Arc::downgrade(&self.proc),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
@ -409,6 +414,7 @@ impl Process {
|
|||||||
}
|
}
|
||||||
self.futexes.get(&uaddr).unwrap().clone()
|
self.futexes.get(&uaddr).unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exit the process.
|
/// Exit the process.
|
||||||
/// Kill all threads and notify parent with the exit code.
|
/// Kill all threads and notify parent with the exit code.
|
||||||
pub fn exit(&mut self, exit_code: usize) {
|
pub fn exit(&mut self, exit_code: usize) {
|
||||||
|
@ -61,6 +61,42 @@ impl Semaphore {
|
|||||||
self.acquire();
|
self.acquire();
|
||||||
SemaphoreGuard { sem: self }
|
SemaphoreGuard { sem: self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the current count
|
||||||
|
pub fn get(&self) -> isize {
|
||||||
|
let mut count = self.lock.lock();
|
||||||
|
*count
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the current count
|
||||||
|
pub fn set(&self, value: isize) {
|
||||||
|
let mut count = self.lock.lock();
|
||||||
|
*count = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify by k atomically. when wait is false avoid waiting. unused
|
||||||
|
pub fn modify(&self, k: isize, wait: bool) -> Result<usize, ()> {
|
||||||
|
if k > 0 {
|
||||||
|
*(self.lock.lock()) += k;
|
||||||
|
self.cvar.notify_one();
|
||||||
|
} else if k <= 0 {
|
||||||
|
let mut count = self.lock.lock();
|
||||||
|
let mut temp_k = k;
|
||||||
|
while *count + temp_k < 0 {
|
||||||
|
if wait == false {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
temp_k += *count;
|
||||||
|
*count = 0;
|
||||||
|
count = self.cvar.wait(count);
|
||||||
|
}
|
||||||
|
*count += temp_k;
|
||||||
|
if *count > 0 {
|
||||||
|
self.cvar.notify_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for SemaphoreGuard<'a> {
|
impl<'a> Drop for SemaphoreGuard<'a> {
|
||||||
|
94
kernel/src/syscall/ipc.rs
Normal file
94
kernel/src/syscall/ipc.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use crate::sync::Semaphore;
|
||||||
|
use crate::sync::SpinLock as Mutex;
|
||||||
|
use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, sync::Weak, vec::Vec};
|
||||||
|
use bitflags::*;
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
|
use spin::RwLock;
|
||||||
|
|
||||||
|
pub use crate::ipc::*;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl Syscall<'_> {
|
||||||
|
pub fn sys_semget(&self, key: usize, nsems: isize, flags: usize) -> SysResult {
|
||||||
|
info!("semget: key: {}", key);
|
||||||
|
|
||||||
|
/// The maximum semaphores per semaphore set
|
||||||
|
const SEMMSL: usize = 256;
|
||||||
|
|
||||||
|
if nsems < 0 || nsems as usize > SEMMSL {
|
||||||
|
return Err(SysError::EINVAL);
|
||||||
|
}
|
||||||
|
let nsems = nsems as usize;
|
||||||
|
|
||||||
|
let sem_array = SemArray::get_or_create(key, nsems, flags);
|
||||||
|
let id = self.process().semaphores.add(sem_array);
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_semop(&self, id: usize, ops: *const SemBuf, num_ops: usize) -> SysResult {
|
||||||
|
info!("semop: id: {}", id);
|
||||||
|
let ops = unsafe { self.vm().check_read_array(ops, num_ops)? };
|
||||||
|
|
||||||
|
let sem_array = self.process().semaphores.get(id).ok_or(SysError::EINVAL)?;
|
||||||
|
for &SemBuf { num, op, flags } in ops.iter() {
|
||||||
|
let flags = SemFlags::from_bits_truncate(flags);
|
||||||
|
if flags.contains(SemFlags::IPC_NOWAIT) {
|
||||||
|
unimplemented!("Semaphore: semop.IPC_NOWAIT");
|
||||||
|
}
|
||||||
|
let sem = &sem_array[num as usize];
|
||||||
|
|
||||||
|
let _result = match op {
|
||||||
|
1 => sem.release(),
|
||||||
|
-1 => sem.acquire(),
|
||||||
|
_ => unimplemented!("Semaphore: semop.(Not 1/-1)"),
|
||||||
|
};
|
||||||
|
if flags.contains(SemFlags::SEM_UNDO) {
|
||||||
|
self.process().semaphores.add_undo(id, num, op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_semctl(&self, id: usize, num: usize, cmd: usize, arg: isize) -> SysResult {
|
||||||
|
info!("semctl: id: {}, num: {}, cmd: {}", id, num, cmd);
|
||||||
|
let sem_array = self.process().semaphores.get(id).ok_or(SysError::EINVAL)?;
|
||||||
|
let sem = &sem_array[num as usize];
|
||||||
|
|
||||||
|
const GETVAL: usize = 12;
|
||||||
|
const GETALL: usize = 13;
|
||||||
|
const SETVAL: usize = 16;
|
||||||
|
const SETALL: usize = 17;
|
||||||
|
|
||||||
|
match cmd {
|
||||||
|
SETVAL => sem.set(arg),
|
||||||
|
_ => unimplemented!("Semaphore: Semctl.(Not setval)"),
|
||||||
|
}
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operation to be performed on a single semaphore
|
||||||
|
///
|
||||||
|
/// Ref: [http://man7.org/linux/man-pages/man2/semop.2.html]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SemBuf {
|
||||||
|
num: u16,
|
||||||
|
op: i16,
|
||||||
|
flags: i16,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub union SemctlUnion {
|
||||||
|
val: isize,
|
||||||
|
buf: usize, // semid_ds*, unimplemented
|
||||||
|
array: usize, // short*, unimplemented
|
||||||
|
} // unused
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct SemFlags: i16 {
|
||||||
|
/// For SemOP
|
||||||
|
const IPC_NOWAIT = 0x800;
|
||||||
|
/// it will be automatically undone when the process terminates.
|
||||||
|
const SEM_UNDO = 0x1000;
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ use crate::util;
|
|||||||
|
|
||||||
pub use self::custom::*;
|
pub use self::custom::*;
|
||||||
pub use self::fs::*;
|
pub use self::fs::*;
|
||||||
|
pub use self::ipc::*;
|
||||||
pub use self::lkm::*;
|
pub use self::lkm::*;
|
||||||
pub use self::mem::*;
|
pub use self::mem::*;
|
||||||
pub use self::misc::*;
|
pub use self::misc::*;
|
||||||
@ -27,6 +28,7 @@ pub use self::time::*;
|
|||||||
|
|
||||||
mod custom;
|
mod custom;
|
||||||
mod fs;
|
mod fs;
|
||||||
|
mod ipc;
|
||||||
mod lkm;
|
mod lkm;
|
||||||
mod mem;
|
mod mem;
|
||||||
mod misc;
|
mod misc;
|
||||||
@ -259,6 +261,14 @@ impl Syscall<'_> {
|
|||||||
}
|
}
|
||||||
SYS_CLOCK_GETTIME => self.sys_clock_gettime(args[0], args[1] as *mut TimeSpec),
|
SYS_CLOCK_GETTIME => self.sys_clock_gettime(args[0], args[1] as *mut TimeSpec),
|
||||||
|
|
||||||
|
// sem
|
||||||
|
#[cfg(not(target_arch = "mips"))]
|
||||||
|
SYS_SEMGET => self.sys_semget(args[0], args[1] as isize, args[2]),
|
||||||
|
#[cfg(not(target_arch = "mips"))]
|
||||||
|
SYS_SEMOP => self.sys_semop(args[0], args[1] as *const SemBuf, args[2]),
|
||||||
|
#[cfg(not(target_arch = "mips"))]
|
||||||
|
SYS_SEMCTL => self.sys_semctl(args[0], args[1], args[2], args[3] as isize),
|
||||||
|
|
||||||
// system
|
// system
|
||||||
SYS_GETPID => self.sys_getpid(),
|
SYS_GETPID => self.sys_getpid(),
|
||||||
SYS_GETTID => self.sys_gettid(),
|
SYS_GETTID => self.sys_gettid(),
|
||||||
@ -398,6 +408,12 @@ impl Syscall<'_> {
|
|||||||
}
|
}
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
SYS_IPC => match args[0] {
|
||||||
|
1 => self.sys_semop(args[1], args[2] as *const SemBuf, args[3]),
|
||||||
|
2 => self.sys_semget(args[1], args[2] as isize, args[3]),
|
||||||
|
3 => self.sys_semctl(args[1], args[2], args[3], args[4] as isize),
|
||||||
|
_ => return None,
|
||||||
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(ret)
|
Some(ret)
|
||||||
|
@ -277,6 +277,7 @@ impl Syscall<'_> {
|
|||||||
queue.notify_one();
|
queue.notify_one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(proc);
|
drop(proc);
|
||||||
|
|
||||||
processor().manager().exit(tid, exit_code as usize);
|
processor().manager().exit(tid, exit_code as usize);
|
||||||
|
2
rboot
2
rboot
@ -1 +1 @@
|
|||||||
Subproject commit 3546cf87ee5aaefc638e6009262358fe07af8717
|
Subproject commit 5aae6587f635f9eabd8f4643f381aa48cf597131
|
2
user
2
user
@ -1 +1 @@
|
|||||||
Subproject commit 72a9ae029e90a39a32d14758b20365557ca0bfa5
|
Subproject commit 3ae3a840bf39bbd6628892842688c8720273546d
|
Loading…
Reference in New Issue
Block a user