Skip to content

Commit

Permalink
Merge pull request #156 from yunwei37/master
Browse files Browse the repository at this point in the history
Add semaphores syscalls
  • Loading branch information
wangrunji0408 committed Aug 18, 2020
2 parents 2f34c8c + a90a629 commit bdd4c31
Show file tree
Hide file tree
Showing 20 changed files with 922 additions and 135 deletions.
5 changes: 5 additions & 0 deletions linux-loader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,9 @@ mod tests {
async fn test_random() {
assert_eq!(test("/bin/testrandom").await, 0);
}

#[async_std::test]
async fn test_sem() {
assert_eq!(test("/bin/testsem1").await, 0);
}
}
3 changes: 3 additions & 0 deletions linux-object/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub enum LxError {
ENOTEMPTY = 39,
/// Too many symbolic links encountered
ELOOP = 40,
/// Identifier removed
EIDRM = 43,
/// Socket operation on non-socket
ENOTSOCK = 88,
/// Protocol not available
Expand Down Expand Up @@ -158,6 +160,7 @@ impl fmt::Display for LxError {
ENOSYS => "Function not implemented",
ENOTEMPTY => "Directory not empty",
ELOOP => "Too many symbolic links encountered",
EIDRM => "Identifier removed",
ENOTSOCK => "Socket operation on non-socket",
ENOPROTOOPT => "Protocol not available",
EPFNOSUPPORT => "Protocol family not supported",
Expand Down
82 changes: 82 additions & 0 deletions linux-object/src/ipc/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//! Linux Inter-Process Communication
#![deny(missing_docs)]
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
}

/// Remove an `array` by ID
pub fn remove(&mut self, id: SemId) {
self.arrays.remove(&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).cloned()
}

/// 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)"),
}
}
}
}
167 changes: 167 additions & 0 deletions linux-object/src/ipc/semary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//! Linux semaphore ipc
use crate::error::LxError;
use crate::sync::Semaphore;
use crate::time::*;
use alloc::{collections::BTreeMap, sync::Arc, sync::Weak, vec::Vec};
use bitflags::*;
use core::ops::Index;
use lazy_static::*;
use spin::Mutex;
use spin::RwLock;

bitflags! {
struct SemGetFlag: usize {
const CREAT = 1 << 9;
const EXCLUSIVE = 1 << 10;
const NO_WAIT = 1 << 11;
}
}

/// structure specifies the access permissions on the semaphore set
///
/// struct ipc_perm
#[repr(C)]
#[derive(Clone, Copy)]
pub struct IpcPerm {
/// Key supplied to semget(2)
pub key: u32,
/// Effective UID of owner
pub uid: u32,
/// Effective GID of owner
pub gid: u32,
/// Effective UID of creator
pub cuid: u32,
/// Effective GID of creator
pub cgid: u32,
/// Permissions
pub mode: u32,
/// Sequence number
pub __seq: u32,
/// pad1
pub __pad1: usize,
/// pad2
pub __pad2: usize,
}

/// semid data structure
///
/// struct semid_ds
#[repr(C)]
#[derive(Clone, Copy)]
pub struct SemidDs {
/// Ownership and permissions
pub perm: IpcPerm,
/// Last semop time
pub otime: usize,
__pad1: usize,
/// Last change time
pub ctime: usize,
__pad2: usize,
/// number of semaphores in set
pub nsems: usize,
}

/// A System V semaphore set
pub struct SemArray {
/// semid data structure
pub semid_ds: Mutex<SemidDs>,
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<u32, Weak<SemArray>>> = RwLock::new(BTreeMap::new());
}

impl SemArray {
/// remove semaphores
pub fn remove(&self) {
let mut key2sem = KEY2SEM.write();
let key = self.semid_ds.lock().perm.key;
key2sem.remove(&key);
for sem in self.sems.iter() {
sem.remove();
}
}

/// set last semop time
pub fn otime(&self) {
self.semid_ds.lock().otime = TimeSpec::now().sec;
}

/// set last change time
pub fn ctime(&self) {
self.semid_ds.lock().ctime = TimeSpec::now().sec;
}

/// for IPC_SET
/// see man semctl(2)
pub fn set(&self, new: &SemidDs) {
let mut lock = self.semid_ds.lock();
lock.perm.uid = new.perm.uid;
lock.perm.gid = new.perm.gid;
lock.perm.mode = new.perm.mode & 0x1ff;
}

/// Get the semaphore array with `key`.
/// If not exist, create a new one with `nsems` elements.
pub fn get_or_create(mut key: u32, nsems: usize, flags: usize) -> Result<Arc<Self>, LxError> {
let mut key2sem = KEY2SEM.write();
let flag = SemGetFlag::from_bits_truncate(flags);

if key == 0 {
// IPC_PRIVATE
// find an empty key slot
key = (1u32..).find(|i| key2sem.get(i).is_none()).unwrap();
} else {
// check existence
if let Some(weak_array) = key2sem.get(&key) {
if let Some(array) = weak_array.upgrade() {
if flag.contains(SemGetFlag::CREAT) && flag.contains(SemGetFlag::EXCLUSIVE) {
// exclusive
return Err(LxError::EEXIST);
}
return Ok(array);
}
}
}

// not found, create one
let mut semaphores = Vec::new();
for _ in 0..nsems {
semaphores.push(Semaphore::new(0));
}

// insert to global map
let array = Arc::new(SemArray {
semid_ds: Mutex::new(SemidDs {
perm: IpcPerm {
key,
uid: 0,
gid: 0,
cuid: 0,
cgid: 0,
// least significant 9 bits
mode: (flags as u32) & 0x1ff,
__seq: 0,
__pad1: 0,
__pad2: 0,
},
otime: 0,
ctime: TimeSpec::now().sec,
nsems,
__pad1: 0,
__pad2: 0,
}),
sems: semaphores,
});
key2sem.insert(key, Arc::downgrade(&array));
Ok(array)
}
}
4 changes: 3 additions & 1 deletion linux-object/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Linux kernel objects

#![no_std]
#![deny(warnings, unsafe_code)]
#![deny(warnings, unsafe_code, missing_docs)]
#![feature(bool_to_option)]

extern crate alloc;
Expand All @@ -16,8 +16,10 @@ pub mod error;
pub mod fs;

// layer 2
pub mod ipc;
pub mod loader;
pub mod process;
pub mod signal;
pub mod sync;
pub mod thread;
pub mod time;
23 changes: 23 additions & 0 deletions linux-object/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::error::*;
use crate::fs::*;
use crate::ipc::*;
use crate::signal::{Signal as LinuxSignal, SignalAction};
use alloc::vec::Vec;
use alloc::{
Expand Down Expand Up @@ -149,6 +150,8 @@ struct LinuxProcessInner {
file_limit: RLimit,
/// Opened files
files: HashMap<FileDesc, Arc<dyn FileLike>>,
/// Semaphore
semaphores: SemProc,
/// Futexes
futexes: HashMap<VirtAddr, Arc<Futex>>,
/// Child processes
Expand Down Expand Up @@ -361,6 +364,26 @@ impl LinuxProcess {
pub fn set_signal_action(&self, signal: LinuxSignal, action: SignalAction) {
self.inner.lock().signal_actions.table[signal as u8 as usize] = action;
}

/// Insert a `SemArray` and return its ID
pub fn semaphores_add(&self, array: Arc<SemArray>) -> usize {
self.inner.lock().semaphores.add(array)
}

/// Get an semaphore set by `id`
pub fn semaphores_get(&self, id: usize) -> Option<Arc<SemArray>> {
self.inner.lock().semaphores.get(id)
}

/// Add an undo operation
pub fn semaphores_add_undo(&self, id: usize, num: u16, op: i16) {
self.inner.lock().semaphores.add_undo(id, num, op)
}

/// Remove an `SemArray` by ID
pub fn semaphores_remove(&self, id: usize) {
self.inner.lock().semaphores.remove(id)
}
}

impl LinuxProcessInner {
Expand Down
5 changes: 3 additions & 2 deletions linux-object/src/signal/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ pub const SIG_ERR: usize = usize::max_value() - 1;
pub const SIG_DFL: usize = 0;
pub const SIG_IGN: usize = 1;

// yet there's a bug because of mismatching bits: https://sourceware.org/bugzilla/show_bug.cgi?id=25657
// just support 64bits size sigset
/// Linux struct sigset_t
///
/// yet there's a bug because of mismatching bits: https://sourceware.org/bugzilla/show_bug.cgi?id=25657
/// just support 64bits size sigset
#[derive(Default, Clone, Copy, Debug)]
#[repr(C)]
pub struct Sigset(u64);
Expand Down
13 changes: 10 additions & 3 deletions linux-object/src/signal/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Linux signals
#![allow(missing_docs)]
use bitflags::*;
use numeric_enum_macro::numeric_enum;

Expand Down Expand Up @@ -125,6 +127,7 @@ impl Signal {
}

/// See musl struct __ucontext
///
/// Not exactly the same for now
#[repr(C)]
#[derive(Clone)]
Expand All @@ -139,10 +142,14 @@ pub struct SignalUserContext {
#[repr(C)]
#[derive(Clone)]
pub struct SignalFrame {
pub ret_code_addr: usize, // point to ret_code
/// point to ret_code
pub ret_code_addr: usize,
/// Signal Frame info
pub info: SigInfo,
pub ucontext: SignalUserContext, // adapt interface, a little bit waste
pub ret_code: [u8; 7], // call sys_sigreturn
/// adapt interface, a little bit waste
pub ucontext: SignalUserContext,
/// call sys_sigreturn
pub ret_code: [u8; 7],
}

bitflags! {
Expand Down
2 changes: 1 addition & 1 deletion linux-object/src/sync/event_bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ bitflags! {

/// Semaphore: is removed
const SEMAPHORE_REMOVED = 1 << 20;
/// Semaphore: can acquired
/// Semaphore: can acquired a resource of this semaphore
const SEMAPHORE_CAN_ACQUIRE = 1 << 21;
}
}
Expand Down

0 comments on commit bdd4c31

Please sign in to comment.