From e652150c6e91fc3e99fa53e9b3f4073d072eef45 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Wed, 15 Jul 2020 16:09:42 +0800 Subject: [PATCH] kernel: get multiple message passing working Signed-off-by: Sean Cross --- kernel/src/arch/hosted/mod.rs | 53 +++++++--- kernel/src/arch/hosted/process.rs | 2 +- kernel/src/server.rs | 166 ++++++++++++++++++++---------- kernel/src/services.rs | 35 ++++--- kernel/src/syscall.rs | 63 +++++++----- kernel/src/test/mod.rs | 113 +++++++++++++++++--- xous-rs/src/syscall.rs | 14 ++- 7 files changed, 320 insertions(+), 126 deletions(-) diff --git a/kernel/src/arch/hosted/mod.rs b/kernel/src/arch/hosted/mod.rs index 50d3d9c4c..ad76288fa 100644 --- a/kernel/src/arch/hosted/mod.rs +++ b/kernel/src/arch/hosted/mod.rs @@ -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 = 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) // 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) 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 { diff --git a/kernel/src/arch/hosted/process.rs b/kernel/src/arch/hosted/process.rs index 2eacfebd1..61572ad62 100644 --- a/kernel/src/arch/hosted/process.rs +++ b/kernel/src/arch/hosted/process.rs @@ -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()); diff --git a/kernel/src/server.rs b/kernel/src/server.rs index d761bb43b..be6cd0c7f 100644 --- a/kernel/src/server.rs +++ b/kernel/src/server.rs @@ -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 - ) -> Result<(), xous::Error> { + pub fn destroy(current: &mut Option) -> 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 { + pub fn take_waiting_message( + &mut self, + idx: usize, + buf: MemoryRange, + ) -> Result { 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; } } diff --git a/kernel/src/services.rs b/kernel/src/services.rs index d8f7d0033..7c60c96c1 100644 --- a/kernel/src/services.rs +++ b/kernel/src/services.rs @@ -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 = 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 { - 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 { + pub fn create_server(&mut self, pid: PID, name: usize) -> Result { // 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(); diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 99f51e9e6..3b36347e9 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -137,7 +137,7 @@ pub fn handle(pid: PID, call: SysCall) -> core::result::Result { 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 { 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 core::result::Result core::result::Result { - 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 core::result::Result { 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 core::result::Result core::result::Result core::result::Result core::result::Result 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) { diff --git a/kernel/src/test/mod.rs b/kernel/src/test/mod.rs index eb021431b..78a317010 100644 --- a/kernel/src/test/mod.rs +++ b/kernel/src/test/mod.rs @@ -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"); +// } diff --git a/xous-rs/src/syscall.rs b/xous-rs/src/syscall.rs index c88154194..e5087e50e 100644 --- a/xous-rs/src/syscall.rs +++ b/xous-rs/src/syscall.rs @@ -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: F) -> JoinHandle +// 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();