forked from ROMEO/obsw
mutexes and datasets
This commit is contained in:
parent
2d8705917c
commit
3bf0667cbb
@ -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) {
|
||||
|
@ -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<T: HasTypeId + Copy> {
|
||||
pub struct OwnedDataset<T: HasTypeId + Clone> {
|
||||
actual_data: T,
|
||||
mutex: mutex::RawMutex,
|
||||
}
|
||||
|
||||
pub struct ReferencedDataset<T: HasTypeId + Copy> {
|
||||
pub struct ReferencedDataset<T: HasTypeId + Clone> {
|
||||
//we use a pointer here to avoid lifetimes
|
||||
actual_data: Option<*const T>,
|
||||
mutex: Option<mutex::RawMutex>,
|
||||
}
|
||||
|
||||
impl<T: HasTypeId + Copy + Default> DataSetIF for OwnedDataset<T> {
|
||||
impl<T: HasTypeId + Clone + Default> DataSetIF for OwnedDataset<T> {
|
||||
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<T: HasTypeId + Copy + Default> OwnedDataset<T> {
|
||||
impl<T: HasTypeId + Clone + Default> OwnedDataset<T> {
|
||||
pub fn new() -> OwnedDataset<T> {
|
||||
OwnedDataset::<T> {
|
||||
actual_data: T::default(),
|
||||
@ -62,12 +65,19 @@ impl<T: HasTypeId + Copy + Default> OwnedDataset<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_default(default_values: T) -> OwnedDataset<T> {
|
||||
OwnedDataset::<T> {
|
||||
actual_data: default_values,
|
||||
mutex: mutex::RawMutex::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&mut self) -> Result<T, ()> {
|
||||
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<T: HasTypeId + Copy + Default> OwnedDataset<T> {
|
||||
self.actual_data = data;
|
||||
}
|
||||
|
||||
fn initialize(&mut self) {
|
||||
|
||||
}
|
||||
fn initialize(&mut self) {}
|
||||
}
|
||||
|
||||
impl<T: HasTypeId + Copy + Default> ReferencedDataset<T> {
|
||||
impl<T: HasTypeId + Clone + Default> ReferencedDataset<T> {
|
||||
pub fn new() -> ReferencedDataset<T> {
|
||||
ReferencedDataset::<T> {
|
||||
actual_data: None,
|
||||
@ -93,33 +101,36 @@ impl<T: HasTypeId + Copy + Default> ReferencedDataset<T> {
|
||||
}
|
||||
|
||||
pub fn read(&mut self) -> Result<T, ()> {
|
||||
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);
|
||||
|
@ -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<RawMutexGuard,()> {
|
||||
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")
|
||||
}
|
||||
self.handle = Some(handle);
|
||||
impl Clone for RawMutex {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
handle: self.handle
|
||||
}
|
||||
}
|
||||
}
|
@ -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::<Message> as length of message queue elements
|
||||
// in MessageQueue::initialize
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user