working on thread safety, preparing for static RTOS

This commit is contained in:
Ulrich Mohr 2023-12-12 22:55:22 +01:00
parent c3be10903b
commit 07d9f52b8d
6 changed files with 142 additions and 45 deletions

View File

@ -4,6 +4,29 @@
// TODO namespace the names
SemaphoreHandle_t * global_threading_semaphore = NULL;
uint8_t global_threading_available_c() {
if (global_threading_semaphore == NULL) {
global_threading_semaphore = xSemaphoreCreateBinary();
//xSemaphoreGive(global_threading_semaphore);
}
if (uxSemaphoreGetCount(global_threading_semaphore) == 1) {
return 1;
} else {
return 0;
}
}
void enable_global_threading_c() {
xSemaphoreGive(global_threading_semaphore);
}
void disable_global_threading_c() {
xSemaphoreTake(global_threading_semaphore, portMAX_DELAY);
}
const char *get_task_name() { return pcTaskGetName(NULL); }
void stop_it() { taskENTER_CRITICAL(); }

View File

@ -39,7 +39,7 @@ pub struct ReferencedDataset<T: HasTypeId + Copy> {
mutex: Option<mutex::RawMutex>,
}
impl<T: HasTypeId + Copy> DataSetIF for OwnedDataset<T> {
impl<T: HasTypeId + Copy + Default> DataSetIF for OwnedDataset<T> {
fn get_type_id(&self) -> TypeId {
self.actual_data.get_type_id()
}
@ -49,6 +49,7 @@ impl<T: HasTypeId + Copy> DataSetIF for OwnedDataset<T> {
}
fn get_mutex(&self) -> mutex::RawMutex {
self.initialize();
return self.mutex;
}
}
@ -77,6 +78,10 @@ impl<T: HasTypeId + Copy + Default> OwnedDataset<T> {
};
self.actual_data = data;
}
fn initialize(&mut self) {
}
}
impl<T: HasTypeId + Copy + Default> ReferencedDataset<T> {

View File

@ -1,10 +1,7 @@
use super::osal;
// We allow copy because we protext our pointer via a global mutex
// when using static allocation (which is TBCoded)
#[derive(Clone, Copy)]
pub struct RawMutex {
handle: *const core::ffi::c_void,
handle: Option<*const core::ffi::c_void>
}
pub struct RawMutexGuard {
@ -22,23 +19,50 @@ impl Drop for RawMutexGuard {
// or maybe lazy later on, TBD if lazy is needed or we can guarantee init to be called
impl RawMutex {
pub fn new() -> Self {
let handle = unsafe {osal::create_mutex()};
Self {
handle: handle
handle: None
}
}
pub fn clone(&self) -> Self {
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
Self {
handle: self.handle
}
}
pub fn take(&self) -> Result<RawMutexGuard,()> {
match unsafe {osal::take_mutex(self.handle)} {
1 => Ok(RawMutexGuard { handle: self.handle }),
osal::check_global_threading_available();
let handle = match self.handle {
None => return Err(()), //TODO plan was that this failes silently -> implement an empty mutex guard?
Some(handle) => handle
};
match unsafe {osal::take_mutex(handle)} {
1 => Ok(RawMutexGuard { handle: handle }),
_ => Err(()) //TODO error code
}
}
// Mutex guard takes care of this in its drop
// Do not offer this in API to avoid duplicate give
// pub fn give(&self) -> Result<(),()> {
// match unsafe {osal::give_mutex(self.handle)} {
// osal::check_global_threading_available();
// let handle = match self.handle {
// None => return Ok(()),
// Some(handle) => handle
// };
// match unsafe {osal::give_mutex(handle)} {
// 1 => Ok(()),
// _ => Err(()) //TODO error code
// }
// }
pub fn initialize(&mut self) {
let handle = unsafe {osal::create_mutex()};
if handle == 0 as *const core::ffi::c_void {
panic!("Could not create mutex")
}
self.handle = Some(handle);
}
}

View File

@ -1,6 +1,7 @@
type TaskFunction = unsafe extern "C" fn(*mut core::ffi::c_void);
//TODO verify uXX == uintXX_t
//TODO safe API
extern "C" {
pub fn outbyte(c: u8);
@ -30,4 +31,26 @@ extern "C" {
pub fn take_mutex(mutex: *const core::ffi::c_void) -> u8;
pub fn give_mutex(mutex: *const core::ffi::c_void) -> u8;
fn global_threading_available_c() -> u8;
fn enable_global_threading_c();
fn disable_global_threading_c();
}
pub fn global_threading_available() -> bool {
unsafe{global_threading_available_c() == 1}
}
pub fn check_global_threading_available() {
if !global_threading_available() {
panic!("using queue outside of threading environment")
}
}
pub fn enable_global_threading(){
unsafe{enable_global_threading_c()};
}
pub fn disable_global_threading(){
unsafe{disable_global_threading_c()};
}

View File

@ -1,46 +1,63 @@
pub struct MessageQueue {
queue_id: *const core::ffi::c_void,
use crate::osal;
pub struct MessageQueue<const DEPTH: usize> {
queue_data: [Message; DEPTH],
queue_id: Option<*const core::ffi::c_void>,
}
pub struct MessageQueueSender {
queue_id: Option<*const core::ffi::c_void>,
}
impl MessageQueue {
pub fn new(depth: usize) -> Self {
unsafe {
//TODO check cast of depth
let cast_depth: u32 = u32::try_from(depth).unwrap(); //TODO check these
let element_size: u32 = u32::try_from(core::mem::size_of::<Message>()).unwrap();
let queue_id = crate::fsrc::osal::create_queue(cast_depth, element_size);
if queue_id == 0 as *mut core::ffi::c_void {
panic!("could not create Queue");
}
Self { queue_id: queue_id }
impl<const DEPTH: usize> MessageQueue<DEPTH> {
pub fn new() -> Self {
Self {
queue_data: [Message::default(); DEPTH],
queue_id: None,
}
}
pub fn get_sender(&self) -> MessageQueueSender {
let instance: MessageQueueSender = MessageQueueSender {
queue_id: Some(self.queue_id),
pub fn receive(&self) -> Option<Message> {
osal::check_global_threading_available();
let actual_id = match self.queue_id {
None => return None,
Some(id) => id,
};
instance
}
pub fn receive(&self) -> Result<Message, ()> {
let mut message: Message = Message::default();
let res: u8;
unsafe {
//message = core::mem::MaybeUninit::zeroed().assume_init(); // We only return it if the queue received something
let message_pointer: *mut core::ffi::c_void = &mut message as *mut _ as *mut core::ffi::c_void;
res = crate::fsrc::osal::queue_receive(self.queue_id, message_pointer);
let message_pointer: *mut core::ffi::c_void =
&mut message as *mut _ as *mut core::ffi::c_void;
res = osal::queue_receive(actual_id, message_pointer);
}
if res == 1 {
Ok(message)
Some(message)
} else {
Err(())
None
}
}
fn initialize(&mut self) {
if self.queue_id != None {
return;
}
let cast_depth: u32 = u32::try_from(DEPTH).unwrap(); //TODO check these
let element_size: u32 = u32::try_from(core::mem::size_of::<Message>()).unwrap();
let queue_id = unsafe { osal::create_queue(cast_depth, element_size) };
if queue_id == 0 as *mut core::ffi::c_void {
panic!("could not create Queue");
}
self.queue_id = Some(queue_id);
}
pub fn get_sender(&self) -> MessageQueueSender {
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
let queue_id = self.queue_id.expect("Queue uninitialized");
MessageQueueSender {
queue_id: Some(queue_id),
}
}
}
@ -51,11 +68,16 @@ impl MessageQueueSender {
}
pub fn send(&self, message: Message) -> Result<(), ()> {
let queue_id = self.queue_id.expect("unitialized Message Queue");
osal::check_global_threading_available();
let queue_id = match self.queue_id {
None => return Err(()),
Some(id) => id,
};
let res: u8;
unsafe {
let message_pointer: *const core::ffi::c_void = &message as *const _ as *const core::ffi::c_void;
res = crate::fsrc::osal::queue_send(queue_id, message_pointer);
let message_pointer: *const core::ffi::c_void =
&message as *const _ as *const core::ffi::c_void;
res = osal::queue_send(queue_id, message_pointer);
}
if res == 1 {
Ok(())

View File

@ -1,6 +1,5 @@
#![no_std]
//TODO look into using core::ffi (some types do not seem to work)
//TODO os errors in API calls
//TODO look into a pattern for late initialized stuff, currently using Option (can we make it compile time safe?)
@ -60,7 +59,7 @@ impl datasets::HasTypeId for HandlerData {}
struct Handler {
id: objectmanager::ObjectId,
command_queue: queues::MessageQueue,
command_queue: queues::MessageQueue<10>,
data: datasets::OwnedDataset<HandlerData>
}
@ -94,8 +93,8 @@ impl tasks::ExecutableObjectIF for Handler {
sifln!("Handler {} performs", self.id);
let result = self.command_queue.receive();
match result {
Ok(message) => self.handle_message(message),
Err(_) => {
Some(message) => self.handle_message(message),
None => {
sifln!("Handler {} got nothing", self.id);
}
}
@ -149,8 +148,9 @@ impl DatapoolOwnerIF for HandlerSender {}
impl SystemObjectIF for HandlerSender {
fn get_command_queue(&self) -> crate::fsrc::queues::MessageQueueSender {
queues::MessageQueueSender::new()
queues::MessageQueueSender::new() //TODO
}
fn get_id(&self) -> objectmanager::ObjectId {
self.id
}
@ -173,7 +173,7 @@ fn mission() {
let mut h1 = Handler {
id: 1,
command_queue: queues::MessageQueue::new(5),
command_queue: queues::MessageQueue::new(),
data: datasets::OwnedDataset::new()
};
let mut h2 = HandlerSender {