messaging: more work on transferring messages

Still need to work on passing messages.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2020-03-23 16:56:56 +08:00
parent 569a4196de
commit 484e21fd30
4 changed files with 147 additions and 67 deletions

View file

@ -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
}

View file

@ -57,7 +57,7 @@ fn next_pid_to_run(last_pid: Option<PID>) -> Option<PID> {
// 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() {

View file

@ -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<xous::MessageEnvelope> {
/// 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<usize> {
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 {

View file

@ -225,7 +225,7 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
.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<xous::Result, xous::Error>
// 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<xous::Result, xous::Error>
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),