diff --git a/kernel/src/arch/x86_64/acpi.rs b/kernel/src/arch/x86_64/acpi.rs index 47973685..dd10a3e6 100644 --- a/kernel/src/arch/x86_64/acpi.rs +++ b/kernel/src/arch/x86_64/acpi.rs @@ -12,8 +12,7 @@ impl AcpiHandler for Handler { ) -> PhysicalMapping { 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, } diff --git a/kernel/src/drivers/gpu/virtio_gpu.rs b/kernel/src/drivers/gpu/virtio_gpu.rs index 4f7af881..62589d99 100644 --- a/kernel/src/drivers/gpu/virtio_gpu.rs +++ b/kernel/src/drivers/gpu/virtio_gpu.rs @@ -267,11 +267,11 @@ fn setup_framebuffer(driver: &mut VirtIOGpu) { HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(size as usize, PAGE_SIZE).unwrap()) } as usize; // test framebuffer -// mandelbrot( -// driver.rect.width, -// driver.rect.height, -// frame_buffer as *mut u32, -// ); + // mandelbrot( + // driver.rect.width, + // driver.rect.height, + // frame_buffer as *mut u32, + // ); driver.frame_buffer = frame_buffer; let request_resource_attach_backing = unsafe { &mut *(driver.queue_buffer[VIRTIO_BUFFER_TRANSMIT] as *mut VirtIOGpuResourceAttachBacking) diff --git a/kernel/src/ipc/mod.rs b/kernel/src/ipc/mod.rs new file mode 100644 index 00000000..879a0d9c --- /dev/null +++ b/kernel/src/ipc/mod.rs @@ -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>, + /// 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) -> 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> { + 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)"), + } + } + } +} diff --git a/kernel/src/ipc/semary.rs b/kernel/src/ipc/semary.rs new file mode 100644 index 00000000..b54511af --- /dev/null +++ b/kernel/src/ipc/semary.rs @@ -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, +} + +impl Index for SemArray { + type Output = Semaphore; + fn index(&self, idx: usize) -> &Semaphore { + &self.sems[idx] + } +} + +lazy_static! { + static ref KEY2SEM: RwLock>> = 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 { + 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 + } +} diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 9e71ffff..994f331d 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -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; diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 5a918145..2e0eb411 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -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>, + 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) { diff --git a/kernel/src/sync/semaphore.rs b/kernel/src/sync/semaphore.rs index 0f6bef70..be7927c4 100644 --- a/kernel/src/sync/semaphore.rs +++ b/kernel/src/sync/semaphore.rs @@ -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 { + 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> { diff --git a/kernel/src/syscall/ipc.rs b/kernel/src/syscall/ipc.rs new file mode 100644 index 00000000..c9956f3b --- /dev/null +++ b/kernel/src/syscall/ipc.rs @@ -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; + } +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index bec4ff91..b07caf78 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -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) diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index fdcfcbea..a20fc4fd 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -277,6 +277,7 @@ impl Syscall<'_> { queue.notify_one(); } } + drop(proc); processor().manager().exit(tid, exit_code as usize); diff --git a/rboot b/rboot index 3546cf87..5aae6587 160000 --- a/rboot +++ b/rboot @@ -1 +1 @@ -Subproject commit 3546cf87ee5aaefc638e6009262358fe07af8717 +Subproject commit 5aae6587f635f9eabd8f4643f381aa48cf597131 diff --git a/user b/user index 72a9ae02..3ae3a840 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 72a9ae029e90a39a32d14758b20365557ca0bfa5 +Subproject commit 3ae3a840bf39bbd6628892842688c8720273546d