2021-01-25 13:54:00 +00:00
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
// SPDX-License-Identifier: Apache-2.0
2021-01-03 10:31:51 +00:00
pub use crate ::arch ::process ::Thread ;
2021-04-05 10:18:48 +00:00
use crate ::{ mem ::MemoryManager , services ::SystemServices } ;
2021-01-03 10:31:51 +00:00
use core ::mem ;
use xous_kernel ::{ MemoryAddress , MemoryRange , MemorySize , Message , MessageSender , PID , SID , TID } ;
2021-03-24 14:10:11 +00:00
/// A pointer to resolve a server ID to a particular process
#[ derive(PartialEq, Debug) ]
pub struct Server {
/// A randomly-generated ID
pub sid : SID ,
/// The process that owns this server
pub pid : PID ,
/// Where messages should be inserted
queue_head : usize ,
/// The index that the server is currently reading from
queue_tail : usize ,
/// An increasing number that indicates where the server is reading.
head_generation : u8 ,
/// An increasing (but wrapping number) that indicates where clients are writing.
tail_generation : u8 ,
/// Where data will appear
#[ cfg(baremetal) ]
queue : & 'static mut [ QueuedMessage ] ,
#[ cfg(not(baremetal)) ]
queue : Vec < QueuedMessage > ,
/// The `context mask` is a bitfield of contexts that are able to handle
/// this message. If there are no available contexts, then messages will
/// need to be queued.
ready_threads : usize ,
}
2021-01-03 10:31:51 +00:00
pub struct SenderID {
/// The index of the server within the SystemServices table
pub sidx : usize ,
/// The index into the queue array
pub idx : usize ,
/// The process ID that sent this message
pid : Option < PID > ,
}
impl SenderID {
pub fn new ( sidx : usize , idx : usize , pid : Option < PID > ) -> Self {
SenderID { sidx , idx , pid }
}
}
impl From < usize > for SenderID {
fn from ( item : usize ) -> SenderID {
SenderID {
sidx : ( item > > 16 ) & 0xff ,
idx : item & 0xffff ,
pid : PID ::new ( ( item > > 24 ) as u8 ) ,
}
}
}
2021-08-06 02:03:12 +00:00
impl From < SenderID > for usize {
fn from ( val : SenderID ) -> Self {
( val . pid . map ( | x | x . get ( ) as usize ) . unwrap_or ( 0 ) < < 24 )
| ( ( val . sidx < < 16 ) & 0x00ff0000 )
| ( val . idx & 0xffff )
2021-01-03 10:31:51 +00:00
}
}
impl From < MessageSender > for SenderID {
fn from ( item : MessageSender ) -> SenderID {
SenderID ::from ( item . to_usize ( ) )
}
}
2021-08-06 02:03:12 +00:00
impl From < SenderID > for MessageSender {
fn from ( val : SenderID ) -> Self {
MessageSender ::from_usize ( val . into ( ) )
2021-01-03 10:31:51 +00:00
}
}
#[ derive(Debug) ]
pub enum WaitingMessage {
/// There is no waiting message.
None ,
/// The memory was borrowed and should be returned to the given process.
BorrowedMemory ( PID , TID , MemoryAddress , MemoryAddress , MemorySize ) ,
/// The memory was moved, and so shouldn't be returned.
MovedMemory ,
/// The message was a scalar message, so you should return the result to the process
ScalarMessage ( PID , TID ) ,
/// This memory should be returned to the system.
ForgetMemory ( MemoryRange ) ,
}
/// Internal representation of a queued message for a server. This should be
/// exactly 8 words / 32 bytes, yielding 128 queued messages per server
#[ repr(usize) ]
#[ derive(PartialEq, Debug) ]
enum QueuedMessage {
Empty ,
BlockingScalarMessage (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-04-05 10:18:48 +00:00
usize , /* reserved */
2021-01-03 10:31:51 +00:00
usize , /* id */
usize , /* arg1 */
usize , /* arg2 */
usize , /* arg3 */
usize , /* arg4 */
) ,
ScalarMessage (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-04-05 10:18:48 +00:00
usize , /* reserved */
2021-01-03 10:31:51 +00:00
usize , /* id */
usize , /* arg1 */
usize , /* arg2 */
usize , /* arg3 */
usize , /* arg4 */
) ,
MemoryMessageSend (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-04-05 10:18:48 +00:00
usize , /* client memory address */
2021-01-03 10:31:51 +00:00
usize , /* id */
2021-04-05 10:18:48 +00:00
usize , /* server memory address */
2021-01-03 10:31:51 +00:00
usize , /* buf_size */
usize , /* offset */
usize , /* valid */
) ,
MemoryMessageROLend (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-04-05 10:18:48 +00:00
usize , /* client memory address */
2021-01-03 10:31:51 +00:00
usize , /* id */
2021-04-05 10:18:48 +00:00
usize , /* server memory address */
2021-01-03 10:31:51 +00:00
usize , /* buf_size */
usize , /* offset */
usize , /* valid */
) ,
MemoryMessageRWLend (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-04-05 10:18:48 +00:00
usize , /* client memory address */
2021-01-03 10:31:51 +00:00
usize , /* id */
2021-04-05 10:18:48 +00:00
usize , /* server memory address */
2021-01-03 10:31:51 +00:00
usize , /* buf_size */
usize , /* offset */
usize , /* valid */
) ,
/// The process lending this memory terminated before
/// we could receive the message.
MemoryMessageROLendTerminated (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-04-05 10:18:48 +00:00
usize , /* client memory address */
2021-01-03 10:31:51 +00:00
usize , /* id */
2021-04-05 10:18:48 +00:00
usize , /* server memory address */
2021-01-03 10:31:51 +00:00
usize , /* buf_size */
usize , /* offset */
usize , /* valid */
) ,
/// The process lending this memory terminated before
/// we could receive the message.
MemoryMessageRWLendTerminated (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-04-05 10:18:48 +00:00
usize , /* client memory address */
2021-01-03 10:31:51 +00:00
usize , /* id */
2021-04-05 10:18:48 +00:00
usize , /* server memory address */
2021-01-03 10:31:51 +00:00
usize , /* buf_size */
usize , /* offset */
usize , /* valid */
) ,
/// The process waiting for the response terminated before
/// we could receive the message.
BlockingScalarTerminated (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-04-05 10:18:48 +00:00
usize , /* reserved */
2021-01-03 10:31:51 +00:00
usize , /* id */
usize , /* arg1 */
usize , /* arg2 */
usize , /* arg3 */
usize , /* arg4 */
) ,
/// When a message is taken that needs to be returned -- such as an ROLend
/// or RWLend -- the slot is replaced with a WaitingReturnMemory token and its
/// index is returned as the message sender. This is used to unblock the
/// sending process.
WaitingReturnMemory (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-01-03 10:31:51 +00:00
usize , /* address of memory base in server */
usize , /* client base address */
usize , /* Range size */
) ,
/// When a server goes away, its memory must be forgotten instead of being returned
/// to the previous process.
WaitingForget (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-01-03 10:31:51 +00:00
usize , /* address of memory base in server */
usize , /* client base address */
usize , /* Range size */
) ,
/// This is the state when a message is blocking, but has no associated memory
/// page.
WaitingReturnScalar (
u16 , /* client PID */
2021-03-24 14:10:11 +00:00
u8 , /* client TID */
u8 , /* message index */
2021-01-03 10:31:51 +00:00
usize , /* server return address */
) ,
}
2021-04-05 10:18:48 +00:00
impl QueuedMessage {
/// Return `true` if this Queued Message is sitting inside of the Server, and
/// is therefore waiting to be returned.
/// This only indicates messages that have been seen by the Server and have
/// not yet been responded to -- Messages that have not yet been seen by the
/// Server will return `false`.
fn is_in_server ( & self ) -> bool {
2021-08-06 02:03:12 +00:00
matches! (
self ,
2021-04-05 10:18:48 +00:00
& QueuedMessage ::WaitingForget ( _ , _ , _ , _ , _ , _ )
2021-08-06 02:03:12 +00:00
| & QueuedMessage ::WaitingReturnMemory ( _ , _ , _ , _ , _ , _ )
| & QueuedMessage ::WaitingReturnScalar ( _ , _ , _ , _ )
)
2021-04-05 10:18:48 +00:00
}
}
2021-01-03 10:31:51 +00:00
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.
///
/// # Errors
///
/// * **MemoryInUse**: The provided Server option already exists
pub fn init (
new : & mut Option < Server > ,
pid : PID ,
sid : SID ,
_backing : MemoryRange ,
) -> Result < ( ) , xous_kernel ::Error > {
if new ! = & None {
return Err ( xous_kernel ::Error ::MemoryInUse ) ;
}
#[ cfg(baremetal) ]
let queue = unsafe {
core ::slice ::from_raw_parts_mut (
_backing . as_mut_ptr ( ) as * mut QueuedMessage ,
2021-04-05 10:18:48 +00:00
_backing . len ( ) / mem ::size_of ::< QueuedMessage > ( ) ,
2021-01-03 10:31:51 +00:00
)
} ;
#[ cfg(not(baremetal)) ]
let queue = {
let mut queue = vec! [ ] ;
// TODO: Replace this with a direct operation on a passed-in page
queue . resize_with (
crate ::arch ::mem ::PAGE_SIZE / mem ::size_of ::< QueuedMessage > ( ) ,
| | QueuedMessage ::Empty ,
) ;
queue
} ;
* new = Some ( Server {
sid ,
pid ,
queue_head : 0 ,
queue_tail : 0 ,
2021-03-24 14:10:11 +00:00
head_generation : 0 ,
tail_generation : 0 ,
2021-01-03 10:31:51 +00:00
queue ,
ready_threads : 0 ,
} ) ;
Ok ( ( ) )
}
/// Take a current slot and replace it with `None`, clearing out the contents of the queue.
2021-04-05 10:18:48 +00:00
/// Returns an error if the queue has any waiting elements.
/// Returns a list of threads that should be readied.
2021-05-17 08:03:20 +00:00
pub fn destroy ( mut self , ss : & mut SystemServices ) -> Result < ( ) , Self > {
2021-04-05 10:18:48 +00:00
// First determine if the server has any Waiting messages. That is, any messages
// that are currently sitting in the memory space of the Server. These cannot
// safely be handled, and will cause an error if we try to mess with them.
for queue_entry in self . queue . iter ( ) {
if queue_entry . is_in_server ( ) {
return Err ( self ) ;
}
2021-01-03 10:31:51 +00:00
}
2021-04-05 10:18:48 +00:00
// We now know there will be no problems in shutting down this server. Look
// through the queue and respond to each message in turn.
for entry in self . queue . iter_mut ( ) {
match * entry {
// If there are `Waiting` messages, then something is seriously wrong because
// we already determined above that this wouldn't happen.
QueuedMessage ::WaitingForget ( _ , _ , _ , _ , _ , _ )
| QueuedMessage ::WaitingReturnMemory ( _ , _ , _ , _ , _ , _ )
| QueuedMessage ::WaitingReturnScalar ( _ , _ , _ , _ ) = > panic! ( " message was waiting " ) ,
// For `Empty` and `Scalar` messages, all we have to do is ignore them.
// The sending process will not be blocked. These messages will be dropped,
// and the server will never see them.
2021-08-06 02:03:12 +00:00
QueuedMessage ::Empty | QueuedMessage ::ScalarMessage ( _ , _ , _ , _ , _ , _ , _ , _ , _ ) = > { }
2021-04-05 10:18:48 +00:00
// For `Send` messages, the Server has not yet seen these messages. Simply
// prevent this memory from getting mapped into the Server and free it.
QueuedMessage ::MemoryMessageSend (
_pid ,
_tid ,
_idx ,
_client_memory_addr ,
_id ,
server_memory_addr ,
memory_length ,
_offset ,
_valid ,
) = > {
MemoryManager ::with_mut ( | mm | {
let mut result = Ok ( xous_kernel ::Result ::Ok ) ;
let virt = server_memory_addr ;
let size = memory_length ;
2021-08-06 02:03:12 +00:00
if ! cfg! ( baremetal ) & & virt & 0xfff ! = 0 {
return Err ( xous_kernel ::Error ::BadAlignment ) ;
2021-04-05 10:18:48 +00:00
}
for addr in ( virt .. ( virt + size ) ) . step_by ( crate ::mem ::PAGE_SIZE ) {
if let Err ( e ) = mm . unmap_page ( addr as * mut usize ) {
if result . is_ok ( ) {
result = Err ( e ) ;
}
}
}
result
} )
. unwrap ( ) ;
}
// For BlockingScalar messages, the client is waiting for a response.
// Unblock the client and return an error indicating the server does
// not exist.
QueuedMessage ::BlockingScalarTerminated ( pid , tid , _ , _ , _ , _ , _ , _ , _ )
| QueuedMessage ::BlockingScalarMessage ( pid , tid , _ , _ , _ , _ , _ , _ , _ ) = > {
let pid = PID ::new ( pid as _ ) . unwrap ( ) ;
let tid = tid as _ ;
// Set the return value of the specified thread.
ss . set_thread_result (
pid ,
tid ,
xous_kernel ::Result ::Error ( xous_kernel ::Error ::ServerNotFound ) ,
)
. unwrap ( ) ;
// Mark it as ready to run.
ss . ready_thread ( pid , tid ) . unwrap ( ) ;
}
QueuedMessage ::MemoryMessageROLend (
client_pid ,
client_tid ,
_idx ,
client_addr ,
_id ,
server_addr ,
buf_size ,
_ ,
_ ,
)
| QueuedMessage ::MemoryMessageRWLend (
client_pid ,
client_tid ,
_idx ,
client_addr ,
_id ,
server_addr ,
buf_size ,
_ ,
_ ,
)
| QueuedMessage ::MemoryMessageROLendTerminated (
client_pid ,
client_tid ,
_idx ,
client_addr ,
_id ,
server_addr ,
buf_size ,
_ ,
_ ,
)
| QueuedMessage ::MemoryMessageRWLendTerminated (
client_pid ,
client_tid ,
_idx ,
client_addr ,
_id ,
server_addr ,
buf_size ,
_ ,
_ ,
) = > {
let client_pid = PID ::new ( client_pid as _ ) . unwrap ( ) ;
let client_tid = client_tid as _ ;
// Return the memory to the calling process
ss . return_memory (
2021-05-05 02:58:12 +00:00
server_addr as * mut usize ,
2021-04-05 10:18:48 +00:00
client_pid ,
client_tid ,
client_addr as _ ,
buf_size ,
)
. unwrap ( ) ;
ss . ready_thread ( client_pid , client_tid ) . unwrap ( ) ;
ss . set_thread_result (
client_pid ,
client_tid ,
xous_kernel ::Result ::Error ( xous_kernel ::Error ::ServerNotFound ) ,
)
. unwrap ( ) ;
}
}
* entry = QueuedMessage ::Empty ;
}
let server_pid = ss . current_pid ( ) ;
// Finally, wake up all threads that are waiting on this Server.
while let Some ( server_tid ) = self . take_available_thread ( ) {
ss . ready_thread ( server_pid , server_tid ) . unwrap ( ) ;
ss . set_thread_result (
server_pid ,
server_tid ,
xous_kernel ::Result ::Error ( xous_kernel ::Error ::ServerNotFound ) ,
)
. unwrap ( ) ;
}
// Release the backing memory
#[ cfg(baremetal) ]
MemoryManager ::with_mut ( | mm | {
let virt = self . queue . as_mut_ptr ( ) as usize ;
let size = self . queue . len ( ) ;
for addr in ( virt .. ( virt + size ) ) . step_by ( crate ::arch ::mem ::PAGE_SIZE ) {
mm . unmap_page ( addr as * mut usize ) . unwrap ( ) ;
}
} ) ;
// The server should now be destroyed.
2021-01-03 10:31:51 +00:00
Ok ( ( ) )
}
// pub fn print_queue(&self) {
// println!(" Q Queue Head: {}", self.queue_head);
// println!(" Q Queue Tail: {}", self.queue_tail);
// for (_idx, _entry) in self.queue.iter().enumerate() {
// if _entry != &QueuedMessage::Empty {
// println!(" Q entry[{}]: {:?}", _idx, _entry);
// }
// }
// }
/// When a process terminates, there may be memory that is lent to us.
/// Mark all of that memory to be discarded when it is returned, rather than
/// giving it back to the previous process space.
pub fn discard_messages_for_pid ( & mut self , pid : PID ) {
for entry in self . queue . iter_mut ( ) {
match * entry {
QueuedMessage ::MemoryMessageROLend (
msg_pid ,
tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-01-03 10:31:51 +00:00
arg1 ,
arg2 ,
arg3 ,
arg4 ,
arg5 ,
arg6 ,
) = > {
if msg_pid = = pid . get ( ) as _ {
* entry = QueuedMessage ::MemoryMessageROLendTerminated (
2021-03-24 14:10:11 +00:00
msg_pid , tid , idx , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ,
2021-01-03 10:31:51 +00:00
) ;
}
}
QueuedMessage ::MemoryMessageRWLend (
msg_pid ,
tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-01-03 10:31:51 +00:00
arg1 ,
arg2 ,
arg3 ,
arg4 ,
arg5 ,
arg6 ,
) = > {
if msg_pid = = pid . get ( ) as _ {
* entry = QueuedMessage ::MemoryMessageRWLendTerminated (
2021-03-24 14:10:11 +00:00
msg_pid , tid , idx , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ,
2021-01-03 10:31:51 +00:00
) ;
}
}
QueuedMessage ::BlockingScalarMessage (
msg_pid ,
tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-01-03 10:31:51 +00:00
arg1 ,
arg2 ,
arg3 ,
arg4 ,
arg5 ,
arg6 ,
) = > {
if msg_pid = = pid . get ( ) as _ {
* entry = QueuedMessage ::BlockingScalarTerminated (
2021-03-24 14:10:11 +00:00
msg_pid , tid , idx , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ,
2021-01-03 10:31:51 +00:00
) ;
}
}
// For "Scalar" and "Move" messages, this memory has already
// been moved into this process, so memory will be reclaimed
// when the process terminates.
_ = > ( ) ,
}
}
}
/// Convert a `QueuedMesage::WaitingReturnMemory` into `QueuedMessage::Empty`
/// 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 ,
2021-03-24 14:10:11 +00:00
message_index : usize ,
2021-01-03 10:31:51 +00:00
buf : Option < & MemoryRange > ,
) -> Result < WaitingMessage , xous_kernel ::Error > {
2021-03-24 14:10:11 +00:00
// klog!("head generation: {} tail generation: {}", self.head_generation, self.tail_generation);
// if self.tail_generation == self.head_generation {
// Err(xous_kernel::Error::BadAddress)?;
// }
2021-01-03 10:31:51 +00:00
let current_val = self
. queue
2021-03-24 14:10:11 +00:00
. get_mut ( message_index )
2021-01-03 10:31:51 +00:00
. ok_or ( xous_kernel ::Error ::BadAddress ) ? ;
2021-03-24 14:10:11 +00:00
// klog!("memory in queue[{}]: {:?}", message_index, current_val);
2021-04-05 10:18:48 +00:00
let ( pid , tid , _idx , server_addr , client_addr , len , forget , is_memory ) = match * current_val
{
2021-03-24 14:10:11 +00:00
QueuedMessage ::WaitingReturnMemory ( pid , tid , idx , server_addr , client_addr , len ) = > {
( pid , tid , idx , server_addr , client_addr , len , false , true )
2021-01-03 10:31:51 +00:00
}
2021-03-24 14:10:11 +00:00
QueuedMessage ::WaitingForget ( pid , tid , idx , server_addr , client_addr , len ) = > {
( pid , tid , idx , server_addr , client_addr , len , true , true )
2021-01-03 10:31:51 +00:00
}
2021-03-24 14:10:11 +00:00
QueuedMessage ::WaitingReturnScalar ( pid , tid , idx , return_address ) = > {
( pid , tid , idx , return_address , 0 , 0 , true , false )
2021-01-03 10:31:51 +00:00
}
_ = > return Ok ( WaitingMessage ::None ) ,
} ;
// Sanity check the specified address was correct, and matches what we
// had cached.
2022-12-29 13:03:39 +00:00
if is_memory & & cfg! ( baremetal ) & & buf . is_some ( ) {
2021-01-03 10:31:51 +00:00
let buf = buf . expect ( " memory message expected but no buffer passed! " ) ;
if server_addr ! = buf . as_ptr ( ) as usize | | len ! = buf . len ( ) {
2021-03-24 14:10:11 +00:00
// klog!("Memory is attached but the returned buffer doesn't match (len: {} vs {}), buf addr: {:08x} vs {:08x}", len, buf.len(), server_addr, buf.as_ptr() as usize);
2021-08-06 02:03:12 +00:00
return Err ( xous_kernel ::Error ::BadAddress ) ;
2021-01-03 10:31:51 +00:00
}
}
* current_val = QueuedMessage ::Empty ;
2021-03-24 14:10:11 +00:00
if message_index = = self . queue_tail {
2021-03-23 11:45:32 +00:00
self . queue_tail + = 1 ;
if self . queue_tail > = self . queue . len ( ) {
self . queue_tail = 0 ;
}
// Advance the pointer in case we have a long string of Empty messages.
2021-03-24 14:10:11 +00:00
while self . queue_tail ! = self . queue_head
& & self . queue [ self . queue_tail ] = = QueuedMessage ::Empty
{
2021-03-23 11:45:32 +00:00
self . queue_tail + = 1 ;
if self . queue_tail > = self . queue . len ( ) {
self . queue_tail = 0 ;
}
}
2021-01-03 10:31:51 +00:00
}
// Destructure the PID and context ID from the `pid_tid` field
2021-03-23 11:45:32 +00:00
// klog!(
// "taking waiting message and returning to pid: {} tid: {}",
// pid,
// tid
// );
2021-01-03 10:31:51 +00:00
if ! is_memory {
return Ok ( WaitingMessage ::ScalarMessage (
PID ::new ( pid as _ ) . unwrap ( ) ,
tid as _ ,
) ) ;
}
if forget {
2021-06-24 09:02:02 +00:00
return Ok ( WaitingMessage ::ForgetMemory ( unsafe {
MemoryRange ::new ( server_addr , len )
} ? ) ) ;
2021-01-03 10:31:51 +00:00
}
// If a `move` address somehow ends up here, indicate the memory has been moved.
let server_addr = match MemoryAddress ::new ( server_addr ) {
Some ( o ) = > o ,
None = > return Ok ( WaitingMessage ::MovedMemory ) ,
} ;
let client_addr = MemoryAddress ::new ( client_addr )
. 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 ::new ( pid as _ ) . unwrap ( ) ,
tid as _ ,
server_addr ,
client_addr ,
len ,
) )
}
/// Remove a message from the server's queue and replace it with either a QueuedMessage::WaitingReturnMemory
/// or, for Scalar messages, QueuedMessage::Empty.
///
/// For non-Scalar messages, you must call `take_waiting_message()` in order to return
/// memory to the calling process.
///
/// # Returns
///
/// * **None**: There are no waiting messages
/// ***Some(MessageEnvelope): This message is queued.
pub fn take_next_message ( & mut self , sidx : usize ) -> Option < xous_kernel ::MessageEnvelope > {
2021-03-23 11:45:32 +00:00
// klog!(
2021-03-24 14:10:11 +00:00
// "queue_head: ((({}))) queue_tail: ((({}))): {:?} CID: ((({}))) head_gen: {} tail_gen: {}",
2021-03-23 11:45:32 +00:00
// self.queue_head,
// self.queue_tail,
// self.queue[self.queue_tail],
2021-03-24 14:10:11 +00:00
// sidx,
// self.head_generation,
// self.tail_generation,
2021-01-03 10:31:51 +00:00
// );
2021-03-24 14:10:11 +00:00
// If the reading head and tail generations are the same, the queue is empty.
if self . tail_generation = = self . head_generation {
// klog!("self.tail_generation {} == self.head_generation {}", self.tail_generation, self.head_generation);
return None ;
}
2021-01-03 10:31:51 +00:00
use core ::convert ::TryInto ;
2021-03-23 11:45:32 +00:00
let mut queue_idx = self . queue_tail ;
2021-03-24 14:10:11 +00:00
loop {
2021-03-23 11:45:32 +00:00
let mut sender = SenderID ::new ( sidx , queue_idx , None ) ;
// klog!("Message @ server.queue[{}]: {:?}", queue_idx, self.queue[queue_idx]);
let ( result , response ) = match self . queue [ queue_idx ] {
QueuedMessage ::MemoryMessageROLend (
pid ,
tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-03-23 11:45:32 +00:00
client_addr ,
id ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-23 11:45:32 +00:00
buf_size ,
offset ,
valid ,
2021-03-24 14:10:11 +00:00
) if idx = = self . head_generation = > {
2021-03-23 11:45:32 +00:00
sender . pid = PID ::new ( pid . try_into ( ) . unwrap ( ) ) ;
(
xous_kernel ::MessageEnvelope {
sender : sender . into ( ) ,
body : xous_kernel ::Message ::Borrow ( xous_kernel ::MemoryMessage {
id ,
2021-06-24 09:02:02 +00:00
buf : unsafe { MemoryRange ::new ( server_addr , buf_size ) . ok ( ) } ? ,
2021-03-23 11:45:32 +00:00
offset : MemorySize ::new ( offset ) ,
valid : MemorySize ::new ( valid ) ,
} ) ,
} ,
2021-03-24 14:10:11 +00:00
QueuedMessage ::WaitingReturnMemory (
pid ,
tid ,
idx ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-24 14:10:11 +00:00
client_addr ,
buf_size ,
) ,
2021-03-23 11:45:32 +00:00
)
}
QueuedMessage ::MemoryMessageRWLend (
pid ,
tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-03-23 11:45:32 +00:00
client_addr ,
id ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-23 11:45:32 +00:00
buf_size ,
offset ,
valid ,
2021-03-24 14:10:11 +00:00
) if idx = = self . head_generation = > {
2021-03-23 11:45:32 +00:00
sender . pid = PID ::new ( pid . try_into ( ) . unwrap ( ) ) ;
(
xous_kernel ::MessageEnvelope {
sender : sender . into ( ) ,
body : xous_kernel ::Message ::MutableBorrow ( xous_kernel ::MemoryMessage {
id ,
2021-06-24 09:02:02 +00:00
buf : unsafe { MemoryRange ::new ( server_addr , buf_size ) . ok ( ) } ? ,
2021-03-23 11:45:32 +00:00
offset : MemorySize ::new ( offset ) ,
valid : MemorySize ::new ( valid ) ,
} ) ,
} ,
2021-03-24 14:10:11 +00:00
QueuedMessage ::WaitingReturnMemory (
pid ,
tid ,
idx ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-24 14:10:11 +00:00
client_addr ,
buf_size ,
) ,
2021-03-23 11:45:32 +00:00
)
}
QueuedMessage ::MemoryMessageROLendTerminated (
pid ,
tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-03-23 11:45:32 +00:00
client_addr ,
id ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-23 11:45:32 +00:00
buf_size ,
offset ,
valid ,
2021-03-24 14:10:11 +00:00
) if idx = = self . head_generation = > {
2021-03-23 11:45:32 +00:00
sender . pid = PID ::new ( pid . try_into ( ) . unwrap ( ) ) ;
(
xous_kernel ::MessageEnvelope {
sender : sender . into ( ) ,
body : xous_kernel ::Message ::Borrow ( xous_kernel ::MemoryMessage {
id ,
2021-06-24 09:02:02 +00:00
buf : unsafe { MemoryRange ::new ( server_addr , buf_size ) . ok ( ) } ? ,
2021-03-23 11:45:32 +00:00
offset : MemorySize ::new ( offset ) ,
valid : MemorySize ::new ( valid ) ,
} ) ,
} ,
2021-03-24 14:10:11 +00:00
QueuedMessage ::WaitingReturnMemory (
pid ,
tid ,
idx ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-24 14:10:11 +00:00
client_addr ,
buf_size ,
) ,
2021-03-23 11:45:32 +00:00
)
}
QueuedMessage ::MemoryMessageRWLendTerminated (
pid ,
tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-03-23 11:45:32 +00:00
client_addr ,
id ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-23 11:45:32 +00:00
buf_size ,
offset ,
valid ,
2021-03-24 14:10:11 +00:00
) if idx = = self . head_generation = > {
2021-03-23 11:45:32 +00:00
sender . pid = PID ::new ( pid . try_into ( ) . unwrap ( ) ) ;
(
xous_kernel ::MessageEnvelope {
sender : sender . into ( ) ,
body : xous_kernel ::Message ::MutableBorrow ( xous_kernel ::MemoryMessage {
id ,
2021-06-24 09:02:02 +00:00
buf : unsafe { MemoryRange ::new ( server_addr , buf_size ) . ok ( ) } ? ,
2021-03-23 11:45:32 +00:00
offset : MemorySize ::new ( offset ) ,
valid : MemorySize ::new ( valid ) ,
} ) ,
} ,
2021-03-24 14:10:11 +00:00
QueuedMessage ::WaitingReturnMemory (
pid ,
tid ,
idx ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-24 14:10:11 +00:00
client_addr ,
buf_size ,
) ,
2021-03-23 11:45:32 +00:00
)
}
QueuedMessage ::BlockingScalarMessage (
pid ,
tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-03-23 11:45:32 +00:00
client_addr ,
id ,
arg1 ,
arg2 ,
arg3 ,
arg4 ,
2021-03-24 14:10:11 +00:00
) if idx = = self . head_generation = > {
2021-03-23 11:45:32 +00:00
sender . pid = PID ::new ( pid . try_into ( ) . unwrap ( ) ) ;
(
xous_kernel ::MessageEnvelope {
sender : sender . into ( ) ,
body : xous_kernel ::Message ::BlockingScalar (
xous_kernel ::ScalarMessage {
id ,
arg1 ,
arg2 ,
arg3 ,
arg4 ,
} ,
) ,
} ,
2021-03-24 14:10:11 +00:00
QueuedMessage ::WaitingReturnScalar ( pid , tid , idx , client_addr ) ,
2021-03-23 11:45:32 +00:00
)
}
QueuedMessage ::MemoryMessageSend (
pid ,
_tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-03-23 11:45:32 +00:00
_reserved ,
id ,
2021-04-05 10:18:48 +00:00
server_addr ,
2021-03-23 11:45:32 +00:00
buf_size ,
offset ,
valid ,
2021-03-24 14:10:11 +00:00
) if idx = = self . head_generation = > {
2021-03-23 11:45:32 +00:00
sender . pid = PID ::new ( pid . try_into ( ) . unwrap ( ) ) ;
let msg = xous_kernel ::MessageEnvelope {
2021-01-03 10:31:51 +00:00
sender : sender . into ( ) ,
2021-03-23 11:45:32 +00:00
body : xous_kernel ::Message ::Move ( xous_kernel ::MemoryMessage {
2021-01-03 10:31:51 +00:00
id ,
2021-06-24 09:02:02 +00:00
buf : unsafe { MemoryRange ::new ( server_addr , buf_size ) . ok ( ) } ? ,
2021-01-03 10:31:51 +00:00
offset : MemorySize ::new ( offset ) ,
valid : MemorySize ::new ( valid ) ,
} ) ,
2021-03-23 11:45:32 +00:00
} ;
self . queue [ queue_idx ] = QueuedMessage ::Empty ;
if queue_idx = = self . queue_tail {
self . queue_tail + = 1 ;
if self . queue_tail > = self . queue . len ( ) {
self . queue_tail = 0 ;
}
}
2021-03-24 14:10:11 +00:00
self . head_generation = self . head_generation . wrapping_add ( 1 ) ;
2021-03-23 11:45:32 +00:00
return Some ( msg ) ;
}
// Scalar messages have nothing to return, so they can go straight to the `Free` state
2021-03-24 14:10:11 +00:00
QueuedMessage ::ScalarMessage (
pid ,
_tid ,
idx ,
_reserved ,
id ,
arg1 ,
arg2 ,
arg3 ,
arg4 ,
) if idx = = self . head_generation = > {
2021-03-23 11:45:32 +00:00
sender . pid = PID ::new ( pid . try_into ( ) . unwrap ( ) ) ;
let msg = xous_kernel ::MessageEnvelope {
2021-01-03 10:31:51 +00:00
sender : sender . into ( ) ,
2021-03-23 11:45:32 +00:00
body : xous_kernel ::Message ::Scalar ( xous_kernel ::ScalarMessage {
2021-01-03 10:31:51 +00:00
id ,
2021-03-23 11:45:32 +00:00
arg1 ,
arg2 ,
arg3 ,
arg4 ,
2021-01-03 10:31:51 +00:00
} ) ,
2021-03-23 11:45:32 +00:00
} ;
self . queue [ queue_idx ] = QueuedMessage ::Empty ;
if queue_idx = = self . queue_tail {
self . queue_tail + = 1 ;
if self . queue_tail > = self . queue . len ( ) {
self . queue_tail = 0 ;
}
}
2021-03-24 14:10:11 +00:00
self . head_generation = self . head_generation . wrapping_add ( 1 ) ;
2021-03-23 11:45:32 +00:00
return Some ( msg ) ;
}
QueuedMessage ::BlockingScalarTerminated (
pid ,
_tid ,
2021-03-24 14:10:11 +00:00
idx ,
2021-03-23 11:45:32 +00:00
_reserved ,
id ,
arg1 ,
arg2 ,
arg3 ,
arg4 ,
2021-03-24 14:10:11 +00:00
) if idx = = self . head_generation = > {
2021-03-23 11:45:32 +00:00
sender . pid = PID ::new ( pid . try_into ( ) . unwrap ( ) ) ;
let msg = xous_kernel ::MessageEnvelope {
2021-01-03 10:31:51 +00:00
sender : sender . into ( ) ,
2021-03-23 11:45:32 +00:00
body : xous_kernel ::Message ::Scalar ( xous_kernel ::ScalarMessage {
2021-01-03 10:31:51 +00:00
id ,
arg1 ,
arg2 ,
arg3 ,
arg4 ,
} ) ,
2021-03-23 11:45:32 +00:00
} ;
self . queue [ queue_idx ] = QueuedMessage ::Empty ;
if queue_idx = = self . queue_tail {
self . queue_tail + = 1 ;
if self . queue_tail > = self . queue . len ( ) {
self . queue_tail = 0 ;
}
}
2021-03-24 14:10:11 +00:00
self . head_generation = self . head_generation . wrapping_add ( 1 ) ;
2021-03-23 11:45:32 +00:00
return Some ( msg ) ;
2021-01-03 10:31:51 +00:00
}
2021-03-24 14:10:11 +00:00
_ = > {
queue_idx + = 1 ;
if queue_idx > = self . queue . len ( ) {
queue_idx = 0 ;
}
if queue_idx = = self . queue_tail {
// panic!("Couldn't find the message in the queue! Queue contents: {:?}", self.queue);
return None ;
}
continue ;
}
2021-03-23 11:45:32 +00:00
} ;
2021-01-03 10:31:51 +00:00
2021-03-24 14:10:11 +00:00
if queue_idx = = self . queue_tail {
self . queue_tail + = 1 ;
if self . queue_tail > = self . queue . len ( ) {
self . queue_tail = 0 ;
}
}
2021-03-23 11:45:32 +00:00
self . queue [ queue_idx ] = response ;
2021-03-24 14:10:11 +00:00
self . head_generation = self . head_generation . wrapping_add ( 1 ) ;
2021-03-23 11:45:32 +00:00
return Some ( result ) ;
}
2021-01-03 10:31:51 +00:00
}
/// Add the given message to this server's queue.
///
/// # Errors
///
/// * **ServerQueueFull**: The server queue cannot accept any more messages
pub fn queue_message (
& mut self ,
pid : PID ,
2021-03-24 14:10:11 +00:00
tid : TID ,
2021-01-03 10:31:51 +00:00
message : xous_kernel ::Message ,
original_address : Option < MemoryAddress > ,
) -> core ::result ::Result < usize , xous_kernel ::Error > {
2021-03-23 11:45:32 +00:00
// klog!(
2022-05-29 10:47:37 +00:00
// "Queueing message: {:?} from pid: {} tid: {}",
2021-03-23 11:45:32 +00:00
// message,
// pid.get(),
2021-03-24 14:10:11 +00:00
// tid
2021-03-23 11:45:32 +00:00
// );
2021-03-24 14:10:11 +00:00
// If the head and the tail generations will end up the same, then
// the queue is full.
if self . tail_generation = = self . head_generation . wrapping_sub ( 1 ) {
2021-08-06 02:03:12 +00:00
return Err ( xous_kernel ::Error ::ServerQueueFull ) ;
2021-01-03 10:31:51 +00:00
}
2021-03-24 14:10:11 +00:00
// Look through the queue, beginning at the queue head, for an empty slot.
let mut discovered_index = None ;
for queue_idx in self . queue_head .. self . queue . len ( ) {
if self . queue [ queue_idx ] = = QueuedMessage ::Empty {
discovered_index = Some ( queue_idx ) ;
break ;
}
}
if discovered_index . is_none ( ) {
for queue_idx in 0 .. self . queue_head {
if self . queue [ queue_idx ] = = QueuedMessage ::Empty {
discovered_index = Some ( queue_idx ) ;
break ;
}
}
}
if discovered_index . is_none ( ) {
2021-08-06 02:03:12 +00:00
return Err ( xous_kernel ::Error ::ServerQueueFull ) ;
2021-03-24 14:10:11 +00:00
}
let queue_idx = discovered_index . unwrap ( ) ;
let queue_entry = & mut self . queue [ queue_idx ] ;
* queue_entry = match message {
2021-01-03 10:31:51 +00:00
xous_kernel ::Message ::Scalar ( msg ) = > QueuedMessage ::ScalarMessage (
pid . get ( ) as _ ,
2021-03-24 14:10:11 +00:00
tid as _ ,
self . tail_generation ,
2021-04-05 10:18:48 +00:00
0 ,
2021-01-03 10:31:51 +00:00
msg . id ,
msg . arg1 ,
msg . arg2 ,
msg . arg3 ,
msg . arg4 ,
) ,
xous_kernel ::Message ::BlockingScalar ( msg ) = > QueuedMessage ::BlockingScalarMessage (
pid . get ( ) as _ ,
2021-03-24 14:10:11 +00:00
tid as _ ,
self . tail_generation ,
2021-04-05 10:18:48 +00:00
0 ,
2021-01-03 10:31:51 +00:00
msg . id ,
msg . arg1 ,
msg . arg2 ,
msg . arg3 ,
msg . arg4 ,
) ,
xous_kernel ::Message ::Move ( msg ) = > QueuedMessage ::MemoryMessageSend (
pid . get ( ) as _ ,
2021-03-24 14:10:11 +00:00
tid as _ ,
self . tail_generation ,
2021-01-03 10:31:51 +00:00
original_address . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) ,
msg . id ,
2021-06-24 09:41:16 +00:00
msg . buf . as_ptr ( ) as _ ,
msg . buf . len ( ) ,
2021-01-03 10:31:51 +00:00
msg . offset . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) as usize ,
msg . valid . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) as usize ,
) ,
xous_kernel ::Message ::MutableBorrow ( msg ) = > QueuedMessage ::MemoryMessageRWLend (
pid . get ( ) as _ ,
2021-03-24 14:10:11 +00:00
tid as _ ,
self . tail_generation ,
2021-01-03 10:31:51 +00:00
original_address . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) ,
msg . id ,
2021-06-24 09:41:16 +00:00
msg . buf . as_ptr ( ) as _ ,
msg . buf . len ( ) ,
2021-01-03 10:31:51 +00:00
msg . offset . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) as usize ,
msg . valid . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) as usize ,
) ,
xous_kernel ::Message ::Borrow ( msg ) = > QueuedMessage ::MemoryMessageROLend (
pid . get ( ) as _ ,
2021-03-24 14:10:11 +00:00
tid as _ ,
self . tail_generation ,
2021-01-03 10:31:51 +00:00
original_address . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) ,
msg . id ,
2021-06-24 09:41:16 +00:00
msg . buf . as_ptr ( ) as _ ,
msg . buf . len ( ) ,
2021-01-03 10:31:51 +00:00
msg . offset . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) as usize ,
msg . valid . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) as usize ,
) ,
} ;
2021-03-24 14:10:11 +00:00
// Advance the tail generation, which is used for incoming messages to keep
// them in sequence.
self . tail_generation = self . tail_generation . wrapping_add ( 1 ) ;
if queue_idx = = self . queue_head {
self . queue_head + = 1 ;
if self . queue_head > = self . queue . len ( ) {
self . queue_head = 0 ;
}
2021-01-03 10:31:51 +00:00
}
2021-03-23 11:45:32 +00:00
// klog!(
// "queue head: {} queue_tail: {}",
// self.queue_head,
// self.queue_tail
// );
2021-03-24 14:10:11 +00:00
Ok ( queue_idx )
2021-01-03 10:31:51 +00:00
}
pub fn queue_response (
& mut self ,
pid : PID ,
2021-03-24 14:10:11 +00:00
tid : TID ,
2021-01-03 10:31:51 +00:00
message : & Message ,
client_address : Option < MemoryAddress > ,
) -> core ::result ::Result < usize , xous_kernel ::Error > {
2021-03-24 14:10:11 +00:00
// klog!("Queueing address message: {:?} (pid: {} tid: {}) tail_gen: {} head_gen: {}", message, pid.get(), tid, self.tail_generation, self.head_generation);
let mut queue_idx = self . queue_head ;
loop {
if self . queue [ queue_idx ] = = QueuedMessage ::Empty {
break ;
}
queue_idx + = 1 ;
if queue_idx > = self . queue . len ( ) {
queue_idx = 0 ;
}
if queue_idx = = self . queue_head {
return Err ( xous_kernel ::Error ::ServerQueueFull ) ;
}
2021-01-03 10:31:51 +00:00
}
2021-03-24 14:10:11 +00:00
self . queue [ queue_idx ] = match message {
2021-01-03 10:31:51 +00:00
xous_kernel ::Message ::Scalar ( _ ) | xous_kernel ::Message ::BlockingScalar ( _ ) = > {
QueuedMessage ::WaitingReturnScalar (
pid . get ( ) as _ ,
2021-03-24 14:10:11 +00:00
tid as _ ,
0 ,
2021-01-03 10:31:51 +00:00
client_address . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) ,
)
}
xous_kernel ::Message ::Move ( msg ) = > {
2021-06-24 09:41:16 +00:00
let server_address = msg . buf . as_ptr ( ) as _ ;
let len = msg . buf . len ( ) ;
2021-01-03 10:31:51 +00:00
QueuedMessage ::WaitingForget (
pid . get ( ) as _ ,
2021-03-24 14:10:11 +00:00
tid as _ ,
0 ,
2021-01-03 10:31:51 +00:00
server_address ,
client_address . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) ,
len ,
)
}
xous_kernel ::Message ::MutableBorrow ( msg ) | xous_kernel ::Message ::Borrow ( msg ) = > {
2021-06-24 09:41:16 +00:00
let server_address = msg . buf . as_ptr ( ) as _ ;
let len = msg . buf . len ( ) ;
2021-01-03 10:31:51 +00:00
QueuedMessage ::WaitingReturnMemory (
pid . get ( ) as _ ,
2021-03-24 14:10:11 +00:00
tid as _ ,
0 ,
2021-01-03 10:31:51 +00:00
server_address ,
client_address . map ( | x | x . get ( ) ) . unwrap_or ( 0 ) ,
len ,
)
}
} ;
2021-03-24 14:10:11 +00:00
if queue_idx = = self . queue_head {
self . queue_head + = 1 ;
if self . queue_head > = self . queue . len ( ) {
self . queue_head = 0 ;
}
2021-01-03 10:31:51 +00:00
}
2021-03-24 14:10:11 +00:00
Ok ( queue_idx )
2021-01-03 10:31:51 +00:00
}
// assert!(
// mem::size_of::<QueuedMessage>() == 32,
// "QueuedMessage was supposed to be 32 bytes, but instead was {} bytes",
// mem::size_of::<QueuedMessage>()
// );
/// 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_thread ( & mut self ) -> Option < TID > {
if self . ready_threads = = 0 {
return None ;
}
let mut test_thread_mask = 1 ;
let mut thread_number = 0 ;
klog! ( " ready threads: 0b{:08b} " , self . ready_threads ) ;
loop {
// If the context mask matches this context number, remove it
// and return the index.
if self . ready_threads & test_thread_mask = = test_thread_mask {
self . ready_threads & = ! test_thread_mask ;
return Some ( thread_number ) ;
}
// Advance to the next slot.
test_thread_mask = test_thread_mask . rotate_left ( 1 ) ;
thread_number + = 1 ;
if test_thread_mask = = 1 {
panic! ( " didn't find a free context, even though there should be one " ) ;
}
}
}
/// Return an available context to the blocking list. This is part of the
/// error condition when a message cannot be handled but the context has
/// already been claimed.
///
/// # Panics
///
/// If the context cannot be returned because it is already blocking.
pub fn return_available_thread ( & mut self , tid : TID ) {
if self . ready_threads & 1 < < tid ! = 0 {
panic! (
" tried to return context {}, but it was already blocking " ,
tid
) ;
}
self . ready_threads | = 1 < < tid ;
}
/// Add the given context to the list of ready and waiting contexts.
pub fn park_thread ( & mut self , tid : TID ) {
klog! ( " parking thread {} " , tid ) ;
assert! ( self . ready_threads & ( 1 < < tid ) = = 0 ) ;
self . ready_threads | = 1 < < tid ;
klog! ( " ready threads now: {:08b} " , self . ready_threads ) ;
}
}