1
0
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:
Runji Wang 2019-10-26 16:00:07 +08:00 committed by GitHub
commit 2ec7f966cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 283 additions and 9 deletions

View File

@ -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
View 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
View 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
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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
View 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;
}
}

View File

@ -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)

View File

@ -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

@ -1 +1 @@
Subproject commit 3546cf87ee5aaefc638e6009262358fe07af8717 Subproject commit 5aae6587f635f9eabd8f4643f381aa48cf597131

2
user

@ -1 +1 @@
Subproject commit 72a9ae029e90a39a32d14758b20365557ca0bfa5 Subproject commit 3ae3a840bf39bbd6628892842688c8720273546d