Merge remote-tracking branch 'origin/master' into ticktimer

This commit is contained in:
bunnie 2020-10-14 15:30:47 +08:00
commit 5cf8e9e3bc
8 changed files with 139 additions and 54 deletions

View file

@ -68,6 +68,10 @@ fn generate_pid_key() -> [u8; 16] {
process_key
}
pub fn current_pid() -> PID {
crate::arch::process::current_pid()
}
/// Each client gets its own connection and its own thread, which is handled here.
fn handle_connection(
conn: TcpStream,

View file

@ -171,6 +171,19 @@ impl Process {
})
}
/// Calls the provided function with the current inner process state.
pub fn with_current_mut<F, R>(f: F) -> R
where
F: FnOnce(&mut Process) -> R,
{
let mut process = Self::current();
f(&mut process)
}
pub fn current_tid(&self) -> TID {
1
}
fn setup_thread_inner(thread: TID, process_table: &mut ProcessTable) {
let current_pid_idx = process_table.current.get() as usize - 1;
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
@ -179,6 +192,10 @@ impl Process {
process.threads[thread - 1].allocated = true;
}
pub fn retry_instruction(&mut self, _tid: TID) -> Result<(), xous_kernel::Error> {
Ok(())
}
pub fn setup_process(pid: PID, setup: ThreadInit) -> Result<(), xous_kernel::Error> {
let mut tmp = Process { pid };
tmp.setup_thread(INITIAL_TID, setup)

View file

@ -235,6 +235,15 @@ impl Process {
}
}
pub fn retry_instruction(&mut self, tid: TID) -> Result<(), xous_kernel::Error> {
let process = unsafe { &mut *PROCESS };
let mut thread = &mut process.threads[tid];
if thread.sepc >= 4 {
thread.sepc -= 4;
}
Ok(())
}
/// Initialize this process thread with the given entrypoint and stack
/// addresses.
pub fn setup_process(pid: PID, thread_init: ThreadInit) -> Result<(), xous_kernel::Error> {

View file

@ -25,6 +25,8 @@ mod syscall;
use services::SystemServices;
use xous_kernel::*;
#[cfg(baremetal)]
use utralib::generated::*;
#[cfg(baremetal)]

View file

@ -10,6 +10,25 @@ use xous_kernel::*;
/// This is the context that called SwitchTo
static mut SWITCHTO_CALLER: Option<(PID, TID)> = None;
fn do_yield(_pid: PID, tid: TID) -> SysCallResult {
// If we're not running on bare metal, treat this as a no-op.
if !cfg!(baremetal) {
return Ok(xous_kernel::Result::Ok);
}
let (parent_pid, parent_ctx) = unsafe {
SWITCHTO_CALLER
.take()
.expect("yielded when no parent context was present")
};
SystemServices::with_mut(|ss| {
// TODO: Advance thread
ss.activate_process_thread(tid, parent_pid, parent_ctx, true)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
})
}
fn send_message(pid: PID, thread: TID, cid: CID, message: Message) -> SysCallResult {
SystemServices::with_mut(|ss| {
let sidx = ss
@ -279,7 +298,12 @@ fn return_memory(pid: PID, tid: TID, sender: MessageSender, buf: MemoryRange) ->
})
}
fn return_scalar(pid: PID, _tid: TID, sender: MessageSender, arg: usize) -> SysCallResult {
fn return_scalar(
server_pid: PID,
server_tid: TID,
sender: MessageSender,
arg: usize,
) -> SysCallResult {
SystemServices::with_mut(|ss| {
let sender = SenderID::from(sender);
@ -289,7 +313,7 @@ fn return_scalar(pid: PID, _tid: TID, sender: MessageSender, arg: usize) -> SysC
let server = ss
.server_from_sidx_mut(sidx)
.ok_or(xous_kernel::Error::ServerNotFound)?;
if server.pid != pid {
if server.pid != server_pid {
return Err(xous_kernel::Error::ServerNotFound);
}
let result = server.take_waiting_message(sender.idx, None)?;
@ -318,10 +342,27 @@ fn return_scalar(pid: PID, _tid: TID, sender: MessageSender, arg: usize) -> SysC
return Err(xous_kernel::Error::ProcessNotFound);
}
};
ss.ready_thread(client_pid, client_tid)?;
ss.switch_to_thread(client_pid, Some(client_tid))?;
ss.set_thread_result(client_pid, client_tid, xous_kernel::Result::Scalar1(arg))?;
Ok(xous_kernel::Result::Scalar1(arg))
if !cfg!(baremetal) {
// In a hosted environment, `switch_to_thread()` doesn't continue
// execution from the new thread. Instead it continues in the old
// thread. Therefore, we need to instruct the client to resume, and
// return to the server.
// In a baremetal environment, the opposite is true -- we instruct
// the server to resume and return to the client.
ss.set_thread_result(client_pid, client_tid, xous_kernel::Result::Scalar1(arg))?;
Ok(xous_kernel::Result::Ok)
} else {
// Switch away from the server, but leave it as Runnable
ss.switch_from_thread(server_pid, server_tid)?;
ss.ready_thread(server_pid, server_tid)?;
ss.set_thread_result(server_pid, server_tid, xous_kernel::Result::Ok)?;
// Switch to the client
ss.ready_thread(client_pid, client_tid)?;
ss.switch_to_thread(client_pid, Some(client_tid))?;
Ok(xous_kernel::Result::Scalar1(arg))
}
})
}
@ -368,22 +409,31 @@ fn return_scalar2(
return Err(xous_kernel::Error::ProcessNotFound);
}
};
ss.ready_thread(client_pid, client_tid)?;
ss.ready_thread(server_pid, server_tid)?;
/*
ss.activate_process_thread(server_tid, client_pid, client_tid, false)
.map(|_| Ok(xous_kernel::Result::Scalar2(arg1, arg2)))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))?;*/
//ss.switch_from_thread(server_pid, server_tid)?;
if !cfg!(baremetal) {
// In a hosted environment, `switch_to_thread()` doesn't continue
// execution from the new thread. Instead it continues in the old
// thread. Therefore, we need to instruct the client to resume, and
// return to the server.
// In a baremetal environment, the opposite is true -- we instruct
// the server to resume and return to the client.
ss.set_thread_result(
client_pid,
client_tid,
xous_kernel::Result::Scalar2(arg1, arg2),
)?;
Ok(xous_kernel::Result::Ok)
} else {
// Switch away from the server, but leave it as Runnable
ss.switch_from_thread(server_pid, server_tid)?;
ss.ready_thread(server_pid, server_tid)?;
ss.set_thread_result(server_pid, server_tid, xous_kernel::Result::Ok)?;
ss.switch_to_thread(client_pid, Some(client_tid))?;
ss.set_thread_result(
client_pid,
client_tid,
xous_kernel::Result::Scalar2(arg1, arg2),
)?;
Ok(xous_kernel::Result::Scalar2(arg1, arg2))
// Switch to the client
ss.ready_thread(client_pid, client_tid)?;
ss.switch_to_thread(client_pid, Some(client_tid))?;
Ok(xous_kernel::Result::Scalar2(arg1, arg2))
}
})
}
@ -446,7 +496,12 @@ pub fn handle(pid: PID, tid: TID, call: SysCall) -> SysCallResult {
print!("KERNEL({}:{}): Syscall {:x?}", pid, tid, call);
let result = handle_inner(pid, tid, call);
#[cfg(feature = "debug-print")]
println!(" -> {:x?}", result);
println!(
" -> ({}:{}) {:?}",
crate::arch::current_pid(),
crate::arch::process::Process::current().current_tid(),
result
);
result
}
@ -598,24 +653,7 @@ pub fn handle_inner(pid: PID, tid: TID, call: SysCall) -> SysCallResult {
interrupt_claim(no, pid as definitions::PID, callback, arg)
.map(|_| xous_kernel::Result::Ok)
}
SysCall::Yield => {
// If we're not running on bare metal, treat this as a no-op.
if !cfg!(baremetal) {
return Ok(xous_kernel::Result::Ok);
}
let (parent_pid, parent_ctx) = unsafe {
SWITCHTO_CALLER
.take()
.expect("yielded when no parent context was present")
};
SystemServices::with_mut(|ss| {
// TODO: Advance thread
ss.activate_process_thread(tid, parent_pid, parent_ctx, true)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
})
}
SysCall::Yield => do_yield(pid, tid),
SysCall::ReturnToParentI(_pid, _cpuid) => {
unsafe {
// let (_current_pid, _current_ctx) = crate::arch::irq::take_isr_return_pair()
@ -679,7 +717,17 @@ pub fn handle_inner(pid: PID, tid: TID, call: SysCall) -> SysCallResult {
// SysCall::Connect(sid) => {
// SystemServices::with_mut(|ss| ss.connect_to_server(sid).map(xous_kernel::Result::ConnectionID))
// }
// SysCall::SendMessage(cid, message) => send_message(pid, tid, cid, message),
SysCall::SendMessage(cid, message) => {
let result = send_message(pid, tid, cid, message);
match result {
Ok(o) => Ok(o),
Err(xous_kernel::Error::ServerQueueFull) => {
arch::process::Process::with_current_mut(|p| p.retry_instruction(tid))?;
do_yield(pid, tid)
}
Err(e) => Err(e),
}
}
_ => panic!("Unhandled Syscall: {:?}", call), //Err(xous_kernel::Error::UnhandledSyscall),
}
}

View file

@ -3,24 +3,24 @@
pub mod api;
pub use api::{Point, Color};
use xous::{try_send_message, CID};
use xous::{send_message, CID};
pub fn draw_line(cid: CID, start: Point, end: Point) -> Result<(), xous::Error> {
try_send_message(cid, api::Opcode::Line(start, end).into()).map(|_| ())
send_message(cid, api::Opcode::Line(start, end).into()).map(|_| ())
}
pub fn draw_circle(cid: CID, center: Point, radius: u32) -> Result<(), xous::Error> {
try_send_message(cid, api::Opcode::Circle(center, radius).into()).map(|_| ())
send_message(cid, api::Opcode::Circle(center, radius).into()).map(|_| ())
}
pub fn draw_rectangle(cid: CID, start: Point, end: Point) -> Result<(), xous::Error> {
try_send_message(cid, api::Opcode::Rectangle(start, end).into()).map(|_| ())
send_message(cid, api::Opcode::Rectangle(start, end).into()).map(|_| ())
}
pub fn set_style(cid: CID, width: u32, stroke: Color, fill: Color) -> Result<(), xous::Error> {
try_send_message(cid, api::Opcode::Style(width, stroke, fill).into()).map(|_| ())
send_message(cid, api::Opcode::Style(width, stroke, fill).into()).map(|_| ())
}
pub fn flush(cid: CID) -> Result<(), xous::Error> {
try_send_message(cid, api::Opcode::Flush.into()).map(|_| ())
send_message(cid, api::Opcode::Flush.into()).map(|_| ())
}

View file

@ -981,21 +981,26 @@ pub fn try_send_message(connection: CID, message: Message) -> core::result::Resu
}
}
/// Send a message to a server, but keep trying if the server queue is full.
/// Send a message to a server. Depending on the mesage type (move or borrow), it
/// will either block (borrow) or return immediately (move).
/// If the message type is `borrow`, then the memory addresses pointed to will be
/// unavailable to this process until this function returns.
///
/// If the server queue is full, this will block.
///
/// # Errors
///
/// * **ServerNotFound**: The server does not exist so the connection is now invalid
/// * **BadAddress**: The client tried to pass a Memory message using an address it doesn't own
/// * **Timeout**: The timeout limit has been reached
pub fn send_message(connection: CID, message: Message) -> core::result::Result<(), Error> {
pub fn send_message(connection: CID, message: Message) -> core::result::Result<Result, Error> {
let result = rsyscall(SysCall::SendMessage(connection, message));
if let Ok(Result::Ok) = result {
Ok(())
} else if let Err(e) = result {
Err(e)
} else {
panic!("Unexpected return value: {:?}", result);
match result {
Ok(Result::Ok) => Ok(Result::Ok),
Ok(Result::Scalar1(a)) => Ok(Result::Scalar1(a)),
Ok(Result::Scalar2(a, b)) => Ok(Result::Scalar2(a, b)),
Err(e) => Err(e),
v => panic!("Unexpected return value: {:?}", v),
}
}