Merge remote-tracking branch 'origin/dev' into mipsel

toolchain_update
Yuhao Zhou 6 years ago
commit c1d139598c

@ -8,7 +8,7 @@ Going to be the next generation teaching operating system.
Supported architectures: x86_64, RISCV32/64, AArch64, MIPS32
Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+, Kendryte K210 and FPGA running Rocket Chip
Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+, Kendryte K210 and FPGA running Rocket Chip / [TrivialMIPS](https://github.com/Harry-Chen/TrivialMIPS)
![demo](./docs/2_OSLab/os2atc/demo.png)
@ -50,9 +50,9 @@ $ make run arch=x86_64 mode=release pci_passthru=0000:00:00.1 # for ixgbe real n
| Module | Maintainer |
|--------|-----------------------|
| x86_64 | @wangrunji0408 |
| RISCV | @jiegec |
| RISC-V | @jiegec |
| ARM (Raspi3) | @equation314 |
| MIPS | @HarryChen @miskcoo |
| MIPS | @Harry_Chen @miskcoo |
| Memory, Process, File System | @wangrunji0408 |
| Network with drivers | @jiegec |
| GUI | @equation314 |

2
kernel/Cargo.lock generated

@ -411,7 +411,7 @@ dependencies = [
[[package]]
name = "rcore-thread"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-thread#fd972c7e3aa2b7618f625f143655c16adfd2ca78"
source = "git+https://github.com/rcore-os/rcore-thread#77e8e0778154734ee59525e043caab6339e14d75"
dependencies = [
"deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",

@ -23,7 +23,7 @@ impl PageTable for ActivePageTable {
let frame = Frame::of_addr(PhysAddr::new(target));
// we may need frame allocator to alloc frame for new page table(first/second)
self.get_table()
.map_to(page, frame, flags, &mut FrameAllocatorForRiscv)
.map_to(page, frame, flags, &mut FrameAllocatorForMips)
.unwrap()
.flush();
self.get_entry(addr).expect("fail to get entry")
@ -254,15 +254,15 @@ impl Drop for InactivePageTable0 {
}
}
struct FrameAllocatorForRiscv;
struct FrameAllocatorForMips;
impl FrameAllocator for FrameAllocatorForRiscv {
impl FrameAllocator for FrameAllocatorForMips {
fn alloc(&mut self) -> Option<Frame> {
alloc_frame().map(|addr| Frame::of_addr(PhysAddr::new(addr)))
}
}
impl FrameDeallocator for FrameAllocatorForRiscv {
impl FrameDeallocator for FrameAllocatorForMips {
fn dealloc(&mut self, frame: Frame) {
dealloc_frame(frame.start_address().as_usize());
}

@ -100,6 +100,13 @@
compatible = "xlnx,xps-intc-1.00.a";
reg = <0x61200000 0x1000>;
interrupt-parent = <&L10>;
interrupts = <0>;
};
router: router@64A00000 {
compatible = "rcore,router";
reg = <0x64A00000 0x1000>;
interrupt-parent = <&L10>;
interrupts = <1>;
};
};

@ -1,19 +1,22 @@
use super::consts::KERNEL_OFFSET;
use crate::memory::active_table;
use rcore_memory::paging::PageTable;
/// Mask all external interrupt except serial.
pub unsafe fn init_external_interrupt() {
const HART0_S_MODE_INTERRUPT_ENABLES: *mut u64 = (KERNEL_OFFSET + 0x0C00_2080) as *mut u64;
// enable all external interrupts
HART0_S_MODE_INTERRUPT_ENABLES.write_volatile(0xf);
// mask interrupts first
const AXI_INTC_IER: *mut u32 = (KERNEL_OFFSET + 0x1900_0008) as *mut u32;
const AXI_INTC_IER: *mut u32 = (KERNEL_OFFSET + 0x1810_0008) as *mut u32;
AXI_INTC_IER.write_volatile(0x0);
// acknowledge all interrupts
const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1900_000C) as *mut u32;
const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1810_000C) as *mut u32;
AXI_INTC_IAR.write_volatile(0xffffffff);
const AXI_INTC_MER: *mut u32 = (KERNEL_OFFSET + 0x1900_001C) as *mut u32;
const AXI_INTC_MER: *mut u32 = (KERNEL_OFFSET + 0x1810_001C) as *mut u32;
// Hardware Interrupt enable | Enable irq output
AXI_INTC_MER.write_volatile(0b11);
@ -32,7 +35,7 @@ pub unsafe fn handle_external_interrupt() {
HART0_S_MODE_INTERRUPT_CLAIM_COMPLETE.write_volatile(source);
// acknowledge all interrupts
const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1900_000C) as *mut u32;
const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1810_000C) as *mut u32;
AXI_INTC_IAR.write_volatile(0xffffffff);
}

@ -154,12 +154,21 @@ fn remap_the_kernel(dtb: usize) {
// map AXI INTC for Rocket Chip
#[cfg(feature = "board_rocket_chip")]
ms.push(
KERNEL_OFFSET + 0x19000000,
KERNEL_OFFSET + 0x19000000 + PAGE_SIZE,
KERNEL_OFFSET + 0x18100000,
KERNEL_OFFSET + 0x18100000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(-(KERNEL_OFFSET as isize + 0x19000000 - 0x61200000)),
Linear::new(-(KERNEL_OFFSET as isize + 0x18100000 - 0x61200000)),
"axi_intc",
);
// map AXI4-Stream Data FIFO for Rocket Chip
#[cfg(feature = "board_rocket_chip")]
ms.push(
KERNEL_OFFSET + 0x18200000,
KERNEL_OFFSET + 0x18200000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(-(KERNEL_OFFSET as isize + 0x18200000 - 0x64A00000)),
"router",
);
unsafe {
ms.activate();
}

@ -4,6 +4,7 @@ use core::slice;
use device_tree::{DeviceTree, Node};
use super::bus::virtio_mmio::virtio_probe;
use super::net::router::router_init;
use super::CMDLINE;
const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed;
@ -14,6 +15,9 @@ fn walk_dt_node(dt: &Node) {
if compatible == "virtio,mmio" {
virtio_probe(dt);
}
if compatible == "rcore,router" {
router_init();
}
// TODO: initial other devices (16650, etc.)
}
if let Ok(bootargs) = dt.prop_str("bootargs") {

@ -1,3 +1,4 @@
pub mod e1000;
pub mod ixgbe;
pub mod router;
pub mod virtio_net;

@ -0,0 +1,229 @@
//! rCore Router Driver
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use smoltcp::iface::*;
use smoltcp::phy::{self, DeviceCapabilities};
use smoltcp::time::Instant;
use smoltcp::wire::*;
use smoltcp::Result;
use rcore_memory::PAGE_SIZE;
use crate::drivers::provider::Provider;
use crate::net::SOCKETS;
use crate::sync::SpinNoIrqLock as Mutex;
use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY};
use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
const AXI_STREAM_FIFO_ISR: *mut u32 = (KERNEL_OFFSET + 0x1820_0000) as *mut u32;
const AXI_STREAM_FIFO_IER: *mut u32 = (KERNEL_OFFSET + 0x1820_0004) as *mut u32;
const AXI_STREAM_FIFO_TDFR: *mut u32 = (KERNEL_OFFSET + 0x1820_0008) as *mut u32;
const AXI_STREAM_FIFO_TDFD: *mut u32 = (KERNEL_OFFSET + 0x1820_0010) as *mut u32;
const AXI_STREAM_FIFO_TLR: *mut u32 = (KERNEL_OFFSET + 0x1820_0014) as *mut u32;
const AXI_STREAM_FIFO_RDFR: *mut u32 = (KERNEL_OFFSET + 0x1820_0018) as *mut u32;
const AXI_STREAM_FIFO_RDFO: *mut u32 = (KERNEL_OFFSET + 0x1820_001C) as *mut u32;
const AXI_STREAM_FIFO_RDFD: *mut u32 = (KERNEL_OFFSET + 0x1820_0020) as *mut u32;
const AXI_STREAM_FIFO_RLR: *mut u32 = (KERNEL_OFFSET + 0x1820_0024) as *mut u32;
const AXI_STREAM_FIFO_TDR: *mut u32 = (KERNEL_OFFSET + 0x1820_002C) as *mut u32;
const AXI_STREAM_FIFO_RDR: *mut u32 = (KERNEL_OFFSET + 0x1820_0030) as *mut u32;
pub struct Router {
buffer: Vec<Vec<u8>>,
}
impl Router {
fn transmit_available(&self) -> bool {
true
}
fn receive_available(&self) -> bool {
self.buffer.len() > 0
}
}
#[derive(Clone)]
pub struct RouterDriver(Arc<Mutex<Router>>);
pub struct RouterRxToken(RouterDriver);
pub struct RouterTxToken(RouterDriver);
impl<'a> phy::Device<'a> for RouterDriver {
type RxToken = RouterRxToken;
type TxToken = RouterTxToken;
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
let driver = self.0.lock();
if driver.transmit_available() && driver.receive_available() {
// potential racing
Some((RouterRxToken(self.clone()), RouterTxToken(self.clone())))
} else {
None
}
}
fn transmit(&'a mut self) -> Option<Self::TxToken> {
let driver = self.0.lock();
if driver.transmit_available() {
Some(RouterTxToken(self.clone()))
} else {
None
}
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = 1536;
caps.max_burst_size = Some(1);
caps
}
}
impl phy::RxToken for RouterRxToken {
fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
where
F: FnOnce(&[u8]) -> Result<R>,
{
let mut router = (self.0).0.lock();
let buffer = router.buffer.pop().unwrap();
f(&buffer)
}
}
impl phy::TxToken for RouterTxToken {
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
where
F: FnOnce(&mut [u8]) -> Result<R>,
{
let mut buffer = vec![0; len];
let res = f(&mut buffer);
debug!("out buf {}", len);
unsafe {
AXI_STREAM_FIFO_TDR.write_volatile(2);
for byte in buffer {
AXI_STREAM_FIFO_TDFD.write_volatile(byte as u32);
}
AXI_STREAM_FIFO_TLR.write((len * 4) as u32);
}
res
}
}
pub struct RouterInterface {
iface: Mutex<EthernetInterface<'static, 'static, 'static, RouterDriver>>,
driver: RouterDriver,
}
impl Driver for RouterInterface {
fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool {
let mut driver = self.driver.0.lock();
let isr = unsafe { AXI_STREAM_FIFO_ISR.read_volatile() };
if isr > 0 {
debug!("handle router interrupt {:b}", isr);
unsafe {
AXI_STREAM_FIFO_ISR.write(isr);
let rdfo = AXI_STREAM_FIFO_RDFO.read_volatile();
if rdfo > 0 {
let mut buffer = Vec::new();
let rlr = AXI_STREAM_FIFO_RLR.read_volatile();
let rdr = AXI_STREAM_FIFO_RDR.read_volatile();
for i in 0..rdfo {
buffer.push(AXI_STREAM_FIFO_RDFD.read_volatile() as u8);
}
debug!("got packet of length {}", rdfo);
driver.buffer.push(buffer);
}
drop(driver);
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
let mut sockets = SOCKETS.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(_) => {
SOCKET_ACTIVITY.notify_all();
}
Err(err) => {
debug!("poll got err {}", err);
}
}
}
return true;
}
return false;
}
fn device_type(&self) -> DeviceType {
DeviceType::Net
}
fn get_id(&self) -> String {
format!("router")
}
fn get_mac(&self) -> EthernetAddress {
unimplemented!()
}
fn get_ifname(&self) -> String {
format!("router")
}
fn ipv4_address(&self) -> Option<Ipv4Address> {
unimplemented!()
}
fn poll(&self) {
unimplemented!()
}
}
pub fn router_init() -> Arc<RouterInterface> {
unsafe {
// reset tx fifo
AXI_STREAM_FIFO_TDFR.write_volatile(0xA5);
// reset rx fifo
AXI_STREAM_FIFO_RDFR.write_volatile(0xA5);
}
let ethernet_addr = EthernetAddress::from_bytes(&[2, 2, 3, 3, 0, 0]);
let net_driver = RouterDriver(Arc::new(Mutex::new(Router { buffer: Vec::new() })));
let ip_addrs = [
IpCidr::new(IpAddress::v4(10, 0, 0, 1), 24),
IpCidr::new(IpAddress::v4(10, 0, 1, 1), 24),
];
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let routes = Routes::new(BTreeMap::new());
let iface = EthernetInterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr)
.ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache)
.routes(routes)
.finalize();
info!("router interface up");
let router_iface = RouterInterface {
iface: Mutex::new(iface),
driver: net_driver,
};
let driver = Arc::new(router_iface);
DRIVERS.write().push(driver.clone());
NET_DRIVERS.write().push(driver.clone());
const AXI_STREAM_FIFO_IER: *mut u32 = (KERNEL_OFFSET + 0x1820_0004) as *mut u32;
// Enable Receive Complete Interrupt
unsafe {
AXI_STREAM_FIFO_IER.write_volatile(1 << 26);
}
driver
}

@ -45,13 +45,25 @@ impl Pipe {
)
}
pub fn can_read(&self) -> bool {
fn can_read(&self) -> bool {
if let PipeEnd::Read = self.direction {
self.data.lock().buf.len() > 0
self.data.lock().buf.len() > 0 || self.is_broken()
} else {
false
}
}
fn can_write(&self) -> bool {
if let PipeEnd::Write = self.direction {
!self.is_broken()
} else {
false
}
}
fn is_broken(&self) -> bool {
Arc::strong_count(&self.data) < 2
}
}
// TODO: better way to provide default impl?
@ -105,39 +117,11 @@ impl INode for Pipe {
}
fn poll(&self) -> Result<PollStatus> {
let data = self.data.lock();
match self.direction {
PipeEnd::Read => {
if data.buf.len() > 0 {
Ok(PollStatus {
read: true,
write: false,
error: false,
})
} else {
Ok(PollStatus {
read: false,
write: false,
error: false,
})
}
}
PipeEnd::Write => {
if data.buf.len() > 0 {
Ok(PollStatus {
read: false,
write: true,
error: false,
})
} else {
Ok(PollStatus {
read: false,
write: false,
error: false,
})
}
}
}
Ok(PollStatus {
read: self.can_read(),
write: self.can_write(),
error: false,
})
}
impl_inode!();
}

@ -3,6 +3,7 @@ use core::fmt;
use lazy_static::lazy_static;
use log::{self, Level, LevelFilter, Log, Metadata, Record};
use crate::processor;
use crate::sync::SpinNoIrqLock as Mutex;
use crate::util::color::ConsoleColor;
@ -63,12 +64,17 @@ impl Log for SimpleLogger {
true
}
fn log(&self, record: &Record) {
static DISABLED_TARGET: &[&str] = &[];
if self.enabled(record.metadata()) && !DISABLED_TARGET.contains(&record.target()) {
// let target = record.target();
// let begin = target.as_bytes().iter().rposition(|&c| c == b':').map(|i| i + 1).unwrap_or(0);
if !self.enabled(record.metadata()) {
return;
}
if let Some(tid) = processor().tid_option() {
print_in_color(
format_args!("[{:>5}][{}] {}\n", record.level(), tid, record.args()),
ConsoleColor::from(record.level()),
);
} else {
print_in_color(
format_args!("[{:>5}] {}\n", record.level(), record.args()),
format_args!("[{:>5}][-] {}\n", record.level(), record.args()),
ConsoleColor::from(record.level()),
);
}

@ -16,7 +16,7 @@ use super::HEAP_ALLOCATOR;
pub use crate::arch::paging::*;
use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::process::current_thread;
use crate::sync::SpinNoIrqLock;
use crate::sync::{SpinNoIrqLock, MutexGuard, SpinNoIrq};
use alloc::boxed::Box;
use bitmap_allocator::BitAlloc;
use buddy_system_allocator::Heap;
@ -52,24 +52,19 @@ pub type FrameAlloc = bitmap_allocator::BitAlloc4K;
lazy_static! {
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> =
SpinNoIrqLock::new(FrameAlloc::default());
pub static ref ACTIVE_TABLE: SpinNoIrqLock<ActivePageTable> =
SpinNoIrqLock::new(unsafe { ActivePageTable::new() });
}
/// The only way to get active page table
/// The only way to get current active page table safely
///
/// ## CHANGE LOG
///
/// In the past, this function returns a `MutexGuard` of a global
/// `Mutex<ActiveTable>` object, which means only one CPU core
/// can access its active table at a time.
///
/// But given that a page table is ** process local **, and being active
/// when and only when a thread of the process is running.
/// The ownership of this page table is in the `MemorySet` object.
/// So it's safe to access the active table inside `MemorySet`.
/// But the shared parts is readonly, e.g. all pages mapped in
/// `InactivePageTable::map_kernel()`.
pub fn active_table() -> ActivePageTable {
unsafe { ActivePageTable::new() }
/// NOTE:
/// Current implementation of recursive page table has a problem that
/// will cause race condition to the initial page table.
/// So we have to add a global mutex to avoid the racing.
/// This will be removed after replacing recursive mapping by linear mapping.
pub fn active_table() -> MutexGuard<'static, ActivePageTable, SpinNoIrq> {
ACTIVE_TABLE.lock()
}
#[derive(Debug, Clone, Copy)]

@ -22,6 +22,7 @@ use crate::sync::{Condvar, SpinNoIrqLock as Mutex};
use super::abi::{self, ProcInitInfo};
use core::mem::uninitialized;
use rcore_fs::vfs::INode;
use crate::processor;
pub struct Thread {
context: Context,
@ -66,7 +67,7 @@ pub struct Process {
// relationship
pub pid: Pid, // i.e. tgid, usually the tid of first thread
pub parent: Option<Arc<Mutex<Process>>>,
pub parent: Weak<Mutex<Process>>,
pub children: Vec<Weak<Mutex<Process>>>,
pub threads: Vec<Tid>, // threads in the same process
@ -125,7 +126,7 @@ impl Thread {
exec_path: String::new(),
futexes: BTreeMap::default(),
pid: Pid(0),
parent: None,
parent: Weak::new(),
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
@ -303,7 +304,7 @@ impl Thread {
exec_path: String::from(exec_path),
futexes: BTreeMap::default(),
pid: Pid(0),
parent: None,
parent: Weak::new(),
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
@ -329,7 +330,7 @@ impl Thread {
exec_path: proc.exec_path.clone(),
futexes: BTreeMap::default(),
pid: Pid(0),
parent: Some(self.proc.clone()),
parent: Arc::downgrade(&self.proc),
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
@ -403,6 +404,20 @@ 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) {
// quit all threads
for tid in self.threads.iter() {
processor().manager().exit(*tid, 1);
}
// notify parent and fill exit code
if let Some(parent) = self.parent.upgrade() {
let mut parent = parent.lock();
parent.child_exit_code.insert(self.pid.get(), exit_code);
parent.child_exit.notify_one();
}
}
}
trait ToMemoryAttr {

@ -28,6 +28,7 @@
use super::Condvar;
use crate::arch::interrupt;
use crate::processor;
use core::cell::UnsafeCell;
use core::fmt;
use core::ops::{Deref, DerefMut};
@ -35,11 +36,12 @@ use core::sync::atomic::{AtomicBool, Ordering};
pub type SpinLock<T> = Mutex<T, Spin>;
pub type SpinNoIrqLock<T> = Mutex<T, SpinNoIrq>;
pub type ThreadLock<T> = Mutex<T, Condvar>;
pub type SleepLock<T> = Mutex<T, Condvar>;
pub struct Mutex<T: ?Sized, S: MutexSupport> {
lock: AtomicBool,
support: S,
user: UnsafeCell<(usize, usize)>, // (cid, tid)
data: UnsafeCell<T>,
}
@ -78,6 +80,7 @@ impl<T, S: MutexSupport> Mutex<T, S> {
lock: AtomicBool::new(false),
data: UnsafeCell::new(user_data),
support: S::new(),
user: UnsafeCell::new((0, 0)),
}
}
@ -93,11 +96,23 @@ impl<T, S: MutexSupport> Mutex<T, S> {
impl<T: ?Sized, S: MutexSupport> Mutex<T, S> {
fn obtain_lock(&self) {
while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false {
let mut try_count = 0;
// Wait until the lock looks unlocked before retrying
while self.lock.load(Ordering::Relaxed) {
self.support.cpu_relax();
try_count += 1;
if try_count == 0x100000 {
let (cid, tid) = unsafe { *self.user.get() };
error!(
"Mutex: deadlock detected! locked by cpu {} thread {} @ {:?}",
cid, tid, self as *const Self
);
}
}
}
let cid = crate::arch::cpu::id();
let tid = processor().tid_option().unwrap_or(0);
unsafe { self.user.get().write((cid, tid)) };
}
/// Locks the spinlock and returns a guard.

@ -3,7 +3,7 @@
//! The code is borrowed from [RustDoc - Dining Philosophers](https://doc.rust-lang.org/1.6.0/book/dining-philosophers.html)
use crate::sync::Condvar;
use crate::sync::ThreadLock as Mutex;
use crate::sync::SleepLock as Mutex;
use crate::thread;
use alloc::vec;
use alloc::{sync::Arc, vec::Vec};

@ -141,6 +141,9 @@ impl Syscall<'_> {
return Ok(0);
}
// NOTE: To run rustc, uncomment yield_now and comment Condvar.
// Waking up from pipe is unimplemented now.
// thread::yield_now();
Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]);
}
}
@ -524,7 +527,7 @@ impl Syscall<'_> {
arg3: usize,
) -> SysResult {
info!(
"ioctl: fd: {}, request: {:x}, args: {} {} {}",
"ioctl: fd: {}, request: {:#x}, args: {:#x} {:#x} {:#x}",
fd, request, arg1, arg2, arg3
);
let mut proc = self.process();
@ -1416,6 +1419,7 @@ impl IoVecs {
}
#[repr(C)]
#[derive(Debug)]
pub struct PollFd {
fd: u32,
events: PollEvents,

@ -69,10 +69,9 @@ impl Syscall<'_> {
val,
timeout
);
// if op & OP_PRIVATE == 0 {
// unimplemented!("futex only support process-private");
// return Err(SysError::ENOSYS);
// }
if op & OP_PRIVATE == 0 {
warn!("process-shared futex is unimplemented");
}
if uaddr % size_of::<u32>() != 0 {
return Err(SysError::EINVAL);
}
@ -80,7 +79,7 @@ impl Syscall<'_> {
const OP_WAIT: u32 = 0;
const OP_WAKE: u32 = 1;
const OP_PRIVATE: u32 = 128;
const OP_PRIVATE: u32 = 0x80;
let mut proc = self.process();
let queue = proc.get_futex(uaddr);

@ -54,7 +54,6 @@ impl Syscall<'_> {
let new_thread = self
.thread
.clone(self.tf, newsp, newtls, child_tid as usize);
// FIXME: parent pid
let tid = processor().manager().add(new_thread);
processor().manager().detach(tid);
info!("clone: {} -> {}", thread::current().id(), tid);
@ -66,7 +65,7 @@ impl Syscall<'_> {
/// Wait for the process exit.
/// Return the PID. Store exit code to `wstatus` if it's not null.
pub fn sys_wait4(&mut self, pid: isize, wstatus: *mut i32) -> SysResult {
//info!("wait4: pid: {}, code: {:?}", pid, wstatus);
info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let wstatus = if !wstatus.is_null() {
Some(unsafe { self.vm().check_write_ptr(wstatus)? })
} else {
@ -75,10 +74,12 @@ impl Syscall<'_> {
#[derive(Debug)]
enum WaitFor {
AnyChild,
AnyChildInGroup,
Pid(usize),
}
let target = match pid {
-1 | 0 => WaitFor::AnyChild,
-1 => WaitFor::AnyChild,
0 => WaitFor::AnyChildInGroup,
p if p > 0 => WaitFor::Pid(p as usize),
_ => unimplemented!(),
};
@ -86,7 +87,7 @@ impl Syscall<'_> {
let mut proc = self.process();
// check child_exit_code
let find = match target {
WaitFor::AnyChild => proc
WaitFor::AnyChild | WaitFor::AnyChildInGroup => proc
.child_exit_code
.iter()
.next()
@ -102,17 +103,19 @@ impl Syscall<'_> {
return Ok(pid);
}
// if not, check pid
let children: Vec<_> = proc
.children
.iter()
.filter_map(|weak| weak.upgrade())
.collect();
let invalid = match target {
WaitFor::AnyChild => children.len() == 0,
WaitFor::Pid(pid) => children
let invalid = {
let children: Vec<_> = proc
.children
.iter()
.find(|p| p.lock().pid.get() == pid)
.is_none(),
.filter_map(|weak| weak.upgrade())
.collect();
match target {
WaitFor::AnyChild | WaitFor::AnyChildInGroup => children.len() == 0,
WaitFor::Pid(pid) => children
.iter()
.find(|p| p.lock().pid.get() == pid)
.is_none(),
}
};
if invalid {
return Err(SysError::ECHILD);
@ -204,7 +207,7 @@ impl Syscall<'_> {
/// Kill the process
pub fn sys_kill(&mut self, pid: usize, sig: usize) -> SysResult {
info!(
"kill: {} killed: {} with sig {}",
"kill: thread {} kill process {} with signal {}",
thread::current().id(),
pid,
sig
@ -215,21 +218,8 @@ impl Syscall<'_> {
self.sys_exit_group(sig);
} else {
if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) {
let proc = proc_arc.lock();
// quit all threads
for tid in proc.threads.iter() {
processor().manager().exit(*tid, sig);
}
// notify parent and fill exit code
// avoid deadlock
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, sig);
parent.child_exit.notify_one();
}
let mut proc = proc_arc.lock();
proc.exit(sig);
Ok(0)
} else {
Err(SysError::EINVAL)
@ -252,7 +242,7 @@ impl Syscall<'_> {
/// Get the parent process id
pub fn sys_getppid(&mut self) -> SysResult {
if let Some(parent) = self.process().parent.as_ref() {
if let Some(parent) = self.process().parent.upgrade() {
Ok(parent.lock().pid.get())
} else {
Ok(0)
@ -266,26 +256,15 @@ impl Syscall<'_> {
let mut proc = self.process();
proc.threads.retain(|&id| id != tid);
// for last thread,
// notify parent and fill exit code
// avoid deadlock
let exit = proc.threads.len() == 0;
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if exit {
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, exit_code);
parent.child_exit.notify_one();
}
// for last thread, exit the process
if proc.threads.len() == 0 {
proc.exit(exit_code);
}
// perform futex wake 1
// ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html
// FIXME: do it in all possible ways a thread can exit
// it has memory access so we can't move it to Thread::drop?
let mut proc = self.process();
let clear_child_tid = self.thread.clear_child_tid as *mut u32;
if !clear_child_tid.is_null() {
info!("exit: futex {:#?} wake 1", clear_child_tid);
@ -304,24 +283,10 @@ impl Syscall<'_> {
/// Exit the current thread group (i.e. process)
pub fn sys_exit_group(&mut self, exit_code: usize) -> ! {
let proc = self.process();
let mut proc = self.process();
info!("exit_group: {}, code: {}", proc.pid, exit_code);
// quit all threads
for tid in proc.threads.iter() {
processor().manager().exit(*tid, exit_code);
}
// notify parent and fill exit code
// avoid deadlock
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, exit_code);
parent.child_exit.notify_one();
}
proc.exit(exit_code);
processor().yield_now();
unreachable!();

@ -1 +1 @@
Subproject commit 9fb1d459b50bc14c7ac56d9fd94b4b8485620730
Subproject commit ad822e6d3b626b598874bb52a407e90f549c5ab9
Loading…
Cancel
Save