Merge branch 'multi_core' into 'master'

Multi core

See merge request redox-os/kernel!118
This commit is contained in:
Jeremy Soller
2020-04-19 20:28:15 +00:00
21 changed files with 208 additions and 67 deletions

View File

@@ -31,7 +31,7 @@ version = "0.29.0"
default-features = false
[features]
default = ["serial_debug"]
default = ["acpi", "multi_core", "serial_debug"]
acpi = []
doc = []
graphical_debug = []

View File

@@ -53,7 +53,7 @@ impl RSDP {
fn slice_to_rsdp(slice: &[u8]) -> Option<&RSDP> {
let ptr = slice.as_ptr() as usize;
if slice.len() >= mem::size_of::<RSDP>() && ptr & (!0x7) == ptr {
if slice.len() >= mem::size_of::<RSDP>() && ptr & (!0x3) == ptr {
let rsdp = unsafe { &*(slice.as_ptr() as *const RSDP) };
// TODO: Validate
Some(rsdp)

View File

@@ -47,6 +47,7 @@ unsafe fn trigger(irq: u8) {
}
irq_trigger(irq);
}
/// Unmask the IRQ. This is called from the IRQ scheme, which does this when a user process has
/// processed the IRQ.
pub unsafe fn acknowledge(irq: usize) {
@@ -55,6 +56,7 @@ pub unsafe fn acknowledge(irq: usize) {
IrqMethod::Apic => ioapic_unmask(irq),
}
}
/// Sends an end-of-interrupt, so that the interrupt controller can go on to the next one.
pub unsafe fn eoi(irq: u8) {
match irq_method() {
@@ -77,17 +79,25 @@ unsafe fn ioapic_mask(irq: u8) {
ioapic::mask(irq);
}
unsafe fn pic_eoi(irq: u8) {
debug_assert!(irq < 16);
if irq >= 8 {
pic::MASTER.ack();
if irq == 15 {
//TODO: check spurious
return;
}
pic::SLAVE.ack();
} else {
if irq == 7 {
//TODO: check spurious
return;
}
pic::MASTER.ack();
}
}
unsafe fn lapic_eoi() {
local_apic::LOCAL_APIC.eoi()
}
@@ -101,6 +111,7 @@ unsafe fn pic_unmask(irq: usize) {
pic::MASTER.mask_clear(irq as u8);
}
}
unsafe fn ioapic_unmask(irq: usize) {
ioapic::unmask(irq as u8);
}
@@ -156,67 +167,70 @@ interrupt!(com1, {
});
interrupt!(lpt2, {
eoi(5);
trigger(5);
eoi(5);
});
interrupt!(floppy, {
eoi(6);
trigger(6);
eoi(6);
});
interrupt!(lpt1, {
eoi(7);
trigger(7);
eoi(7);
});
interrupt!(rtc, {
eoi(8);
trigger(8);
eoi(8);
});
interrupt!(pci1, {
eoi(9);
trigger(9);
eoi(9);
});
interrupt!(pci2, {
eoi(10);
trigger(10);
eoi(10);
});
interrupt!(pci3, {
eoi(11);
trigger(11);
eoi(11);
});
interrupt!(mouse, {
eoi(12);
trigger(12);
eoi(12);
});
interrupt!(fpu, {
eoi(13);
trigger(13);
eoi(13);
});
interrupt!(ata1, {
eoi(14);
trigger(14);
eoi(14);
});
interrupt!(ata2, {
eoi(15);
trigger(15);
eoi(15);
});
interrupt!(lapic_timer, {
println!("Local apic timer interrupt");
lapic_eoi();
});
interrupt!(lapic_error, {
println!("Local apic internal error: ESR={:#0x}", local_apic::LOCAL_APIC.esr());
lapic_eoi();
});
interrupt!(calib_pit, {
const PIT_RATE: u64 = 2_250_286;

View File

@@ -10,7 +10,7 @@ use spin::Mutex;
use crate::arch::{macros::InterruptStack, paging::PAGE_SIZE};
use crate::common::unique::Unique;
use crate::context::arch;
use crate::context::file::FileDescriptor;
use crate::context::file::{FileDescriptor, FileDescription};
use crate::context::memory::{Grant, Memory, SharedMemory, Tls};
use crate::ipi::{ipi, IpiKind, IpiTarget};
use crate::scheme::{SchemeNamespace, FileHandle};
@@ -91,6 +91,76 @@ impl PartialEq for WaitpidKey {
impl Eq for WaitpidKey {}
pub struct ContextSnapshot {
// Copy fields
pub id: ContextId,
pub pgid: ContextId,
pub ppid: ContextId,
pub ruid: u32,
pub rgid: u32,
pub rns: SchemeNamespace,
pub euid: u32,
pub egid: u32,
pub ens: SchemeNamespace,
pub sigmask: [u64; 2],
pub umask: usize,
pub status: Status,
pub status_reason: &'static str,
pub running: bool,
pub cpu_id: Option<usize>,
pub ticks: u64,
pub syscall: Option<(usize, usize, usize, usize, usize, usize)>,
// Clone fields
//TODO: is there a faster way than allocation?
pub name: Box<[u8]>,
pub files: Vec<Option<FileDescription>>,
// pub cwd: Box<[u8]>,
}
impl ContextSnapshot {
//TODO: Should this accept &mut Context to ensure name/files will not change?
pub fn new(context: &Context) -> Self {
let name = context.name.lock().clone();
let mut files = Vec::new();
for descriptor_opt in context.files.lock().iter() {
let description = if let Some(descriptor) = descriptor_opt {
let description = descriptor.description.read();
Some(FileDescription {
namespace: description.namespace,
scheme: description.scheme,
number: description.number,
flags: description.flags,
})
} else {
None
};
files.push(description);
}
Self {
id: context.id,
pgid: context.pgid,
ppid: context.ppid,
ruid: context.ruid,
rgid: context.rgid,
rns: context.rns,
euid: context.euid,
egid: context.egid,
ens: context.ens,
sigmask: context.sigmask,
umask: context.umask,
status: context.status,
status_reason: context.status_reason,
running: context.running,
cpu_id: context.cpu_id,
ticks: context.ticks,
syscall: context.syscall,
name,
files,
}
}
}
/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
@@ -118,6 +188,7 @@ pub struct Context {
pub umask: usize,
/// Status of context
pub status: Status,
pub status_reason: &'static str,
/// Context running or not
pub running: bool,
/// CPU ID, if locked
@@ -197,6 +268,7 @@ impl Context {
sigmask: [0; 2],
umask: 0o022,
status: Status::Blocked,
status_reason: "",
running: false,
cpu_id: None,
ticks: 0,
@@ -304,9 +376,10 @@ impl Context {
}
/// Block the context, and return true if it was runnable before being blocked
pub fn block(&mut self) -> bool {
pub fn block(&mut self, reason: &'static str) -> bool {
if self.status == Status::Runnable {
self.status = Status::Blocked;
self.status_reason = reason;
true
} else {
false
@@ -317,6 +390,7 @@ impl Context {
pub fn unblock(&mut self) -> bool {
if self.status == Status::Blocked {
self.status = Status::Runnable;
self.status_reason = "";
if let Some(cpu_id) = self.cpu_id {
if cpu_id != crate::cpu_id() {

View File

@@ -3,12 +3,14 @@
use alloc::sync::Arc;
use crate::event;
use spin::RwLock;
use crate::scheme::{self, SchemeId};
use crate::scheme::{self, SchemeNamespace, SchemeId};
use crate::syscall::error::{Result, Error, EBADF};
/// A file description
#[derive(Debug)]
pub struct FileDescription {
/// The namespace the file was opened from (used for debugging)
pub namespace: SchemeNamespace,
/// The scheme that this file refers to
pub scheme: SchemeId,
/// The number the scheme uses to refer to this file

View File

@@ -6,7 +6,7 @@ use core::alloc::{GlobalAlloc, Layout};
use core::sync::atomic::Ordering;
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
pub use self::context::{Context, ContextId, Status, WaitpidKey};
pub use self::context::{Context, ContextId, ContextSnapshot, Status, WaitpidKey};
pub use self::list::ContextList;
pub use self::switch::switch;

View File

@@ -26,7 +26,7 @@ impl EventQueue {
}
pub fn read(&self, events: &mut [Event]) -> Result<usize> {
self.queue.receive_into(events, true).ok_or(Error::new(EINTR))
self.queue.receive_into(events, true, "EventQueue::read").ok_or(Error::new(EINTR))
}
pub fn write(&self, events: &[Event]) -> Result<usize> {

View File

@@ -39,7 +39,7 @@ use core::{
cmp,
sync::atomic::Ordering
};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
// ____ _
// / ___| ___ ___ ___(_) ___ _ __ ___
@@ -225,7 +225,9 @@ pub fn wait(pid: ContextId) -> Result<()> {
}
};
while !tracer.wait() {}
//TODO: proper wait_condition mutex
let m = Mutex::new(());
while !tracer.wait(m.lock(), "ptrace::wait") {}
let contexts = context::contexts();
let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
@@ -269,7 +271,9 @@ pub fn breakpoint_callback(match_flags: PtraceFlags, event: Option<PtraceEvent>)
)
};
while !tracee.wait() {}
//TODO: proper wait_condition mutex
let m = Mutex::new(());
while !tracee.wait(m.lock(), "ptrace::breakpoint_callback") {}
Some(flags)
}

View File

@@ -69,7 +69,7 @@ impl Scheme for DebugScheme {
};
INPUT.call_once(init_input)
.receive_into(buf, flags & O_NONBLOCK != O_NONBLOCK)
.receive_into(buf, flags & O_NONBLOCK != O_NONBLOCK, "DebugScheme::read")
.ok_or(Error::new(EINTR))
}

View File

@@ -180,31 +180,29 @@ impl PipeRead {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
loop {
{
let mut vec = self.vec.lock();
let mut vec = self.vec.lock();
let mut i = 0;
while i < buf.len() {
if let Some(b) = vec.pop_front() {
buf[i] = b;
i += 1;
} else {
break;
}
let mut i = 0;
while i < buf.len() {
if let Some(b) = vec.pop_front() {
buf[i] = b;
i += 1;
} else {
break;
}
}
if i > 0 {
event::trigger(self.scheme_id, self.write_id, EVENT_WRITE);
if i > 0 {
event::trigger(self.scheme_id, self.write_id, EVENT_WRITE);
return Ok(i);
}
return Ok(i);
}
if Arc::weak_count(&self.vec) == 0 {
return Ok(0);
} else if self.flags.load(Ordering::SeqCst) & O_NONBLOCK == O_NONBLOCK {
return Err(Error::new(EAGAIN));
} else if ! self.condition.wait() {
} else if ! self.condition.wait(vec, "PipeRead::read") {
return Err(Error::new(EINTR));
}
}

35
src/scheme/sys/block.rs Normal file
View File

@@ -0,0 +1,35 @@
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::Write;
use core::str;
use crate::context;
use crate::syscall::error::Result;
pub fn resource() -> Result<Vec<u8>> {
let mut string = String::new();
{
let mut rows = Vec::new();
{
let contexts = context::contexts();
for (id, context_lock) in contexts.iter() {
let context = context_lock.read();
rows.push((*id, context.name.lock().clone(), context.status_reason));
}
}
for row in rows.iter() {
let id: usize = row.0.into();
let name = str::from_utf8(&row.1).unwrap_or(".");
let _ = writeln!(string, "{}: {}", id, name);
if ! row.2.is_empty() {
let _ = writeln!(string, " {}", row.2);
}
}
}
Ok(string.into_bytes())
}

View File

@@ -10,6 +10,7 @@ use crate::syscall::error::{Error, EBADF, EINVAL, ENOENT, Result};
use crate::syscall::flag::{MODE_DIR, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET};
use crate::syscall::scheme::Scheme;
mod block;
mod context;
mod cpu;
mod exe;
@@ -40,6 +41,7 @@ impl SysScheme {
pub fn new() -> SysScheme {
let mut files: BTreeMap<&'static [u8], Box<SysFn>> = BTreeMap::new();
files.insert(b"block", Box::new(block::resource));
files.insert(b"context", Box::new(context::resource));
files.insert(b"cpu", Box::new(cpu::resource));
files.insert(b"exe", Box::new(exe::resource));

View File

@@ -97,7 +97,7 @@ impl UserInner {
self.todo.send(packet);
event::trigger(self.root_id, self.handle_id, EVENT_READ);
Error::demux(self.done.receive(&id))
Error::demux(self.done.receive(&id, "UserInner::call_inner"))
}
pub fn capture(&self, buf: &[u8]) -> Result<usize> {
@@ -202,7 +202,7 @@ impl UserInner {
// If unmounting, do not block so that EOF can be returned immediately
let unmounting = self.unmounting.load(Ordering::SeqCst);
let block = !(nonblock || unmounting);
if let Some(count) = self.todo.receive_into(packet_buf, block) {
if let Some(count) = self.todo.receive_into(packet_buf, block, "UserInner::read") {
if count > 0 {
// If we received requests, return them to the scheme handler
Ok(count * mem::size_of::<Packet>())

View File

@@ -1,6 +1,6 @@
use alloc::sync::Arc;
use alloc::vec::Vec;
use spin::{Mutex, RwLock};
use spin::{Mutex, MutexGuard, RwLock};
use crate::context::{self, Context};
@@ -36,8 +36,8 @@ impl WaitCondition {
len
}
// Wait until notified. Returns false if resumed by a signal or the notify_signal function
pub fn wait(&self) -> bool {
// Wait until notified. Unlocks guard when blocking is ready. Returns false if resumed by a signal or the notify_signal function
pub fn wait<T>(&self, guard: MutexGuard<T>, reason: &'static str) -> bool {
let id;
{
let context_lock = {
@@ -49,10 +49,12 @@ impl WaitCondition {
{
let mut context = context_lock.write();
id = context.id;
context.block();
context.block(reason);
}
self.contexts.lock().push(context_lock);
drop(guard);
}
unsafe { context::switch(); }

View File

@@ -22,13 +22,14 @@ impl<K, V> WaitMap<K, V> where K: Clone + Ord {
self.inner.lock().remove(key)
}
pub fn receive(&self, key: &K) -> V {
pub fn receive(&self, key: &K, reason: &'static str) -> V {
loop {
if let Some(value) = self.receive_nonblock(key) {
let mut inner = self.inner.lock();
if let Some(value) = inner.remove(key) {
return value;
}
//TODO: use false from wait condition to indicate EINTR
let _ = self.condition.wait();
let _ = self.condition.wait(inner, reason);
}
}
@@ -41,12 +42,15 @@ impl<K, V> WaitMap<K, V> where K: Clone + Ord {
}
}
pub fn receive_any(&self) -> (K, V) {
pub fn receive_any(&self, reason: &'static str) -> (K, V) {
loop {
if let Some(entry) = self.receive_any_nonblock() {
return entry;
let mut inner = self.inner.lock();
if let Some(key) = inner.keys().next().cloned() {
if let Some(entry) = inner.remove(&key).map(|value| (key, value)) {
return entry;
}
}
let _ = self.condition.wait();
let _ = self.condition.wait(inner, reason);
}
}

View File

@@ -28,22 +28,23 @@ impl<T> WaitQueue<T> {
self.inner.lock().is_empty()
}
pub fn receive(&self) -> Option<T> {
pub fn receive(&self, reason: &'static str) -> Option<T> {
loop {
if let Some(value) = self.inner.lock().pop_front() {
let mut inner = self.inner.lock();
if let Some(value) = inner.pop_front() {
return Some(value);
}
if ! self.condition.wait() {
if ! self.condition.wait(inner, reason) {
return None;
}
}
}
pub fn receive_into(&self, buf: &mut [T], block: bool) -> Option<usize> {
pub fn receive_into(&self, buf: &mut [T], block: bool, reason: &'static str) -> Option<usize> {
let mut i = 0;
if i < buf.len() && block {
buf[i] = self.receive()?;
buf[i] = self.receive(reason)?;
i += 1;
}

View File

@@ -22,7 +22,7 @@ impl<'a> ::core::fmt::Debug for ByteStr<'a> {
}
}
//TODO: calling format_call with arguments from another process space will not work
pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> String {
match a {
SYS_OPEN => format!(

View File

@@ -142,6 +142,7 @@ pub fn open(path: &[u8], flags: usize) -> Result<FileHandle> {
let context = context_lock.read();
return context.add_file(FileDescriptor {
description: Arc::new(RwLock::new(FileDescription {
namespace: scheme_ns,
scheme: scheme_id,
number: file_id,
flags: flags & !O_CLOEXEC,
@@ -163,6 +164,7 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> {
let read_fd = context.add_file(FileDescriptor {
description: Arc::new(RwLock::new(FileDescription {
namespace: context.ens,
scheme: scheme_id,
number: read_id,
flags: O_RDONLY | flags & !O_ACCMODE & !O_CLOEXEC,
@@ -172,6 +174,7 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> {
let write_fd = context.add_file(FileDescriptor {
description: Arc::new(RwLock::new(FileDescription {
namespace: context.ens,
scheme: scheme_id,
number: write_id,
flags: O_WRONLY | flags & !O_ACCMODE & !O_CLOEXEC,
@@ -293,6 +296,7 @@ fn duplicate_file(fd: FileHandle, buf: &[u8]) -> Result<FileDescriptor> {
Ok(FileDescriptor {
description: Arc::new(RwLock::new(FileDescription {
namespace: description.namespace,
scheme: description.scheme,
number: new_id,
flags: description.flags,

View File

@@ -66,7 +66,7 @@ pub fn futex(addr: &mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32)
context.wake = Some(end);
}
context.block();
context.block("futex");
}
futexes.push_back((addr as *mut i32 as usize, context_lock));

View File

@@ -115,9 +115,10 @@ pub fn clone(flags: CloneFlags, stack_base: usize) -> Result<ContextId> {
sigmask = context.sigmask;
umask = context.umask;
if flags.contains(CLONE_VM) {
cpu_id_opt = context.cpu_id;
}
// Uncomment to disable threads on different CPUs
// if flags.contains(CLONE_VM) {
// cpu_id_opt = context.cpu_id;
// }
arch = context.arch.clone();
@@ -355,7 +356,7 @@ pub fn clone(flags: CloneFlags, stack_base: usize) -> Result<ContextId> {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let mut context = context_lock.write();
context.block();
context.block("vfork");
vfork = true;
} else {
vfork = false;
@@ -1429,7 +1430,7 @@ pub fn sigreturn() -> Result<usize> {
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let mut context = context_lock.write();
context.ksig_restore = true;
context.block();
context.block("sigreturn");
}
let _ = unsafe { context::switch() };
@@ -1538,7 +1539,7 @@ pub fn waitpid(pid: ContextId, status_ptr: usize, flags: WaitFlags) -> Result<Co
Some(Ok(ContextId::from(0)))
}
} else {
let (_wid, (w_pid, status)) = waitpid.receive_any();
let (_wid, (w_pid, status)) = waitpid.receive_any("waitpid any");
grim_reaper(w_pid, status)
}
} else if (pid.into() as isize) < 0 {
@@ -1575,7 +1576,7 @@ pub fn waitpid(pid: ContextId, status_ptr: usize, flags: WaitFlags) -> Result<Co
let (w_pid, status) = waitpid.receive(&WaitpidKey {
pid: None,
pgid: Some(pgid)
});
}, "waitpid pgid");
grim_reaper(w_pid, status)
}
} else {
@@ -1612,7 +1613,7 @@ pub fn waitpid(pid: ContextId, status_ptr: usize, flags: WaitFlags) -> Result<Co
let (w_pid, status) = waitpid.receive(&WaitpidKey {
pid: Some(pid),
pgid: None
});
}, "waitpid pid");
grim_reaper(w_pid, status)
}
};

View File

@@ -29,7 +29,7 @@ pub fn nanosleep(req: &TimeSpec, rem_opt: Option<&mut TimeSpec>) -> Result<usize
let mut context = context_lock.write();
context.wake = Some(end);
context.block();
context.block("nanosleep");
}
unsafe { context::switch(); }