diff --git a/mission/freeRTOS_rust_helper.c b/mission/freeRTOS_rust_helper.c index 6518fbb..4e841a4 100644 --- a/mission/freeRTOS_rust_helper.c +++ b/mission/freeRTOS_rust_helper.c @@ -4,7 +4,7 @@ // TODO namespace the names -SemaphoreHandle_t * global_threading_semaphore = NULL; +SemaphoreHandle_t global_threading_semaphore = NULL; uint8_t global_threading_available_c() { if (global_threading_semaphore == NULL) { diff --git a/mission_rust/src/fsrc/datasets/mod.rs b/mission_rust/src/fsrc/datasets/mod.rs index a0c7841..eeb5065 100644 --- a/mission_rust/src/fsrc/datasets/mod.rs +++ b/mission_rust/src/fsrc/datasets/mod.rs @@ -1,12 +1,14 @@ -use super::{mutex, objectmanager}; +use crate::check_global_threading_available; + use super::objectmanager::SystemObjectIF; +use super::{mutex, objectmanager}; #[derive(Copy, Clone, PartialEq)] pub struct TypeId { id: usize, } -// inspired by https://github.com/jswrenn/deflect/ +// inspired by Jack Wrenn at https://github.com/jswrenn/deflect/ pub trait HasTypeId { #[inline(never)] fn get_type_id(&self) -> TypeId { @@ -28,33 +30,34 @@ pub trait DataSetIF { fn get_mutex(&self) -> mutex::RawMutex; } -pub struct OwnedDataset { +pub struct OwnedDataset { actual_data: T, mutex: mutex::RawMutex, } -pub struct ReferencedDataset { +pub struct ReferencedDataset { //we use a pointer here to avoid lifetimes actual_data: Option<*const T>, mutex: Option, } -impl DataSetIF for OwnedDataset { +impl DataSetIF for OwnedDataset { fn get_type_id(&self) -> TypeId { self.actual_data.get_type_id() } fn get_actual_data(&self) -> &dyn HasTypeId { + // only return pointer when threading + check_global_threading_available!(); &self.actual_data } fn get_mutex(&self) -> mutex::RawMutex { - self.initialize(); - return self.mutex; + return self.mutex.clone(); } } -impl OwnedDataset { +impl OwnedDataset { pub fn new() -> OwnedDataset { OwnedDataset:: { actual_data: T::default(), @@ -62,12 +65,19 @@ impl OwnedDataset { } } + pub fn new_default(default_values: T) -> OwnedDataset { + OwnedDataset:: { + actual_data: default_values, + mutex: mutex::RawMutex::new(), + } + } + pub fn read(&mut self) -> Result { let _mutex_guard = match self.mutex.take() { Err(()) => return Err(()), Ok(guard) => guard, }; - Ok(self.actual_data) + Ok(self.actual_data.clone()) } //TODO do we want to know if it fails? @@ -79,12 +89,10 @@ impl OwnedDataset { self.actual_data = data; } - fn initialize(&mut self) { - - } + fn initialize(&mut self) {} } -impl ReferencedDataset { +impl ReferencedDataset { pub fn new() -> ReferencedDataset { ReferencedDataset:: { actual_data: None, @@ -93,33 +101,36 @@ impl ReferencedDataset { } pub fn read(&mut self) -> Result { - let _mutex_guard = match self.mutex { + let _mutex_guard = match &self.mutex { None => return Err(()), Some(mutex) => match mutex.take() { Err(()) => return Err(()), Ok(guard) => guard, }, }; - match self.actual_data { - None => Err(()), - Some(data) => Ok(unsafe { *data }), - } + let pointer = match self.actual_data { + None => return Err(()), + Some(data) => data, + }; + // we are only allowed to use the pointer during threading + check_global_threading_available!(); + Ok(unsafe { (*pointer).clone() }) } - //Note, passing the object_manager is per design, so that this call can only be used during init (when storing the address is valid) - pub fn initialize(&mut self, object_manager: &dyn objectmanager::ObjectManager, owner_of_the_set: objectmanager::ObjectId) -> Result<(), ()> { + pub fn initialize( + &mut self, + object_manager: &dyn objectmanager::ObjectManager, + owner_of_the_set: objectmanager::ObjectId, + ) -> Result<(), ()> { let owner = object_manager.get_object(owner_of_the_set)?; let temp: T = T::default(); //TODO find nicer solution whithout local instance and trait bound to Default let type_id = temp.get_type_id(); - let other_set: &dyn DataSetIF; - match owner.get_set(type_id) { + let other_set = match owner.get_set(type_id) { None => { return Err(()); } - Some(set) => { - other_set = set; - } - } + Some(set) => set, + }; //pointer cast is safe because we checked the type_id //getting pointer to avoid lifetime check self.actual_data = Some(other_set.get_actual_data() as *const dyn HasTypeId as *const T); diff --git a/mission_rust/src/fsrc/mutex.rs b/mission_rust/src/fsrc/mutex.rs index 1770dfe..3aeae00 100644 --- a/mission_rust/src/fsrc/mutex.rs +++ b/mission_rust/src/fsrc/mutex.rs @@ -1,7 +1,11 @@ use super::osal; +// for now, this is an implementation based on FreeRTOS, where we can preallocate mutexes +// this allows us to assume that mutexes are valid starting from their creation until end of runtime +// and so we do not use the global_threading lock + pub struct RawMutex { - handle: Option<*const core::ffi::c_void> + handle: *const core::ffi::c_void } pub struct RawMutexGuard { @@ -15,31 +19,20 @@ impl Drop for RawMutexGuard { } } -//TODO for non allocating, keep handle as option, to be set either in an initialize() call -// or maybe lazy later on, TBD if lazy is needed or we can guarantee init to be called impl RawMutex { pub fn new() -> Self { - Self { - handle: None + let handle = unsafe {osal::create_mutex()}; + if handle == 0 as *const core::ffi::c_void { + panic!("Could not create mutex") } - } - - 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 + handle: handle } } pub fn take(&self) -> Result { - 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 }), + match unsafe {osal::take_mutex(self.handle)} { + 1 => Ok(RawMutexGuard { handle: self.handle }), _ => Err(()) //TODO error code } } @@ -57,12 +50,12 @@ impl RawMutex { // _ => 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") +impl Clone for RawMutex { + fn clone(&self) -> Self { + Self { + handle: self.handle } - self.handle = Some(handle); } } \ No newline at end of file diff --git a/mission_rust/src/fsrc/queues/mod.rs b/mission_rust/src/fsrc/queues/mod.rs index 4f13dc3..f752174 100644 --- a/mission_rust/src/fsrc/queues/mod.rs +++ b/mission_rust/src/fsrc/queues/mod.rs @@ -81,7 +81,7 @@ impl MessageQueueSender { }; let res: u8; unsafe { - // safe beacuse: + // safe because: // OS will read not more than length of message queue elements // queue was created with size_of:: as length of message queue elements // in MessageQueue::initialize diff --git a/mission_rust/src/fsrc/tasks/mod.rs b/mission_rust/src/fsrc/tasks/mod.rs index 3013ca3..04395ca 100644 --- a/mission_rust/src/fsrc/tasks/mod.rs +++ b/mission_rust/src/fsrc/tasks/mod.rs @@ -103,11 +103,12 @@ impl<'a> TaskExecutor<'a> { let object_manager = TaskObjectManager { tasks: unsafe { slice::from_raw_parts(self.tasks.as_ptr(), self.tasks.len()) }, }; + // init uses unsafe methods and checks against the lock, so we need to enable it here + crate::fsrc::osal::enable_global_threading(); for task in self.tasks.iter_mut() { let _ = task.initialize(&object_manager).unwrap(); } drop(object_manager); - crate::fsrc::osal::enable_global_threading(); for task in self.tasks.iter_mut() { // we give away a raw pointer, to be called by an OS task // while this is generally very broken, we use a reference tied