continuing on thread safety

This commit is contained in:
Ulrich Mohr 2024-01-31 15:38:13 +01:00
parent 3e4ba8e5fc
commit 2d8705917c
4 changed files with 63 additions and 24 deletions

View File

@ -3,6 +3,17 @@ type TaskFunction = unsafe extern "C" fn(*mut core::ffi::c_void);
//TODO verify uXX == uintXX_t //TODO verify uXX == uintXX_t
//TODO safe API //TODO safe API
// This is a macro so that the panic is at the right place
#[macro_export]
macro_rules! check_global_threading_available {
() => (
if !crate::osal::global_threading_available() {
panic!("using threaded API outside of threading environment")
}
);
}
extern "C" { extern "C" {
pub fn outbyte(c: u8); pub fn outbyte(c: u8);
//void *create_task(TaskFunction_t taskFunction, void *parameter, size_t stack_size) //void *create_task(TaskFunction_t taskFunction, void *parameter, size_t stack_size)
@ -37,20 +48,20 @@ extern "C" {
} }
pub fn global_threading_available() -> bool { pub fn task_delete_self() {
unsafe{global_threading_available_c() == 1} unsafe {
} delete_task(0 as *const core::ffi::c_void);
pub fn check_global_threading_available() {
if !global_threading_available() {
panic!("using queue outside of threading environment")
} }
} }
pub fn enable_global_threading(){ pub fn global_threading_available() -> bool {
unsafe{enable_global_threading_c()}; unsafe { global_threading_available_c() == 1 }
} }
pub fn disable_global_threading(){ pub fn enable_global_threading() {
unsafe{disable_global_threading_c()}; unsafe { enable_global_threading_c() };
}
pub fn disable_global_threading() {
unsafe { disable_global_threading_c() };
} }

View File

@ -1,4 +1,4 @@
use crate::osal; use crate::{check_global_threading_available, osal};
pub struct MessageQueue<const DEPTH: usize> { pub struct MessageQueue<const DEPTH: usize> {
queue_data: [Message; DEPTH], queue_data: [Message; DEPTH],
@ -18,7 +18,7 @@ impl<const DEPTH: usize> MessageQueue<DEPTH> {
} }
pub fn receive(&self) -> Option<Message> { pub fn receive(&self) -> Option<Message> {
osal::check_global_threading_available(); check_global_threading_available!();
let actual_id = match self.queue_id { let actual_id = match self.queue_id {
None => return None, None => return None,
Some(id) => id, Some(id) => id,
@ -26,7 +26,11 @@ impl<const DEPTH: usize> MessageQueue<DEPTH> {
let mut message: Message = Message::default(); let mut message: Message = Message::default();
let res: u8; let res: u8;
unsafe { unsafe {
//message = core::mem::MaybeUninit::zeroed().assume_init(); // We only return it if the queue received something // safe beacuse:
// OS will write not more than length of message queue elements
// queue was created with size_of::<Message> as length of message queue elements
// in MessageQueue::initialize
// making this pointer access safe as long as OS is holding the contract
let message_pointer: *mut core::ffi::c_void = let message_pointer: *mut core::ffi::c_void =
&mut message as *mut _ as *mut core::ffi::c_void; &mut message as *mut _ as *mut core::ffi::c_void;
res = osal::queue_receive(actual_id, message_pointer); res = osal::queue_receive(actual_id, message_pointer);
@ -39,6 +43,7 @@ impl<const DEPTH: usize> MessageQueue<DEPTH> {
} }
fn initialize(&mut self) { fn initialize(&mut self) {
check_global_threading_available!();
if self.queue_id != None { if self.queue_id != None {
return; return;
} }
@ -53,6 +58,7 @@ impl<const DEPTH: usize> MessageQueue<DEPTH> {
} }
pub fn get_sender(&self) -> MessageQueueSender { pub fn get_sender(&self) -> MessageQueueSender {
check_global_threading_available!();
let mut_self = self as *const Self as *mut Self; //oh look, a C developer wrote this let mut_self = self as *const Self as *mut Self; //oh look, a C developer wrote this
unsafe { (*mut_self).initialize() }; //TODO this might be safe (we are in init), but does not look very good unsafe { (*mut_self).initialize() }; //TODO this might be safe (we are in init), but does not look very good
let queue_id = self.queue_id.expect("Queue uninitialized"); let queue_id = self.queue_id.expect("Queue uninitialized");
@ -68,13 +74,18 @@ impl MessageQueueSender {
} }
pub fn send(&self, message: Message) -> Result<(), ()> { pub fn send(&self, message: Message) -> Result<(), ()> {
osal::check_global_threading_available(); check_global_threading_available!();
let queue_id = match self.queue_id { let queue_id = match self.queue_id {
None => return Err(()), None => return Err(()),
Some(id) => id, Some(id) => id,
}; };
let res: u8; let res: u8;
unsafe { unsafe {
// safe beacuse:
// OS will read not more than length of message queue elements
// queue was created with size_of::<Message> as length of message queue elements
// in MessageQueue::initialize
// making this pointer access safe as long as OS is holding the contract
let message_pointer: *const core::ffi::c_void = let message_pointer: *const core::ffi::c_void =
&message as *const _ as *const core::ffi::c_void; &message as *const _ as *const core::ffi::c_void;
res = osal::queue_send(queue_id, message_pointer); res = osal::queue_send(queue_id, message_pointer);

View File

@ -89,8 +89,17 @@ pub struct TaskExecutor<'a> {
} }
impl<'a> TaskExecutor<'a> { impl<'a> TaskExecutor<'a> {
pub fn init_and_run(&mut self) { /// Initializes all tasks (and the objects contained within them)
//TODO unlock global multitasking mutex /// and starts them.
///
/// It also enables global threading, allowing threading APIs to be used (queues, mutexes etc)
/// See TODO about threading
///
///# Arguments
///
/// * `delete_init_task` - If true, will delete the init task (the task this functions is called in) which means the function will not return
///
pub fn init_and_run(&mut self, delete_init_task: bool) {
let object_manager = TaskObjectManager { let object_manager = TaskObjectManager {
tasks: unsafe { slice::from_raw_parts(self.tasks.as_ptr(), self.tasks.len()) }, tasks: unsafe { slice::from_raw_parts(self.tasks.as_ptr(), self.tasks.len()) },
}; };
@ -98,17 +107,22 @@ impl<'a> TaskExecutor<'a> {
let _ = task.initialize(&object_manager).unwrap(); let _ = task.initialize(&object_manager).unwrap();
} }
drop(object_manager); drop(object_manager);
crate::fsrc::osal::enable_global_threading();
for task in self.tasks.iter_mut() { for task in self.tasks.iter_mut() {
// we give away a raw pointer, to be called by an OS task // we give away a raw pointer, to be called by an OS task
// while this is generally very broken, we use a reference tied // while this is generally very broken, we use a reference tied
// to our own lifetime and destroy the task when we get dropped // to our own lifetime and destroy the task when we get dropped.
// this way, the reference is guaranteed to be valid over our // this way, the reference is guaranteed to be valid over our
// lifetime while the task is deleted at the end of our lifetime // lifetime while the task is deleted at the end of our lifetime
let task_pointer: *const core::ffi::c_void = *task as *mut _ as *const core::ffi::c_void; //TODO this does work without the "*" in front of the task -> Why?? let task_pointer: *const core::ffi::c_void =
*task as *mut _ as *const core::ffi::c_void; //TODO this does work without the "*" in front of the task -> Why??
let handle; let handle;
unsafe { unsafe {
handle = handle = crate::fsrc::osal::create_task(
crate::fsrc::osal::create_task(task_entry, task_pointer, u32::try_from(task.get_stack_size()).unwrap()); task_entry,
task_pointer,
u32::try_from(task.get_stack_size()).unwrap(),
);
} }
if handle == 0 as *mut core::ffi::c_void { if handle == 0 as *mut core::ffi::c_void {
panic!("could not create Task"); panic!("could not create Task");
@ -116,6 +130,9 @@ impl<'a> TaskExecutor<'a> {
task.set_handle(handle); task.set_handle(handle);
} }
} }
if delete_init_task {
crate::osal::task_delete_self();
}
} }
} }
@ -141,7 +158,7 @@ impl<'a> crate::objectmanager::ObjectManager<'a> for TaskObjectManager<'a> {
impl<'a> Drop for TaskExecutor<'a> { impl<'a> Drop for TaskExecutor<'a> {
fn drop(&mut self) { fn drop(&mut self) {
//TODO lock global multitasking mutex crate::fsrc::osal::disable_global_threading();
for task in self.tasks.iter_mut() { for task in self.tasks.iter_mut() {
unsafe { unsafe {
crate::fsrc::osal::delete_task(task.get_handle()); crate::fsrc::osal::delete_task(task.get_handle());

View File

@ -199,7 +199,7 @@ fn mission() {
tasks: &mut [&mut t1, &mut t2], tasks: &mut [&mut t1, &mut t2],
}; };
task_executor.init_and_run(); task_executor.init_and_run(false);
sifln!("Mission delay"); sifln!("Mission delay");
unsafe { unsafe {