kernel: get multiple message passing working

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2020-07-15 16:09:42 +08:00
parent 0ffbaa369a
commit e652150c6e
7 changed files with 320 additions and 126 deletions

View file

@ -29,7 +29,7 @@ enum BackchannelMessage {
NewPid(PID),
}
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
thread_local!(static NETWORK_LISTEN_ADDRESS: RefCell<SocketAddr> = RefCell::new(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080)));
/// Set the network address for this particular thread.
@ -54,10 +54,10 @@ fn handle_connection(mut conn: TcpStream, pid: PID, chn: Sender<ThreadMessage>)
// If the connection has gone away, send a `TerminateProcess` message to the main
// and then exit this thread.
if e.kind() != std::io::ErrorKind::WouldBlock {
// println!(
// "KERNEL({}): Client disconnected: {}. Shutting down virtual process.",
// pid, e
// );
println!(
"KERNEL({}): Client disconnected: {} ({:?}). Shutting down virtual process.",
pid, e, e
);
chn.send(ThreadMessage::SysCall(pid, xous::SysCall::TerminateProcess))
.unwrap();
return;
@ -83,6 +83,7 @@ fn handle_connection(mut conn: TcpStream, pid: PID, chn: Sender<ThreadMessage>)
tmp_data.resize(msg.buf.len(), 0);
conn.read_exact(&mut tmp_data)
.map_err(|_e| {
println!("KERNEL({}): Read Error {}", pid, _e);
chn.send(ThreadMessage::SysCall(
pid,
xous::SysCall::TerminateProcess,
@ -216,12 +217,13 @@ pub fn idle() -> bool {
let (sender, receiver) = channel();
let (backchannel_sender, backchannel_receiver) = channel();
let listen_addr = env::var("XOUS_LISTEN_ADDR").map(|s|
s
.to_socket_addrs()
.expect("invalid server address")
.next()
.expect("unable to resolve server address"))
let listen_addr = env::var("XOUS_LISTEN_ADDR")
.map(|s| {
s.to_socket_addrs()
.expect("invalid server address")
.next()
.expect("unable to resolve server address")
})
.unwrap_or_else(|_| NETWORK_LISTEN_ADDRESS.with(|nla| *nla.borrow()));
let listen_thread_handle =
@ -230,19 +232,26 @@ pub fn idle() -> bool {
while let Ok(msg) = receiver.recv() {
match msg {
ThreadMessage::NewConnection(conn) => {
// println!("KERNEL(?): Going to call ss.spawn_process()");
// Spawn a new process inside the kernel. This will assign us a PID.
let new_pid = SystemServices::with_mut(|ss| {
ss.spawn_process(process::ProcessInit::new(conn.try_clone().unwrap()), ())
})
.unwrap();
// println!("KERNEL({}): SystemServices assigned new PID of {}", new_pid, new_pid);
// Inform the backchannel of the new process ID.
backchannel_sender
.send(BackchannelMessage::NewPid(new_pid))
.expect("couldn't send new pid to new connection");
// Switch to this process immediately, which moves it from `Setup(_)` to `Running(0)`.
// Note that in this system, multiple processes can be active at once. This is
// similar to having one core for each process. However, each process may only have
// one context running at a time.
SystemServices::with_mut(|ss| ss.switch_to(new_pid, Some(1))).unwrap();
}
ThreadMessage::SysCall(pid, call) => {
// println!("KERNEL({}): Received syscall {:?}", pid, call);
SystemServices::with_mut(|ss| ss.switch_to(pid, Some(1))).unwrap();
println!("KERNEL({}): Received syscall {:?}", pid, call);
crate::arch::process::set_current_pid(pid);
// println!("KERNEL({}): Now running as the new process", pid);
// If the call being made is to terminate the current process, we need to know
@ -271,11 +280,18 @@ pub fn idle() -> bool {
// Handle the syscall within the Xous kernel
let response = crate::syscall::handle(pid, call).unwrap_or_else(Result::Error);
// println!("KERNEL({}): Syscall response {:?}", pid, response);
println!("KERNEL({}): Syscall response {:?}", pid, response);
// There's a response if it wasn't a blocked process and we're not terminating.
// Send the response back to the target.
if response != Result::BlockedProcess && !is_terminate && !is_shutdown {
{
// The syscall may change what the current process is, but we always
// want to send a response to the process where the request came from.
// For this block, switch to the original PID, send the message, then
// switch back.
let existing_pid = crate::arch::process::current_pid();
crate::arch::process::set_current_pid(pid);
let mut process = Process::current();
let mut response_vec = Vec::new();
for word in response.to_args().iter_mut() {
@ -289,8 +305,11 @@ pub fn idle() -> bool {
// );
crate::syscall::handle(pid, SysCall::TerminateProcess).ok();
});
crate::arch::process::set_current_pid(existing_pid);
}
SystemServices::with_mut(|ss| ss.switch_from(pid, 1, true)).unwrap();
// SystemServices::with_mut(|ss| {
// println!("295: Switching from {}", pid);
// ss.switch_from(pid, 1, true)}).unwrap();
}
if is_shutdown {

View file

@ -137,7 +137,7 @@ impl Process {
}
pub fn set_context_result(&mut self, context: CtxID, result: xous::Result) {
assert!(context == INITIAL_CONTEXT);
assert!(context == INITIAL_CONTEXT, "context is {} and not {}", context, INITIAL_CONTEXT);
let mut response = vec![];
for word in result.to_args().iter_mut() {
response.extend_from_slice(&word.to_le_bytes());

View file

@ -1,6 +1,6 @@
pub use crate::arch::process::Context;
use core::mem;
use xous::{CtxID, MemoryAddress, MemoryRange, MemorySize, Message, PID, SID, pid_from_usize};
use xous::{CtxID, MemoryAddress, MemoryRange, MemorySize, Message, PID, SID};
pub struct SenderID {
pub sidx: usize,
@ -17,7 +17,6 @@ impl SenderID {
}
pub enum WaitingMessage {
/// There is no waiting message.
None,
@ -38,7 +37,8 @@ pub enum WaitingMessage {
enum QueuedMessage {
Empty,
ScalarMessage(
usize, /* sender PID/CtxID */
u16, /* sender PID */
u16, /* Sender CTX */
usize, /* sender base address */
usize, /* id */
usize, /* arg1 */
@ -47,7 +47,8 @@ enum QueuedMessage {
usize, /* arg4 */
),
MemoryMessageSend(
usize, /* sender PID/CtxID */
u16, /* sender PID */
u16, /* Sender CTX */
usize, /* reserved */
usize, /* id */
usize, /* buf */
@ -56,7 +57,8 @@ enum QueuedMessage {
usize, /* valid */
),
MemoryMessageROLend(
usize, /* sender PID/CtxID */
u16, /* sender PID */
u16, /* Sender CTX */
usize, /* sender base address */
usize, /* id */
usize, /* buf */
@ -65,7 +67,8 @@ enum QueuedMessage {
usize, /* valid */
),
MemoryMessageRWLend(
usize, /* sender PID/CtxID */
u16, /* sender PID */
u16, /* Sender CTX */
usize, /* sender base address */
usize, /* id */
usize, /* buf */
@ -77,7 +80,8 @@ enum QueuedMessage {
/// The process lending this memory terminated before
/// we could receive the message.
MemoryMessageROLendTerminated(
usize, /* sender PID/CtxID */
u16, /* sender PID */
u16, /* Sender CTX */
usize, /* sender base address */
usize, /* id */
usize, /* buf */
@ -89,7 +93,8 @@ enum QueuedMessage {
/// The process lending this memory terminated before
/// we could receive the message.
MemoryMessageRWLendTerminated(
usize, /* sender PID/CtxID */
u16, /* sender PID */
u16, /* Sender CTX */
usize, /* sender base address */
usize, /* id */
usize, /* buf */
@ -103,7 +108,8 @@ enum QueuedMessage {
/// index is returned as the message sender. This is used to unblock the
/// sending process.
WaitingResponse(
usize, /* sender PID/CtxID */
u16, /* sender PID */
u16, /* Sender CTX */
usize, /* Client base address */
usize, /* Server base address */
usize, /* Range size */
@ -112,7 +118,8 @@ enum QueuedMessage {
/// When a server goes away, its memory must be forgotten instead of being returned
/// to the previous process.
WaitingForget(
usize, /* sender PID/CtxID */
u16, /* sender PID */
u16, /* Sender CTX */
usize, /* Client base address */
usize, /* Server base address */
usize, /* Range size */
@ -143,6 +150,11 @@ pub struct Server {
ready_contexts: usize,
}
/// Convert a PID and CTX pair into a `usize` sender
fn make_sender(pid: u16, ctx: u16) -> usize {
(((pid as usize) << 16) & 0xffff_0000) | (ctx as usize & 0xffff)
}
impl Server {
/// Initialize a server in the given option array. This function is
/// designed to be called with `new` pointing to an entry in a vec.
@ -185,9 +197,7 @@ impl Server {
}
/// Take a current slot and replace it with `None`, clearing out the contents of the queue.
pub fn destroy(
current: &mut Option<Server>
) -> Result<(), xous::Error> {
pub fn destroy(current: &mut Option<Server>) -> Result<(), xous::Error> {
*current = None;
Ok(())
}
@ -208,18 +218,36 @@ impl Server {
pub fn discard_messages_for_pid(&mut self, pid: PID) {
for entry in self.queue.iter_mut() {
match entry {
&mut QueuedMessage::MemoryMessageROLend(pid_ctx, arg1, arg2, arg3, arg4, arg5, arg6) => {
if let Ok(msg_pid) = pid_from_usize(pid_ctx >> 16) {
if msg_pid == pid {
*entry = QueuedMessage::MemoryMessageROLendTerminated(pid_ctx, arg1, arg2, arg3, arg4, arg5, arg6);
}
&mut QueuedMessage::MemoryMessageROLend(
msg_pid,
ctx,
arg1,
arg2,
arg3,
arg4,
arg5,
arg6,
) => {
if msg_pid == pid.get() as _ {
*entry = QueuedMessage::MemoryMessageROLendTerminated(
msg_pid, ctx, arg1, arg2, arg3, arg4, arg5, arg6,
);
}
}
&mut QueuedMessage::MemoryMessageRWLend(pid_ctx, arg1, arg2, arg3, arg4, arg5, arg6) => {
if let Ok(msg_pid) = pid_from_usize(pid_ctx >> 16) {
if msg_pid == pid {
*entry = QueuedMessage::MemoryMessageRWLendTerminated(pid_ctx, arg1, arg2, arg3, arg4, arg5, arg6);
}
&mut QueuedMessage::MemoryMessageRWLend(
msg_pid,
ctx,
arg1,
arg2,
arg3,
arg4,
arg5,
arg6,
) => {
if msg_pid == pid.get() as _ {
*entry = QueuedMessage::MemoryMessageRWLendTerminated(
msg_pid, ctx, arg1, arg2, arg3, arg4, arg5, arg6,
);
}
}
// For "Scalar" and "Move" messages, this memory has already
@ -234,16 +262,20 @@ impl Server {
/// and return the pair. Advance the tail. Note that the `idx` could be
/// somewhere other than the tail, but as long as it points to a valid
/// message that's waiting a response, that's acceptable.
pub fn take_waiting_message(&mut self, idx: usize, buf: MemoryRange) -> Result<WaitingMessage, xous::Error> {
pub fn take_waiting_message(
&mut self,
idx: usize,
buf: MemoryRange,
) -> Result<WaitingMessage, xous::Error> {
if idx > self.queue.len() {
return Err(xous::Error::BadAddress);
}
let (pid_ctx, server_addr, client_addr, len, forget) = match self.queue[idx] {
QueuedMessage::WaitingResponse(pid_ctx, server_addr, client_addr, len) => {
(pid_ctx, server_addr, client_addr, len, false)
let (pid, ctx, server_addr, client_addr, len, forget) = match self.queue[idx] {
QueuedMessage::WaitingResponse(pid, ctx, server_addr, client_addr, len) => {
(pid, ctx, server_addr, client_addr, len, false)
}
QueuedMessage::WaitingForget(pid_ctx, server_addr, client_addr, len) => {
(pid_ctx, server_addr, client_addr, len, true)
QueuedMessage::WaitingForget(pid, ctx, server_addr, client_addr, len) => {
(pid, ctx, server_addr, client_addr, len, true)
}
_ => return Ok(WaitingMessage::None),
};
@ -257,11 +289,13 @@ impl Server {
}
// Destructure the PID and context ID from the `pid_ctx` field
let pid = pid_from_usize((pid_ctx >> 16) & 0xff)?;
let ctx = (pid_ctx & 0xffff) as CtxID;
println!("Taking waiting message -- pid: {} ctx: {}", pid, ctx);
if forget {
return Ok(WaitingMessage::ForgetMemory(MemoryRange::new(server_addr, len)));
return Ok(WaitingMessage::ForgetMemory(MemoryRange::new(
server_addr,
len,
)));
}
// If a `move` address somehow ends up here, indicate the memory has been moved.
@ -274,8 +308,8 @@ impl Server {
.expect("client memory address was 0, but server address was not");
let len = MemorySize::new(len).expect("memory length was 0, but address was not None");
Ok(WaitingMessage::BorrowedMemory(
pid,
ctx,
PID::new(pid as _).unwrap(),
ctx as _,
server_addr,
client_addr,
len,
@ -299,10 +333,11 @@ impl Server {
// );
let result = match self.queue[self.queue_tail] {
QueuedMessage::Empty => return None,
QueuedMessage::WaitingResponse(_, _, _, _) => return None,
QueuedMessage::WaitingForget(_, _, _, _) => return None,
QueuedMessage::WaitingResponse(_, _, _, _, _) => return None,
QueuedMessage::WaitingForget(_, _, _, _, _) => return None,
QueuedMessage::MemoryMessageROLend(
pid_ctx,
pid,
ctx,
client_addr,
id,
buf,
@ -319,14 +354,16 @@ impl Server {
valid: MemorySize::new(valid),
}),
},
pid_ctx,
pid,
ctx,
buf,
client_addr,
buf_size,
false,
),
QueuedMessage::MemoryMessageRWLend(
pid_ctx,
pid,
ctx,
client_addr,
id,
buf,
@ -343,14 +380,16 @@ impl Server {
valid: MemorySize::new(valid),
}),
},
pid_ctx,
pid,
ctx,
buf,
client_addr,
buf_size,
false,
),
QueuedMessage::MemoryMessageROLendTerminated(
pid_ctx,
pid,
ctx,
client_addr,
id,
buf,
@ -367,14 +406,16 @@ impl Server {
valid: MemorySize::new(valid),
}),
},
pid_ctx,
pid,
ctx,
buf,
client_addr,
buf_size,
true,
),
QueuedMessage::MemoryMessageRWLendTerminated(
pid_ctx,
pid,
ctx,
client_addr,
id,
buf,
@ -391,14 +432,16 @@ impl Server {
valid: MemorySize::new(valid),
}),
},
pid_ctx,
pid,
ctx,
buf,
client_addr,
buf_size,
true,
),
QueuedMessage::MemoryMessageSend(
pid_ctx,
pid,
ctx,
_reserved,
id,
buf,
@ -407,7 +450,7 @@ impl Server {
valid,
) => {
let msg = xous::MessageEnvelope {
sender: pid_ctx,
sender: make_sender(pid, ctx),
message: xous::Message::Move(xous::MemoryMessage {
id,
buf: MemoryRange::new(buf, buf_size),
@ -424,9 +467,9 @@ impl Server {
}
// Scalar messages have nothing to return, so they can go straight to the `Free` state
QueuedMessage::ScalarMessage(pid_ctx, _reserved, id, arg1, arg2, arg3, arg4) => {
QueuedMessage::ScalarMessage(pid, ctx, _reserved, id, arg1, arg2, arg3, arg4) => {
let msg = xous::MessageEnvelope {
sender: pid_ctx,
sender: make_sender(pid, ctx),
message: xous::Message::Scalar(xous::ScalarMessage {
id,
arg1,
@ -443,12 +486,12 @@ impl Server {
return Some(msg);
}
};
if result.5 {
if result.6 {
self.queue[self.queue_tail] =
QueuedMessage::WaitingForget(result.1, result.2, result.3, result.4);
QueuedMessage::WaitingForget(result.1, result.2, result.3, result.4, result.5);
} else {
self.queue[self.queue_tail] =
QueuedMessage::WaitingResponse(result.1, result.2, result.3, result.4);
QueuedMessage::WaitingResponse(result.1, result.2, result.3, result.4, result.5);
}
Some(result.0)
}
@ -472,7 +515,8 @@ impl Server {
self.queue[self.queue_head] = match message {
xous::Message::Scalar(msg) => QueuedMessage::ScalarMessage(
pid.get() as usize | (context << 16),
pid.get() as _,
context as _,
original_address.map(|x| x.get()).unwrap_or(0),
msg.id,
msg.arg1,
@ -481,7 +525,8 @@ impl Server {
msg.arg4,
),
xous::Message::Move(msg) => QueuedMessage::MemoryMessageSend(
pid.get() as usize | (context << 16),
pid.get() as _,
context as _,
original_address.map(|x| x.get()).unwrap_or(0),
msg.id,
msg.buf.addr.get(),
@ -490,7 +535,8 @@ impl Server {
msg.valid.map(|x| x.get()).unwrap_or(0) as usize,
),
xous::Message::MutableBorrow(msg) => QueuedMessage::MemoryMessageRWLend(
pid.get() as usize | (context << 16),
pid.get() as _,
context as _,
original_address.map(|x| x.get()).unwrap_or(0),
msg.id,
msg.buf.addr.get(),
@ -499,7 +545,8 @@ impl Server {
msg.valid.map(|x| x.get()).unwrap_or(0) as usize,
),
xous::Message::Borrow(msg) => QueuedMessage::MemoryMessageROLend(
pid.get() as usize | (context << 16),
pid.get() as _,
context as _,
original_address.map(|x| x.get()).unwrap_or(0),
msg.id,
msg.buf.addr.get(),
@ -536,7 +583,8 @@ impl Server {
};
self.queue[self.queue_head] = QueuedMessage::WaitingResponse(
((pid.get() as usize) << 16) | (context & 0xffff),
pid.get() as _,
context as _,
server_address,
client_address.map(|x| x.get()).unwrap_or(0),
len,
@ -568,6 +616,10 @@ impl Server {
// If the context mask matches this context number, remove it
// and return the index.
if self.ready_contexts & test_ctx_mask == test_ctx_mask {
println!(
"Returning ready context {:08b}: {}",
self.ready_contexts, ctx_number
);
self.ready_contexts &= !test_ctx_mask;
return Some(ctx_number);
}
@ -599,7 +651,7 @@ impl Server {
/// Add the given context to the list of ready and waiting contexts.
pub fn park_context(&mut self, context: CtxID) {
// println!("Parking context: {}", context);
println!("KERNEL({}): Parking context: {}", self.pid, context);
self.ready_contexts |= 1 << context;
}
}

View file

@ -21,7 +21,7 @@ pub use crate::arch::process::INITIAL_CONTEXT;
/// This is inherited from the stage 1 bootloader.
pub struct SystemServices {
/// Current PID.
pid: PID,
// pid: PID,
/// A table of all processes in the system
pub processes: [Process; MAX_PROCESS_COUNT],
@ -193,7 +193,7 @@ impl Process {
}
thread_local!(static SYSTEM_SERVICES: RefCell<SystemServices> = RefCell::new(SystemServices {
pid: unsafe { PID::new_unchecked(1) },
// pid: unsafe { PID::new_unchecked(1) },
processes: [Process {
state: ProcessState::Free,
ppid: unsafe { PID::new_unchecked(1) },
@ -299,6 +299,7 @@ impl SystemServices {
let new_pid = pid_from_usize(idx + 1)?;
arch::process::Process::create(new_pid, init_process);
// #[allow(clippy::unit_arg)]
println!("Creating new process for PID {}", new_pid);
entry.state = ProcessState::Setup(init_context);
entry.ppid = crate::arch::process::current_pid();
entry.pid = new_pid;
@ -336,8 +337,8 @@ impl SystemServices {
Ok(&mut self.processes[pid_idx])
}
pub fn current_context_nr(&self) -> usize {
self.processes[self.pid.get() as usize - 1].current_context as usize
pub fn current_context_nr(&self, pid: PID) -> usize {
self.processes[pid.get() as usize - 1].current_context as usize
}
pub fn current_pid(&self) -> PID {
@ -403,7 +404,7 @@ impl SystemServices {
let mut arch_process = crate::arch::process::Process::current();
arch_process.set_context(context)?;
}
self.pid = pid;
// self.pid = pid;
Ok(())
}
@ -480,6 +481,7 @@ impl SystemServices {
/// Mark the specified context as ready to run. If the thread is Sleeping, mark
/// it as Ready.
pub fn ready_context(&mut self, pid: PID, context: CtxID) -> Result<(), xous::Error> {
assert!(context == INITIAL_CONTEXT);
let process = self.get_process_mut(pid)?;
process.state = match process.state {
ProcessState::Free => panic!(
@ -498,6 +500,7 @@ impl SystemServices {
pid, context, other
),
};
println!("KERNEL({}): Readying context {} -> {:?}", pid, context, process.state);
Ok(())
}
@ -510,6 +513,7 @@ impl SystemServices {
// println!("KERNEL(?): Getting current process...");
let process = self.get_process_mut(pid)?;
// println!("KERNEL(?): Current process is {:?}", process);
println!("switch_to (start): PID {}: {:?} @ {:?}", pid, process.state, std::thread::current().id());
// Determine which context number to switch to
process.state = match process.state {
@ -530,6 +534,7 @@ impl SystemServices {
let mut p = crate::arch::process::Process::current();
p.setup_context(INITIAL_CONTEXT, setup)?;
p.set_context(INITIAL_CONTEXT)?;
process.current_context = INITIAL_CONTEXT as u8;
// Mark the current proces state as "running, and no waiting contexts"
ProcessState::Running(0)
@ -609,7 +614,8 @@ impl SystemServices {
ProcessState::Running(new_mask)
}
};
self.pid = pid;
println!("switch_to (end): PID {}: {:?}", pid, process.state);
// self.pid = pid;
Ok(())
}
@ -628,6 +634,7 @@ impl SystemServices {
can_resume: bool,
) -> Result<(), xous::Error> {
let process = self.get_process_mut(pid)?;
println!("switch_from (start): PID {}: {:?}", pid, process.state);
process.state = match process.state {
ProcessState::Running(x) if x & (1 << context) != 0 => panic!(
"PID {} context {} was already queued for running when `switch_from()` was called",
@ -649,6 +656,7 @@ impl SystemServices {
pid, other
),
};
println!("switch_from (end): PID {}: {:?}", pid, process.state);
Ok(())
}
@ -685,9 +693,10 @@ impl SystemServices {
can_resume: bool,
advance_context: bool,
) -> Result<CtxID, xous::Error> {
println!("Activating PID {}, context {}", new_pid, new_context);
// println!("Activating PID {}, context {}", new_pid, new_context);
let previous_pid = self.current_pid();
let previous_context = self.current_context_nr();
let previous_context = self.current_context_nr(previous_pid);
println!("KERNEL({}): Activating process {} context {}", previous_pid, new_pid, new_context);
// Save state if the PID has changed. This will activate the new memory
// space.
@ -814,7 +823,7 @@ impl SystemServices {
// previous_pid, previous.state, can_resume
// );
} else {
if self.current_context_nr() == new_context {
if self.current_context_nr(previous_pid) == new_context {
if !can_resume {
panic!("tried to switch to our own context without resume");
}
@ -844,13 +853,13 @@ impl SystemServices {
}
}
}
self.pid = new_pid;
// self.pid = new_pid;
let mut process = crate::arch::process::Process::current();
// Restore the previous context, if one exists.
process.set_context(new_context)?;
self.processes[self.pid.get() as usize - 1].current_context = new_context as u8;
self.processes[new_pid.get() as usize - 1].current_context = new_context as u8;
// let _ctx = process.current_context();
Ok(new_context)
@ -1186,7 +1195,7 @@ impl SystemServices {
/// queue.
/// * **ServerNotFound**: The server queue was full and a free slot could not
/// be found.
pub fn create_server(&mut self, name: usize) -> Result<SID, xous::Error> {
pub fn create_server(&mut self, pid: PID, name: usize) -> Result<SID, xous::Error> {
// println!(
// "KERNEL({}): Looking through server list for free server",
// self.pid.get()
@ -1198,7 +1207,6 @@ impl SystemServices {
// "KERNEL({}): Found a free slot for a server -- allocating an entry",
// self.pid.get()
// );
let pid = self.pid;
// TODO: Come up with a way to randomize this
let sid = (
@ -1415,6 +1423,7 @@ impl SystemServices {
process.activate()?;
let parent_pid = process.ppid;
process.terminate()?;
println!("KERNEL({}): Terminated", target_pid);
let process = self.get_process(parent_pid)?;
process.activate().unwrap();

View file

@ -137,7 +137,7 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
}
SysCall::SwitchTo(new_pid, new_context) => {
SystemServices::with_mut(|ss| {
let context_nr = ss.current_context_nr();
let context_nr = ss.current_context_nr(pid);
unsafe {
assert!(
SWITCHTO_CALLER.is_none(),
@ -187,7 +187,7 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
SysCall::ReceiveMessage(sid) => {
SystemServices::with_mut(|ss| {
// See if there is a pending message. If so, return immediately.
let context_nr = ss.current_context_nr();
let context_nr = ss.current_context_nr(pid);
let sidx = ss.server_sidx(sid).ok_or(xous::Error::ServerNotFound)?;
let server = ss
.server_from_sidx(sidx)
@ -209,10 +209,10 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
// process and mark ourselves as awaiting an event. When a message
// arrives, our return value will already be set to the
// MessageEnvelope of the incoming message.
// println!(
// "PID {} did not have any waiting messages -- parking context {}",
// pid, context_nr
// );
println!(
"KERNEL({}): did not have any waiting messages -- parking context {}",
pid, context_nr
);
server.park_context(context_nr);
// For baremetal targets, switch away from this process.
@ -226,6 +226,7 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
// For hosted targets, simply return `BlockedProcess` indicating we'll make
// a callback to their socket at a later time.
else {
println!("229: Switching from {}", pid);
ss.switch_from(pid, context_nr, false)
.map(|_| xous::Result::BlockedProcess)
}
@ -246,7 +247,7 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
})
}
SysCall::CreateServer(name) => {
SystemServices::with_mut(|ss| ss.create_server(name).map(xous::Result::ServerID))
SystemServices::with_mut(|ss| ss.create_server(pid, name).map(xous::Result::ServerID))
}
SysCall::Connect(sid) => {
// ::debug_here::debug_here!();
@ -296,15 +297,15 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
return Err(xous::Error::ProcessNotFound);
}
};
// println!(
// "Returning {} bytes from {:08x} in PID {} to {:08x} in PID {} in context {}",
// len,
// server_addr.get(),
// pid,
// client_addr.get(),
// client_pid,
// client_ctx
// );
println!(
"Returning {} bytes from {:08x} in PID {} to {:08x} in PID {} in context {}",
len,
server_addr.get(),
pid,
client_addr.get(),
client_pid,
client_ctx
);
// Return the memory to the calling process
ss.return_memory(
@ -315,15 +316,19 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
)?;
// Unblock the client context to allow it to continue.
// println!("Unblocking PID {} CTX {}", client_pid, client_ctx);
println!(
"KERNEL({}): Unblocking PID {} CTX {}",
pid, client_pid, client_ctx
);
ss.ready_context(client_pid, client_ctx)?;
ss.set_context_result(client_pid, client_ctx, xous::Result::Ok)?;
ss.switch_to(client_pid, Some(client_ctx))?;
Ok(xous::Result::Ok)
})
}
SysCall::SendMessage(cid, message) => {
SystemServices::with_mut(|ss| {
let context_nr = ss.current_context_nr();
let context_nr = ss.current_context_nr(pid);
let sidx = ss.sidx_from_cid(cid).ok_or(xous::Error::ServerNotFound)?;
// ::debug_here::debug_here!();
@ -455,11 +460,16 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
.unwrap_or(Err(xous::Error::ProcessNotFound))
} else if blocking && !cfg!(baremetal) {
// println!("Blocking client, since it sent a blocking message");
ss.switch_to(server_pid, None)?;
ss.set_context_result(
server_pid,
ctx_number,
xous::Result::Message(envelope),
).and_then(|_| ss.switch_from(pid, context_nr, false))
)
.and_then(|_| {
println!("464: Switching from {}", pid);
ss.switch_from(pid, context_nr, false)
})
.map(|_| xous::Result::BlockedProcess)
} else if cfg!(baremetal) {
// println!("Setting the return value of the Server and returning to Client");
@ -471,6 +481,9 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
.map(|_| xous::Result::Ok)
} else {
// println!("Setting the return value of the Server and returning to Client");
// "Switch to" the server PID when not running on bare metal. This ensures
// that it's "Running".
ss.switch_to(server_pid, None)?;
ss.set_context_result(
server_pid,
ctx_number,
@ -479,10 +492,10 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
.map(|_| xous::Result::Ok)
}
} else {
println!("No contexts available to handle this. Queueing message.");
// println!("No contexts available to handle this. Queueing message.");
// There is no server context we can use, so add the message to
// the queue.
let context_nr = ss.current_context_nr();
let context_nr = ss.current_context_nr(pid);
// Add this message to the queue. If the queue is full, this
// returns an error.
@ -490,7 +503,10 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
// Park this context if it's blocking. This is roughly
// equivalent to a "Yield".
if blocking {
if !cfg!(baremetal) {
ss.switch_from(pid, context_nr, false)?;
Ok(xous::Result::BlockedProcess)
} else if blocking {
// println!("Returning to parent");
let process = ss.get_process(pid).expect("Can't get current process");
let ppid = process.ppid;
@ -506,7 +522,8 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result<xous::Result, xou
})
}
SysCall::TerminateProcess => SystemServices::with_mut(|ss| {
let context_nr = ss.current_context_nr();
let context_nr = ss.current_context_nr(pid);
println!("515: Switching from {}", pid);
ss.switch_from(pid, context_nr, false)?;
let ppid = ss.terminate_process(pid)?;
if cfg!(baremetal) {

View file

@ -8,6 +8,8 @@ use xous::{rsyscall, SysCall};
mod shutdown;
const SERVER_SPEC: &str = "localhost:0";
fn start_kernel(server_spec: &str) -> (JoinHandle<()>, SocketAddr) {
let server_addr = server_spec
.to_socket_addrs()
@ -46,10 +48,8 @@ fn start_kernel(server_spec: &str) -> (JoinHandle<()>, SocketAddr) {
#[test]
fn shutdown() {
let server_spec = "localhost:0";
// Start the server in another thread.
let (main_thread, server_spec) = start_kernel(server_spec);
let (main_thread, server_spec) = start_kernel(SERVER_SPEC);
// This is now the client.
xous::hosted::set_xous_address(server_spec);
@ -64,9 +64,8 @@ fn shutdown() {
#[test]
fn send_scalar_message() {
let server_spec = "localhost:0";
// Start the server in another thread
let (main_thread, server_spec) = start_kernel(server_spec);
let (main_thread, server_spec) = start_kernel(SERVER_SPEC);
xous::hosted::set_xous_address(server_spec);
@ -123,11 +122,10 @@ fn send_scalar_message() {
#[test]
fn send_move_message() {
let server_spec = "localhost:0";
let test_str = "Hello, world!";
let test_bytes = test_str.as_bytes();
let (main_thread, server_spec) = start_kernel(server_spec);
let (main_thread, server_spec) = start_kernel(SERVER_SPEC);
let (server_addr_send, server_addr_recv) = channel();
@ -175,18 +173,19 @@ fn send_move_message() {
#[test]
fn send_borrow_message() {
let server_spec = "localhost:0";
let (main_thread, server_spec) = start_kernel(server_spec);
let (main_thread, server_spec) = start_kernel(SERVER_SPEC);
let (server_addr_send, server_addr_recv) = channel();
let test_str = "Hello, world!";
let test_bytes = test_str.as_bytes();
let xous_server = spawn(move || {
xous::hosted::set_xous_address(server_spec);
println!("SERVER: Creating server...");
let sid = xous::create_server(0x7884_3123).expect("couldn't create test server");
server_addr_send.send(sid).unwrap();
println!("SERVER: Receiving message...");
let envelope = xous::receive_message(sid).expect("couldn't receive messages");
// println!("Received message from {}", envelope.sender);
println!("SERVER: Received message from {}", envelope.sender);
let message = envelope.message;
if let xous::Message::Borrow(m) = message {
let buf = m.buf;
@ -194,9 +193,10 @@ fn send_borrow_message() {
Box::from_raw(core::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()))
};
assert_eq!(*test_bytes, *bt);
// let s = String::from_utf8_lossy(&bt);
// println!("Got message: {:?} -> \"{}\"", bt, s);
let s = String::from_utf8_lossy(&bt);
println!("SERVER: Got message: {:?} -> \"{}\"", bt, s);
xous::return_memory(envelope.sender, m.buf).unwrap();
println!("SERVER: Returned memory");
} else {
panic!("unexpected message type");
}
@ -206,16 +206,22 @@ fn send_borrow_message() {
xous::hosted::set_xous_address(server_spec);
// Get the server address (out of band) so we know what to connect to
println!("CLIENT: Waiting for server to start...");
let sid = server_addr_recv.recv().unwrap();
// Perform a connection to the server
println!("CLIENT: Connecting to server...");
let conn = xous::connect(sid).expect("couldn't connect to server");
// Convert the message into a "Carton" that can be shipped as a message
println!("CLIENT: Creating carton...");
let carton = xous::carton::Carton::from_bytes(test_bytes);
// Send the message to the server
println!("CLIENT: Lending message...");
carton.lend(conn, 0).expect("couldn't lend message to server");
println!("CLIENT: Done");
});
xous_server.join().expect("couldn't join server process");
@ -229,8 +235,7 @@ fn send_borrow_message() {
#[test]
fn send_mutableborrow_message() {
let server_spec = "localhost:0";
let (main_thread, server_spec) = start_kernel(server_spec);
let (main_thread, server_spec) = start_kernel(SERVER_SPEC);
let (server_addr_send, server_addr_recv) = channel();
let test_str = "Hello, world!";
let test_bytes = test_str.as_bytes();
@ -287,3 +292,83 @@ fn send_mutableborrow_message() {
main_thread.join().expect("couldn't join kernel process");
}
#[test]
fn send_mutableborrow_message_long() {
let (main_thread, server_spec) = start_kernel(SERVER_SPEC);
let (server_addr_send, server_addr_recv) = channel();
let test_str = "Hello, world!";
let test_bytes = test_str.as_bytes();
let loops = 50;
let xous_server = spawn(move || {
xous::hosted::set_xous_address(server_spec);
let sid = xous::create_server(0x7884_3123).expect("couldn't create test server");
server_addr_send.send(sid).unwrap();
for iteration in 0..loops {
let envelope = xous::receive_message(sid).expect("couldn't receive messages");
let message = envelope.message;
if let xous::Message::MutableBorrow(m) = message {
let buf = m.buf;
let mut bt = unsafe {
Box::from_raw(core::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()))
};
for letter in bt.iter_mut() {
*letter = (*letter).wrapping_add((iteration & 0xff) as u8);
}
xous::return_memory(envelope.sender, m.buf).unwrap();
} else {
panic!("unexpected message type");
}
}
});
let xous_client = spawn(move || {
xous::hosted::set_xous_address(server_spec);
// Get the server address (out of band) so we know what to connect to
let sid = server_addr_recv.recv().unwrap();
// Perform a connection to the server
let conn = xous::connect(sid).expect("couldn't connect to server");
// Convert the message into a "Carton" that can be shipped as a message
for iteration in 0..loops {
let mut carton = xous::carton::Carton::from_bytes(&test_bytes);
let mut check_bytes = test_bytes.to_vec();
for letter in check_bytes.iter_mut() {
*letter = (*letter).wrapping_add((iteration & 0xff) as u8);
}
// Send the message to the server
carton.lend_mut(conn, 3).expect("couldn't mutably lend data");
let modified_bytes: &[u8] = carton.as_ref();
assert_eq!(&check_bytes, &modified_bytes);
}
});
xous_server.join().expect("couldn't join server process");
xous_client.join().expect("couldn't join client process");
// Any process ought to be able to shut down the system currently.
rsyscall(SysCall::Shutdown).expect("unable to shutdown server");
main_thread.join().expect("couldn't join kernel process");
}
// #[test]
// fn multiple_contexts() {
// // Start the kernel in its own thread
// let (main_thread, server_spec) = start_kernel(SERVER_SPEC);
// let (server_addr_send, server_addr_recv) = channel();
// xous::create_server(name)
// // Any process ought to be able to shut down the system currently.
// rsyscall(SysCall::Shutdown).expect("unable to shutdown server");
// main_thread.join().expect("couldn't join kernel process");
// }

View file

@ -607,7 +607,9 @@ impl SysCall {
),
_ => SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7),
},
Some(SysCallNumber::ReturnMemory) => SysCall::ReturnMemory(a1, MemoryRange::new(a2, a3)),
Some(SysCallNumber::ReturnMemory) => {
SysCall::ReturnMemory(a1, MemoryRange::new(a2, a3))
}
Some(SysCallNumber::SpawnThread) => SysCall::SpawnThread(
MemoryAddress::new(a1).ok_or(Error::InvalidSyscall)?,
MemoryAddress::new(a2).ok_or(Error::InvalidSyscall)?,
@ -798,6 +800,16 @@ pub fn wait_event() {
rsyscall(SysCall::WaitEvent).expect("wait_event returned an error");
}
/// Create a new thread
// pub fn spawn<F, T>(f: F) -> JoinHandle<T>
// where
// F: FnOnce() -> T,
// F: Send + 'static,
// T: Send + 'static,
// {
// Builder::new().spawn(f).expect("failed to spawn thread")
// }
pub fn rsyscall(call: SysCall) -> SysCallResult {
let mut ret = Result::Ok;
let args = call.as_args();