mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-11 07:40:10 +00:00
This allows us to mock the current TID for debugging purposes on hosted environments. Signed-off-by: Sean Cross <sean@xobs.io>
387 lines
13 KiB
Rust
387 lines
13 KiB
Rust
pub const MAX_THREAD: TID = 31;
|
|
use crate::services::ProcessInner;
|
|
use core::cell::RefCell;
|
|
use std::io::Write;
|
|
use std::net::TcpStream;
|
|
use std::thread_local;
|
|
use xous_kernel::{ProcessInit, ProcessKey, ThreadInit, PID, TID};
|
|
|
|
pub const INITIAL_TID: usize = 1;
|
|
pub const MAX_PROCESS_COUNT: usize = 32;
|
|
|
|
pub struct Process {
|
|
pid: PID,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct ProcessImpl {
|
|
/// Global parameters used by the operating system
|
|
pub inner: ProcessInner,
|
|
|
|
/// A 16-byte key used to register a process when it first starts
|
|
key: ProcessKey,
|
|
|
|
/// The network connection to the client process.
|
|
conn: Option<TcpStream>,
|
|
|
|
/// Memory that may need to be returned to the caller for each thread
|
|
memory_to_return: [Option<Vec<u8>>; MAX_THREAD + 1],
|
|
|
|
/// This enables the kernel to keep track of threads in the
|
|
/// target process, and know which threads are ready to
|
|
/// receive messages.
|
|
threads: [Thread; MAX_THREAD + 1],
|
|
|
|
/// The currently-active thread for this process
|
|
current_thread: TID,
|
|
}
|
|
|
|
impl PartialEq for Process {
|
|
fn eq(&self, other: &Process) -> bool {
|
|
self.pid == other.pid
|
|
}
|
|
}
|
|
|
|
struct ProcessTable {
|
|
/// The process upon which the current syscall is operating
|
|
current: PID,
|
|
|
|
/// The number of processes that exist
|
|
total: usize,
|
|
|
|
/// The actual table contents
|
|
table: Vec<Option<ProcessImpl>>,
|
|
}
|
|
|
|
thread_local!(
|
|
static PROCESS_TABLE: RefCell<ProcessTable> = RefCell::new(ProcessTable {
|
|
current: unsafe { PID::new_unchecked(1) },
|
|
total: 0,
|
|
table: Vec::new(),
|
|
})
|
|
);
|
|
|
|
pub fn current_pid() -> PID {
|
|
PROCESS_TABLE.with(|pt| pt.borrow().current)
|
|
}
|
|
|
|
pub fn set_current_pid(pid: PID) {
|
|
PROCESS_TABLE.with(|pt| {
|
|
let pid_idx = (pid.get() - 1) as usize;
|
|
let mut pt = pt.borrow_mut();
|
|
|
|
// // If the PID doesn't exist, only allow it if the table is
|
|
// // currently empty.
|
|
// for (idx, i) in pt.table.iter().enumerate() {
|
|
// println!("pt.table[{}]: {:?}", idx, i);
|
|
// }
|
|
match pt.table.get_mut(pid_idx) {
|
|
None | Some(None) => {
|
|
// if pid.get() != 1 || pt.total > 0 {
|
|
panic!("PID {} does not exist", pid);
|
|
// }
|
|
}
|
|
Some(_) => {}
|
|
}
|
|
pt.current = pid
|
|
});
|
|
}
|
|
|
|
pub fn register_connection_for_key(
|
|
conn: TcpStream,
|
|
key: ProcessKey,
|
|
) -> Result<PID, xous_kernel::Error> {
|
|
PROCESS_TABLE.with(|pt| {
|
|
let mut process_table = pt.borrow_mut();
|
|
for (pid_minus_1, process) in process_table.table.iter_mut().enumerate() {
|
|
if let Some(process) = process.as_mut() {
|
|
if process.key == key && process.conn.is_none() {
|
|
process.conn = Some(conn);
|
|
return Ok(PID::new(pid_minus_1 as u8 + 1).unwrap());
|
|
}
|
|
}
|
|
}
|
|
Err(xous_kernel::Error::ProcessNotFound)
|
|
})
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug)]
|
|
/// Everything required to keep track of a single thread of execution.
|
|
/// In a `std` environment, we can't manage threads so this is a no-op.
|
|
pub struct Thread {
|
|
allocated: bool,
|
|
}
|
|
|
|
impl Default for Thread {
|
|
fn default() -> Self {
|
|
Thread { allocated: false }
|
|
}
|
|
}
|
|
|
|
// /// Everything required to initialize a process on this platform
|
|
// pub struct ProcessInit {
|
|
// /// A network connection to the client
|
|
// conn: TcpStream,
|
|
// }
|
|
|
|
// impl ProcessInit {
|
|
// pub fn new(conn: TcpStream) -> ProcessInit {
|
|
// ProcessInit { conn }
|
|
// }
|
|
// }
|
|
|
|
impl Process {
|
|
pub fn current() -> Process {
|
|
let current_pid = PROCESS_TABLE.with(|pt| pt.borrow().current);
|
|
Process { pid: current_pid }
|
|
}
|
|
|
|
/// Mark this process as running (on the current core?!)
|
|
pub fn activate(&mut self) -> Result<(), xous_kernel::Error> {
|
|
// let mut pt = PROCESS_TABLE.lock().unwrap();
|
|
// assert!(pt.table[self.pid as usize - 1] == *self);
|
|
// pt.current = self.pid as _;
|
|
Ok(())
|
|
}
|
|
|
|
/// Calls the provided function with the current inner process state.
|
|
pub fn with_inner<F, R>(f: F) -> R
|
|
where
|
|
F: FnOnce(&ProcessInner) -> R,
|
|
{
|
|
PROCESS_TABLE.with(|pt| {
|
|
let process_table = pt.borrow();
|
|
let current = &process_table.table[process_table.current.get() as usize - 1]
|
|
.as_ref()
|
|
.unwrap();
|
|
f(¤t.inner)
|
|
})
|
|
}
|
|
|
|
pub fn with_inner_mut<F, R>(f: F) -> R
|
|
where
|
|
F: FnOnce(&mut ProcessInner) -> R,
|
|
{
|
|
PROCESS_TABLE.with(|pt| {
|
|
let mut process_table = pt.borrow_mut();
|
|
let current_pid_idx = process_table.current.get() as usize - 1;
|
|
let current = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
|
f(&mut current.inner)
|
|
})
|
|
}
|
|
|
|
/// Calls the provided function with the current inner process state.
|
|
pub fn with_current_mut<F, R>(f: F) -> R
|
|
where
|
|
F: FnOnce(&mut Process) -> R,
|
|
{
|
|
let mut process = Self::current();
|
|
f(&mut process)
|
|
}
|
|
|
|
pub fn current_tid(&self) -> TID {
|
|
1
|
|
}
|
|
|
|
fn setup_thread_inner(thread: TID, process_table: &mut ProcessTable) {
|
|
let current_pid_idx = process_table.current.get() as usize - 1;
|
|
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
|
|
|
assert!(!process.threads[thread - 1].allocated);
|
|
process.threads[thread - 1].allocated = true;
|
|
}
|
|
|
|
pub fn retry_instruction(&mut self, _tid: TID) -> Result<(), xous_kernel::Error> {
|
|
Ok(())
|
|
}
|
|
|
|
pub fn setup_process(pid: PID, setup: ThreadInit) -> Result<(), xous_kernel::Error> {
|
|
let mut tmp = Process { pid };
|
|
tmp.setup_thread(INITIAL_TID, setup)
|
|
}
|
|
|
|
pub fn setup_thread(
|
|
&mut self,
|
|
thread: TID,
|
|
_setup: ThreadInit,
|
|
) -> Result<(), xous_kernel::Error> {
|
|
// println!(
|
|
// "KERNEL({}): Setting up thread {} @ {:?}",
|
|
// self.pid,
|
|
// thread,
|
|
// std::thread::current()
|
|
// );
|
|
assert!(thread > 0);
|
|
PROCESS_TABLE.with(|pt| {
|
|
let process_table = &mut *pt.borrow_mut();
|
|
Self::setup_thread_inner(thread, process_table);
|
|
// println!(
|
|
// "KERNEL({}): self.contexts[{}].allocated = {}",
|
|
// current_pid_idx,
|
|
// context - 1,
|
|
// process.contexts[context - 1].allocated
|
|
// );
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
// pub fn current_thread(&mut self) -> TID {
|
|
// PROCESS_TABLE.with(|pt| {
|
|
// let mut process_table = pt.borrow_mut();
|
|
// let current_pid_idx = process_table.current.get() as usize - 1;
|
|
// let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
|
// process.current_context
|
|
// })
|
|
// }
|
|
|
|
/// Set the current context number.
|
|
pub fn set_thread(&mut self, thread: TID) -> Result<(), xous_kernel::Error> {
|
|
assert!(thread > 0);
|
|
PROCESS_TABLE.with(|pt| {
|
|
let mut process_table = pt.borrow_mut();
|
|
let current_pid_idx = process_table.current.get() as usize - 1;
|
|
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
|
assert!(
|
|
process.threads[thread - 1].allocated,
|
|
"tried to switch to thread {} which wasn't allocated",
|
|
thread
|
|
);
|
|
process.current_thread = thread;
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub fn find_free_thread(&self) -> Option<TID> {
|
|
PROCESS_TABLE.with(|pt| {
|
|
let mut process_table = pt.borrow_mut();
|
|
let current_pid_idx = process_table.current.get() as usize - 1;
|
|
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
|
for (index, thread) in process.threads.iter().enumerate() {
|
|
if !thread.allocated {
|
|
return Some(index as TID + 1);
|
|
}
|
|
}
|
|
None
|
|
})
|
|
}
|
|
|
|
pub fn set_thread_result(&mut self, tid: TID, result: xous_kernel::Result) {
|
|
assert!(tid > 0);
|
|
PROCESS_TABLE.with(|pt| {
|
|
let mut process_table = pt.borrow_mut();
|
|
let current_pid_idx = process_table.current.get() as usize - 1;
|
|
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
|
assert!(
|
|
process.threads[tid - 1].allocated,
|
|
"thread {} is not allocated",
|
|
tid,
|
|
);
|
|
|
|
let mut response = vec![];
|
|
// Add the destination thread ID to the start of the packet.
|
|
response.extend_from_slice(&tid.to_le_bytes());
|
|
|
|
// Append the contents of the response packet.
|
|
for word in result.to_args().iter_mut() {
|
|
response.extend_from_slice(&word.to_le_bytes());
|
|
}
|
|
|
|
// If there is memory to return for this thread, also return that.
|
|
if let Some(buf) = process.memory_to_return[tid - 1].take() {
|
|
// if let xous_kernel::Result::Message(_) = result {
|
|
// } else {
|
|
// panic!(
|
|
// "memory was waiting to be returned, but message was not a result message"
|
|
// );
|
|
// }
|
|
response.extend_from_slice(&buf);
|
|
}
|
|
|
|
// eprintln!(
|
|
// "KERNEL({}): Setting thread return value to {:?}",
|
|
// current_pid_idx + 1,
|
|
// response
|
|
// );
|
|
process
|
|
.conn
|
|
.as_mut()
|
|
.unwrap()
|
|
.write_all(&response)
|
|
.expect("Disconnection");
|
|
});
|
|
}
|
|
|
|
pub fn return_memory(&mut self, tid: TID, buf: &[u8]) {
|
|
PROCESS_TABLE.with(|pt| {
|
|
let mut process_table = pt.borrow_mut();
|
|
let current_pid_idx = process_table.current.get() as usize - 1;
|
|
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
|
assert!(process.memory_to_return[tid - 1].is_none());
|
|
process.memory_to_return[tid - 1] = Some(buf.to_vec());
|
|
});
|
|
}
|
|
|
|
/// Initialize this process with the given memory space. THIS DOES NOT
|
|
/// INITIALIZE A MAIN THREAD. You must call `setup_thread()` in order to
|
|
/// select a main thread.
|
|
pub fn create(pid: PID, init_data: ProcessInit) -> PID {
|
|
PROCESS_TABLE.with(|process_table| {
|
|
let mut process_table = process_table.borrow_mut();
|
|
let pid_idx = (pid.get() - 1) as usize;
|
|
use crate::filled_array;
|
|
let process = ProcessImpl {
|
|
inner: Default::default(),
|
|
conn: None,
|
|
key: init_data.key,
|
|
memory_to_return: filled_array![None; 32 /* MAX_THREAD */],
|
|
current_thread: INITIAL_TID,
|
|
threads: [Thread { allocated: false }; MAX_THREAD + 1],
|
|
};
|
|
|
|
process_table.total += 1;
|
|
if pid_idx >= process_table.table.len() {
|
|
process_table.table.push(Some(process));
|
|
} else if process_table.table[pid_idx].is_none() {
|
|
process_table.table[pid_idx] = Some(process);
|
|
} else {
|
|
panic!("pid already allocated!");
|
|
}
|
|
pid
|
|
})
|
|
}
|
|
|
|
pub fn destroy(pid: PID) -> Result<(), xous_kernel::Error> {
|
|
PROCESS_TABLE.with(|pt| {
|
|
let mut process_table = pt.borrow_mut();
|
|
let pid_idx = pid.get() as usize - 1;
|
|
if pid_idx >= process_table.table.len() {
|
|
panic!("attempted to destroy PID that exceeds table index: {}", pid);
|
|
}
|
|
let process = process_table.table[pid_idx].as_mut().unwrap();
|
|
process
|
|
.conn
|
|
.as_mut()
|
|
.unwrap()
|
|
.shutdown(std::net::Shutdown::Both)
|
|
.unwrap();
|
|
process_table.table[pid_idx] = None;
|
|
process_table.total -= 1;
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
pub fn send(&mut self, bytes: &[u8]) -> Result<(), xous_kernel::Error> {
|
|
// eprintln!("KERNEL: Sending syscall response: {:?}", bytes);
|
|
PROCESS_TABLE.with(|pt| {
|
|
let mut process_table = pt.borrow_mut();
|
|
let current_pid_idx = process_table.current.get() as usize - 1;
|
|
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
|
process.conn.as_mut().unwrap().write_all(bytes).unwrap();
|
|
});
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Thread {}
|