kernel: fix hosted mode

The process scheduler changed in subtle ways taht completely broke
hosted mode.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2023-01-31 11:24:09 +08:00
parent ca2a47e67f
commit fc8d78c2ec
4 changed files with 82 additions and 47 deletions

View file

@ -95,12 +95,6 @@ fn handle_connection(
chn: Sender<ThreadMessage>,
should_exit: std::sync::Arc<core::sync::atomic::AtomicBool>,
) {
// enum ServerMessage {
// Exit,
// ServerPacket(Box<SysCall>),
// ServerPacketWithData([usize; 9], Vec<u8>),
// }
fn conn_thread(mut conn: TcpStream, sender: Sender<ThreadMessage>, pid: PID) {
loop {
let mut raw_data = [0u8; 9 * std::mem::size_of::<usize>()];
@ -184,8 +178,6 @@ fn handle_connection(
}
}
// let (sender, receiver) = unbounded();
// let conn_sender = sender.clone();
let conn_sender = chn.clone();
let conn_thread = std::thread::Builder::new()
.name(format!("PID {}: client connection thread", pid))
@ -267,7 +259,6 @@ fn listen_thread(
let NewPidMessage::NewPid(new_pid) = new_pid_channel
.recv()
.expect("couldn't receive message from main thread");
// println!("KERNEL({}): New client connected from {}", new_pid, _addr);
let conn_copy = conn.try_clone().expect("couldn't duplicate connection");
let should_exit = should_exit.clone();
let jh = std::thread::Builder::new()
@ -506,6 +497,17 @@ pub fn idle() -> bool {
// println!("KERNEL: Done sending");
}
{
let current_process = crate::arch::process::Process::current();
if current_process.thread_exists(thread_id) {
SystemServices::with_mut(|ss| {
ss.switch_to_thread(pid, Some(thread_id))
})
.unwrap();
crate::arch::process::Process::current().set_tid(thread_id).unwrap();
}
}
// Handle the syscall within the Xous kernel
let response = crate::syscall::handle(pid, thread_id, false, call)
.unwrap_or_else(Result::Error);

View file

@ -222,35 +222,22 @@ impl Process {
PROCESS_TABLE.with(|pt| {
let process_table = &mut *pt.borrow_mut();
Self::setup_thread_inner(thread, process_table);
// println!(
// "KERNEL({}): self.contexts[{}].allocated = {}",
// current_pid_idx,
// context - 1,
// process.contexts[context - 1].allocated
// );
});
Ok(())
}
// pub fn current_thread(&mut self) -> TID {
// PROCESS_TABLE.with(|pt| {
// let mut process_table = pt.borrow_mut();
// let current_pid_idx = process_table.current.get() as usize - 1;
// let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
// process.current_context
// })
// }
/// Set the current context number.
/// Set the current thread ID.
pub fn set_tid(&mut self, thread: TID) -> Result<(), xous_kernel::Error> {
assert!(thread > 0);
PROCESS_TABLE.with(|pt| {
let mut process_table = pt.borrow_mut();
let current_pid_idx = process_table.current.get() as usize - 1;
let current_pid = process_table.current.get();
let current_pid_idx = current_pid as usize - 1;
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
assert!(
process.threads[thread - 1].allocated,
"tried to switch to thread {} which wasn't allocated",
"process {} tried to switch to thread {} which wasn't allocated",
current_pid,
thread
);
process.current_thread = thread;
@ -273,8 +260,20 @@ impl Process {
})
}
pub fn thread_exists(&self, _tid: TID) -> bool {
false
pub fn thread_exists(&self, tid: TID) -> bool {
if tid == 0 {
return false;
}
PROCESS_TABLE.with(|pt| {
let process_table = pt.borrow();
let current_pid = process_table.current.get();
let current_pid_idx = current_pid as usize - 1;
if let Some(Some(process)) = process_table.table.get(current_pid_idx) {
process.threads.get(tid - 1).map(|t| t.allocated).unwrap_or(false)
} else {
false
}
})
}
pub fn set_thread_result(&mut self, tid: TID, result: xous_kernel::Result) {
@ -283,11 +282,11 @@ impl Process {
let mut process_table = pt.borrow_mut();
let current_pid_idx = process_table.current.get() as usize - 1;
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
assert!(
process.threads[tid - 1].allocated,
"thread {} is not allocated",
tid,
);
// assert!(
// process.threads[tid - 1].allocated,
// "thread {} is not allocated",
// tid,
// );
let mut response = vec![];
// Add the destination thread ID to the start of the packet.
@ -305,7 +304,11 @@ impl Process {
}
// If there is memory to return for this thread, also return that.
if let Some(buf) = process.memory_to_return[tid - 1].take() {
if let Some(buf) = process
.memory_to_return
.get_mut(tid - 1)
.and_then(|v| v.take())
{
if result.memory().is_some() {
panic!("Result has memory and we're also returning memory!");
}

View file

@ -698,6 +698,7 @@ impl SystemServices {
Ok(())
}
#[cfg(target_pointer_width = "32")]
pub fn find_next_thread(thread_mask: usize, current_thread: usize) -> usize {
// From https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
// This platform has a multiplier, so this is fast
@ -727,6 +728,23 @@ impl SystemServices {
}
}
#[cfg(not(target_pointer_width = "32"))]
pub fn find_next_thread(thread_mask: usize, current_thread: usize) -> usize {
if thread_mask == 0 {
panic!("no threads were available to run");
}
if thread_mask.is_power_of_two() {
thread_mask.trailing_zeros() as usize
} else {
let upper_bits = thread_mask & !((2usize << current_thread) - 1);
if upper_bits != 0 {
upper_bits.trailing_zeros() as usize
} else {
thread_mask.trailing_zeros() as usize
}
}
}
/// Mark the current process as "Ready to run".
///
/// # Panics
@ -815,6 +833,8 @@ impl SystemServices {
}
// Activate this process on this CPU
#[cfg(not(target_os = "xous"))]
process.activate()?;
ArchProcess::current().set_tid(new_thread)?;
process.current_thread = new_thread as _;
ProcessState::Running(ready_threads & !(1 << new_thread))
@ -1549,7 +1569,6 @@ impl SystemServices {
// println!("KERNEL({}): Created new thread {}", pid, new_tid);
// let old_state = process.state;
// Queue the thread to run
process.state = match process.state {
ProcessState::Running(x) => ProcessState::Running(x | (1 << new_tid)),
@ -1825,15 +1844,21 @@ impl SystemServices {
// existing connection
for (connection_idx, server_idx) in process_inner.connection_map.iter().enumerate() {
// If we find an empty slot, use it
if server_idx.is_none() {
let Some(server_idx) = server_idx else {
if slot_idx.is_none() {
slot_idx = Some(connection_idx);
}
continue;
};
let server_idx = server_idx.get() as usize;
// Tombstone or unallocated server index
if server_idx < 2 {
continue;
}
// If a connection to this server ID exists already, return it.
let server_idx = (server_idx.unwrap().get() as usize) - 2;
let server_idx = server_idx - 2;
if let Some(allocated_server) = &self.servers[server_idx] {
if allocated_server.sid == sid {
// println!("KERNEL({}): Existing connection to SID {:?} found in this process @ {}, process connection map is: {:?}",

View file

@ -179,6 +179,7 @@ fn send_message(pid: PID, tid: TID, cid: CID, message: Message) -> SysCallResult
// Mark the server's context as "Ready". If this fails, return the context
// to the blocking list.
#[cfg(target_os = "xous")]
ss.ready_thread(server_pid, server_tid).map_err(|e| {
ss.server_from_sidx_mut(sidx)
.expect("server couldn't be located")
@ -366,6 +367,7 @@ fn return_memory(
if !cfg!(baremetal) || in_irq || !client_is_runnable {
// Send a message to the client, in order to wake it up
// print!(" [waking up PID {}:{}]", client_pid, client_tid);
#[cfg(baremetal)]
ss.ready_thread(client_pid, client_tid)?;
#[cfg(not(baremetal))]
ss.switch_to_thread(client_pid, Some(client_tid))?;
@ -724,7 +726,7 @@ fn reply_and_receive_next(
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
} else {
// Switch to the client and return the result
ss.ready_thread(response.pid, response.tid)?;
//ss.ready_thread(response.pid, response.tid)?;
ss.switch_to_thread(response.pid, Some(response.tid))?;
ss.set_thread_result(response.pid, response.tid, response.result)?;
@ -1057,16 +1059,19 @@ pub fn handle_inner(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallR
}),
SysCall::CreateThread(thread_init) => SystemServices::with_mut(|ss| {
ss.create_thread(pid, thread_init).map(|new_tid| {
// Immediately switch to the new thread
ss.switch_to_thread(pid, Some(new_tid))
.expect("couldn't activate new thread");
// Set the return value of the existing thread to be the new thread ID
ss.set_thread_result(pid, tid, xous_kernel::Result::ThreadID(new_tid))
.expect("couldn't set new thread ID");
if cfg!(target_os = "xous") {
// Immediately switch to the new thread
ss.switch_to_thread(pid, Some(new_tid))
.expect("couldn't activate new thread");
ss.set_thread_result(pid, tid, xous_kernel::Result::ThreadID(new_tid))
.expect("couldn't set new thread ID");
// Return `ResumeProcess` since we're switching threads
xous_kernel::Result::ResumeProcess
// Return `ResumeProcess` since we're switching threads
xous_kernel::Result::ResumeProcess
} else {
xous_kernel::Result::ThreadID(new_tid)
}
})
}),
SysCall::CreateProcess(process_init) => SystemServices::with_mut(|ss| {