From 484e21fd309bdac0c8a5670d779aac9f1cdec890 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 23 Mar 2020 16:56:56 +0800 Subject: [PATCH] messaging: more work on transferring messages Still need to work on passing messages. Signed-off-by: Sean Cross --- kernel/src/arch/riscv/process.rs | 6 + kernel/src/main.rs | 2 +- kernel/src/services.rs | 185 ++++++++++++++++++++----------- kernel/src/syscall.rs | 21 +++- 4 files changed, 147 insertions(+), 67 deletions(-) diff --git a/kernel/src/arch/riscv/process.rs b/kernel/src/arch/riscv/process.rs index 98dd26413..4c30a32ff 100644 --- a/kernel/src/arch/riscv/process.rs +++ b/kernel/src/arch/riscv/process.rs @@ -51,6 +51,12 @@ impl Process { &mut self.contexts[self.context_nr as usize - 1] } + /// Return the current context number. + /// Context numbers are 0-indexed + pub fn current_context_nr(&self) -> usize { + self.context_nr as usize - 1 + } + pub fn trap_context(&mut self) -> &mut ProcessContext { &mut self.trap_context } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index a60737289..fa6f63c51 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -57,7 +57,7 @@ fn next_pid_to_run(last_pid: Option) -> Option { // PIDs are 1-indexed but arrays are 0-indexed. By not subtracting // 1 from the PID when we use it as an array index, we automatically // pick the next process in the list. - let mut current_pid = last_pid.unwrap_or(0) as usize + 2; + let mut current_pid = last_pid.unwrap_or(0) as usize + 1; let system_services = SystemServicesHandle::get(); for test_idx in current_pid..system_services.processes.len() { diff --git a/kernel/src/services.rs b/kernel/src/services.rs index 843e4babd..bceaf1d5f 100644 --- a/kernel/src/services.rs +++ b/kernel/src/services.rs @@ -92,7 +92,7 @@ pub struct ProcessInner { pub mem_heap_max: usize, /// A mapping of connection IDs to servers - pub connection_map: [u8 /* connection id */; 32], + pub connection_map: [u8; 32], pub _reserved: [u8; 28], } @@ -119,6 +119,10 @@ impl Process { _ => false, } } + + pub fn current_context_nr(&self) -> usize { + ProcessHandle::get().current_context_nr() + } } #[derive(Copy, Clone, PartialEq)] @@ -147,7 +151,7 @@ enum QueuedMessage { Empty, ScalarMessage( usize, /* sender */ - usize, /* unused */ + usize, /* context */ usize, /* id */ usize, /* arg1 */ usize, /* arg2 */ @@ -156,7 +160,7 @@ enum QueuedMessage { ), MemoryMessageSend( usize, /* sender */ - usize, /* unused */ + usize, /* context */ usize, /* id */ usize, /* buf */ usize, /* buf_size */ @@ -165,7 +169,7 @@ enum QueuedMessage { ), MemoryMessageROLend( usize, /* sender */ - usize, /* unused */ + usize, /* context */ usize, /* id */ usize, /* buf */ usize, /* buf_size */ @@ -174,7 +178,7 @@ enum QueuedMessage { ), MemoryMessageRWLend( usize, /* sender */ - usize, /* unused */ + usize, /* context */ usize, /* id */ usize, /* buf */ usize, /* buf_size */ @@ -203,88 +207,133 @@ pub struct Server { } impl Server { - pub fn take_next_message(&mut self) -> Option { + /// Remove a message from the server's queue and replace it with + /// QueuedMessage::Empty. Advance the queue pointer while we're at it. + pub fn take_next_message(&mut self) -> Option<(xous::MessageEnvelope, usize)> { let result = match self.queue[self.queue_index] { QueuedMessage::Empty => return None, QueuedMessage::MemoryMessageROLend( sender, - _unused, + context, id, buf, buf_size, offset, valid, - ) => xous::MessageEnvelope { - sender: sender, - message: xous::Message::ImmutableBorrow(xous::MemoryMessage { - id, - buf: MemoryAddress::new(buf), - buf_size: MemorySize::new(buf_size), - _offset: MemorySize::new(offset), - _valid: MemorySize::new(valid), - }), - }, + ) => ( + xous::MessageEnvelope { + sender: sender, + message: xous::Message::ImmutableBorrow(xous::MemoryMessage { + id, + buf: MemoryAddress::new(buf), + buf_size: MemorySize::new(buf_size), + _offset: MemorySize::new(offset), + _valid: MemorySize::new(valid), + }), + }, + context, + ), QueuedMessage::MemoryMessageRWLend( sender, - _unused, + context, id, buf, buf_size, offset, valid, - ) => xous::MessageEnvelope { - sender: sender, - message: xous::Message::MutableBorrow(xous::MemoryMessage { - id, - buf: MemoryAddress::new(buf), - buf_size: MemorySize::new(buf_size), - _offset: MemorySize::new(offset), - _valid: MemorySize::new(valid), - }), - }, - QueuedMessage::MemoryMessageSend( - sender, - _unused, - id, - buf, - buf_size, - offset, - valid, - ) => xous::MessageEnvelope { - sender: sender, - message: xous::Message::Move(xous::MemoryMessage { - id, - buf: MemoryAddress::new(buf), - buf_size: MemorySize::new(buf_size), - _offset: MemorySize::new(offset), - _valid: MemorySize::new(valid), - }), - }, - QueuedMessage::ScalarMessage( - sender, - _unused, - id, - arg1, - arg2, - arg3, - arg4, - ) => xous::MessageEnvelope { - sender: sender, - message: xous::Message::Scalar(xous::ScalarMessage { - id, - arg1, - arg2, - arg3, - arg4, - }), - }, + ) => ( + xous::MessageEnvelope { + sender: sender, + message: xous::Message::MutableBorrow(xous::MemoryMessage { + id, + buf: MemoryAddress::new(buf), + buf_size: MemorySize::new(buf_size), + _offset: MemorySize::new(offset), + _valid: MemorySize::new(valid), + }), + }, + context, + ), + QueuedMessage::MemoryMessageSend(sender, context, id, buf, buf_size, offset, valid) => { + ( + xous::MessageEnvelope { + sender: sender, + message: xous::Message::Move(xous::MemoryMessage { + id, + buf: MemoryAddress::new(buf), + buf_size: MemorySize::new(buf_size), + _offset: MemorySize::new(offset), + _valid: MemorySize::new(valid), + }), + }, + context, + ) + } + QueuedMessage::ScalarMessage(sender, context, id, arg1, arg2, arg3, arg4) => ( + xous::MessageEnvelope { + sender: sender, + message: xous::Message::Scalar(xous::ScalarMessage { + id, + arg1, + arg2, + arg3, + arg4, + }), + }, + context, + ), }; + self.queue[self.queue_index] = QueuedMessage::Empty; self.queue_index += 1; if self.queue_index >= self.queue.len() { self.queue_index = 0; } Some(result) } + + /// Add the given message to this server's queue. + pub fn queue_message( + &mut self, + envelope: xous::MessageEnvelope, + context: usize, + ) -> core::result::Result<(), xous::Error> { + if self.queue[self.queue_index] != QueuedMessage::Empty { + return Err(xous::Error::ServerQueueFull); + } + + self.queue_index += 1; + if self.queue_index >= self.queue.len() { + self.queue_index = 0; + } + Ok(()) + } + + /// Return a context ID that is available and blocking. If no such context ID exists, + /// or if this server isn't actually ready to receive packets, return None. + pub fn take_available_context(&mut self) -> Option { + let context_index = match self.state { + ServerState::Ready(0) => return None, + ServerState::Ready(x) => x, + _ => return None, + }; + + let mut test_ctx_mask = 1; + let mut ctx_number = 0; + loop { + // If the context mask matches this context number, remove it + // and return the index. + if context_index & test_ctx_mask == test_ctx_mask { + self.state = ServerState::Ready(context_index & !test_ctx_mask); + return Some(ctx_number); + } + // Advance to the next slot. + test_ctx_mask = test_ctx_mask.rotate_left(1); + ctx_number = ctx_number + 1; + if test_ctx_mask == 1 { + panic!("didn't find a free context, even though there should be one"); + } + } + } } impl Default for Server { @@ -326,6 +375,12 @@ pub struct SystemServices { /// A table of all servers in the system servers: [Server; MAX_SERVER_COUNT], + + /// A log of the currently-active syscall depth + syscall_stack: [(usize, usize); 3], + + /// How many entries there are on the syscall stack + syscall_depth: usize, } static mut SYSTEM_SERVICES: SystemServices = SystemServices { @@ -342,6 +397,8 @@ static mut SYSTEM_SERVICES: SystemServices = SystemServices { queue_index: 0, queue: &[], }; MAX_SERVER_COUNT], + syscall_stack: [(0, 0), (0, 0), (0, 0)], + syscall_depth: 0, }; impl core::fmt::Debug for Process { diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index a6743a4f7..e02cbca5b 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -225,7 +225,7 @@ pub fn handle(call: SysCall) -> core::result::Result .map(|_| Ok(xous::Result::ResumeProcess)) .unwrap_or(Err(xous::Error::ProcessNotFound)) } - SysCall::WaitMessage(sid) => { + SysCall::ReceiveMessage(sid) => { let mut ss = SystemServicesHandle::get(); // See if there is a pending message. If so, return immediately. let mut server = ss.server_mut(sid).ok_or(xous::Error::ServerNotFound)?; @@ -237,7 +237,7 @@ pub fn handle(call: SysCall) -> core::result::Result // If there is a pending message, return it immediately. if let Some(msg) = server.take_next_message() { - return Ok(xous::Result::Message(msg)); + return Ok(xous::Result::Message(msg.0)); } // There is no pending message, so return control to the parent process @@ -270,6 +270,23 @@ pub fn handle(call: SysCall) -> core::result::Result SysCall::SendMessage(cid, message) => { let mut ss = SystemServicesHandle::get(); let server = ss.server_from_cid(cid).ok_or(xous::Error::ServerNotFound)?; + + // If the server has an available context to receive the message, transfer it right away. + if let Some(ctx_number) = server.take_available_context() { + // We can pass control on to this context, and add the existing context + // to the blocking pool. + } else { + // There is no server context we can use, so add the message to + // the queue. + let current_pid = ss.current_pid(); + let context_nr = ss.get_process(current_pid)?.current_context_nr(); + + // Add this message to the queue. If the queue is full, this + // returns an error. + server.queue_message(MessageEnvelope { sender: 0, message }, context_nr)?; + + // Park this context. This is roughly equivalent to a "Yield". + } Err(xous::Error::UnhandledSyscall) } _ => Err(xous::Error::UnhandledSyscall),