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 {
|
||||
physical_start: physical_address,
|
||||
virtual_start: NonNull::new(phys_to_virt(physical_address) as *mut T)
|
||||
.unwrap(),
|
||||
virtual_start: NonNull::new(phys_to_virt(physical_address) as *mut T).unwrap(),
|
||||
region_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 drivers;
|
||||
pub mod fs;
|
||||
pub mod ipc;
|
||||
pub mod lang;
|
||||
pub mod lkm;
|
||||
pub mod memory;
|
||||
|
@ -14,6 +14,7 @@ use xmas_elf::{
|
||||
|
||||
use crate::arch::interrupt::{Context, TrapFrame};
|
||||
use crate::fs::{FileHandle, FileLike, OpenOptions, FOLLOW_MAX_DEPTH};
|
||||
use crate::ipc::SemProc;
|
||||
use crate::memory::{
|
||||
ByFrame, Delay, File, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet, Read,
|
||||
};
|
||||
@ -64,6 +65,7 @@ pub struct Process {
|
||||
pub cwd: String,
|
||||
pub exec_path: String,
|
||||
futexes: BTreeMap<usize, Arc<Condvar>>,
|
||||
pub semaphores: SemProc,
|
||||
|
||||
// relationship
|
||||
pub pid: Pid, // i.e. tgid, usually the tid of first thread
|
||||
@ -124,6 +126,7 @@ impl Thread {
|
||||
files: BTreeMap::default(),
|
||||
cwd: String::from("/"),
|
||||
exec_path: String::new(),
|
||||
semaphores: SemProc::default(),
|
||||
futexes: BTreeMap::default(),
|
||||
pid: Pid(0),
|
||||
parent: Weak::new(),
|
||||
@ -308,6 +311,7 @@ impl Thread {
|
||||
cwd: String::from("/"),
|
||||
exec_path: String::from(exec_path),
|
||||
futexes: BTreeMap::default(),
|
||||
semaphores: SemProc::default(),
|
||||
pid: Pid(0),
|
||||
parent: Weak::new(),
|
||||
children: Vec::new(),
|
||||
@ -334,6 +338,7 @@ impl Thread {
|
||||
cwd: proc.cwd.clone(),
|
||||
exec_path: proc.exec_path.clone(),
|
||||
futexes: BTreeMap::default(),
|
||||
semaphores: proc.semaphores.clone(),
|
||||
pid: Pid(0),
|
||||
parent: Arc::downgrade(&self.proc),
|
||||
children: Vec::new(),
|
||||
@ -409,6 +414,7 @@ impl Process {
|
||||
}
|
||||
self.futexes.get(&uaddr).unwrap().clone()
|
||||
}
|
||||
|
||||
/// Exit the process.
|
||||
/// Kill all threads and notify parent with the exit code.
|
||||
pub fn exit(&mut self, exit_code: usize) {
|
||||
|
@ -61,6 +61,42 @@ impl Semaphore {
|
||||
self.acquire();
|
||||
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> {
|
||||
|
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::fs::*;
|
||||
pub use self::ipc::*;
|
||||
pub use self::lkm::*;
|
||||
pub use self::mem::*;
|
||||
pub use self::misc::*;
|
||||
@ -27,6 +28,7 @@ pub use self::time::*;
|
||||
|
||||
mod custom;
|
||||
mod fs;
|
||||
mod ipc;
|
||||
mod lkm;
|
||||
mod mem;
|
||||
mod misc;
|
||||
@ -259,6 +261,14 @@ impl Syscall<'_> {
|
||||
}
|
||||
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
|
||||
SYS_GETPID => self.sys_getpid(),
|
||||
SYS_GETTID => self.sys_gettid(),
|
||||
@ -398,6 +408,12 @@ impl Syscall<'_> {
|
||||
}
|
||||
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,
|
||||
};
|
||||
Some(ret)
|
||||
|
@ -277,6 +277,7 @@ impl Syscall<'_> {
|
||||
queue.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
drop(proc);
|
||||
|
||||
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