mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
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:
parent
569a4196de
commit
484e21fd30
4 changed files with 147 additions and 67 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Reference in a new issue