Skip to content

Commit eaaf458

Browse files
committed
Config is now thread-safe
1 parent d4e68aa commit eaaf458

File tree

3 files changed

+23
-26
lines changed

3 files changed

+23
-26
lines changed

examples/sdo_mapping.rs

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ async fn main() -> std::io::Result<()> {
3737
let error = pdo.push(Sdo::<u16>::complete(0x603f));
3838
let position = pdo.push(Sdo::<i32>::complete(0x6064));
3939
let torque = pdo.push(Sdo::<i16>::complete(0x6077));
40+
drop(slave);
4041
println!("done {:#?}", config);
4142

4243
let allocator = mapping::Allocator::new();

examples/servodrive_run.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ async fn main() -> std::io::Result<()> {
4444
let current_position = pdo.push(sdo::cia402::current::position);
4545
let _current_velocity = pdo.push(sdo::cia402::current::velocity);
4646
let _current_torque = pdo.push(sdo::cia402::current::torque);
47+
drop(slave);
4748
println!("done {:#?}", config);
4849

4950
let allocator = mapping::Allocator::new();
@@ -69,10 +70,9 @@ async fn main() -> std::io::Result<()> {
6970
async {
7071
let mut period = tokio::time::interval(Duration::from_millis(1));
7172
loop {
72-
let mut group = group.data().await;
73-
period.tick().await;
74-
group.exchange().await;
73+
group.data().await.exchange().await;
7574
cycle.notify_waiters();
75+
period.tick().await;
7676
}
7777
},
7878
async {

src/mapping.rs

+19-23
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ use crate::{
6363
};
6464
use core::{
6565
fmt,
66-
ops::Range,
66+
ops::{Range, Deref},
6767
cell::Ref,
6868
};
6969
use std::{
7070
cell::RefCell,
7171
collections::{HashMap, BTreeSet},
72-
sync::{Arc, Weak, Mutex},
72+
sync::{Arc, Weak, Mutex, MutexGuard, RwLock, RwLockWriteGuard},
7373
};
7474
use bilge::prelude::*;
7575

@@ -127,13 +127,13 @@ impl Allocator {
127127
}
128128
// update global config
129129
let mut slaves = HashMap::<u16, Arc<ConfigSlave>>::new();
130-
for (&k, slave) in mapping.config.slaves.borrow().iter() {
130+
for (&k, slave) in mapping.config.slaves.lock().unwrap().iter() {
131131
slaves.insert(k,
132132
if let Some(value) = internal.slaves.get(&k).map(|v| v.upgrade()).flatten()
133133
// if config for slave already existing, we can use it, because we already checked it was perfectly the same in `self.compatible()`
134134
{value}
135135
else {
136-
let new = Arc::new(slave.as_ref().clone());
136+
let new = Arc::new(slave.try_read().expect("a slave is still in mapping").clone());
137137
internal.slaves.insert(k, Arc::downgrade(&new));
138138
new
139139
});
@@ -175,10 +175,10 @@ impl AllocatorInternal {
175175
/// check that a given mapping is compatible with the already configured slaves in the allocator
176176
/// if true, a group can be initialized from the mapping
177177
fn compatible(&self, mapping: &Mapping) -> bool {
178-
for (address, slave) in mapping.config.slaves.borrow().iter() {
178+
for (address, slave) in mapping.config.slaves.lock().unwrap().iter() {
179179
if let Some(alter) = self.slaves.get(address) {
180180
if let Some(alter) = alter.upgrade() {
181-
if slave.as_ref() != alter.as_ref()
181+
if slave.try_read().expect("a slave is still in mapping").deref() != alter.as_ref()
182182
{return false}
183183
}
184184
}
@@ -389,10 +389,10 @@ impl fmt::Debug for Group<'_> {
389389

390390

391391
/// struct holding configuration informations for multiple slaves, that can be shared between multiple mappings
392-
#[derive(Clone, Default, Debug, Eq, PartialEq)]
392+
#[derive(Default, Debug)]
393393
pub struct Config {
394394
// slave configs are boxed so that they won't move even while inserting in the hashmap
395-
slaves: RefCell<HashMap<u16, Box<ConfigSlave>>>,
395+
pub slaves: Mutex<HashMap<u16, Box<RwLock<ConfigSlave>>>>,
396396
}
397397
/// configuration for one slave
398398
#[derive(Clone, Default, Debug, Eq, PartialEq)]
@@ -423,12 +423,6 @@ pub struct ConfigFmmu {
423423
pub logical: u32,
424424
}
425425

426-
impl Config {
427-
pub fn slaves(&self) -> Ref<'_, HashMap<u16, Box<ConfigSlave>>> {
428-
self.slaves.borrow()
429-
}
430-
}
431-
432426

433427
/**
434428
Convenient struct to create a memory mapping for multiple slaves to the logical memory (responsible for realtime data exchanges).
@@ -464,20 +458,22 @@ impl<'a> Mapping<'a> {
464458
///
465459
/// data coming for different slaves can interlace, hence multiple slave mapping instances can exist at the same time
466460
pub fn slave(&self, address: u16) -> MappingSlave<'_> {
467-
let mut slaves = self.config.slaves.borrow_mut();
461+
let mut slaves = self.config.slaves.lock().unwrap();
468462
slaves
469463
.entry(address)
470-
.or_insert_with(|| Box::new(ConfigSlave {
464+
.or_insert_with(|| Box::new(RwLock::new(ConfigSlave {
471465
pdos: HashMap::new(),
472466
channels: HashMap::new(),
473467
fmmu: Vec::new(),
474-
}));
475-
let slave = slaves.get(&address).unwrap().as_ref();
468+
})));
469+
// uncontroled reference to self and to configuration
470+
// this is safe since the slave config will not be removed from the hashmap and cannot be moved since it is heap allocated
471+
// the returned instance holds an immutable reference to self so it cannot be freed
472+
let slave = unsafe {core::mem::transmute::<_, &Box<RwLock<_>>>(
473+
slaves.get(&address).unwrap()
474+
)};
476475
MappingSlave {
477-
// uncontroled reference to self and to configuration
478-
// this is safe since the config parts that will be accessed by this new slave shall be accessed only by it
479-
// the returned instance holds an immutable reference to self so it cannot be freed
480-
config: unsafe {&mut *(slave as *const _ as *mut _)},
476+
config: slave.try_write().expect("slave already in mapping"),
481477
mapping: self,
482478
buffer: SLAVE_PHYSICAL_MAPPABLE.start,
483479
additional: 0,
@@ -493,7 +489,7 @@ impl<'a> Mapping<'a> {
493489
/// data coming from one's slave physical memory shall not interlace (this is a limitation due to this library, not ethercat) so any mapping methods in here are preventing multiple mapping instances
494490
pub struct MappingSlave<'a> {
495491
mapping: &'a Mapping<'a>,
496-
config: &'a mut ConfigSlave,
492+
config: RwLockWriteGuard<'a, ConfigSlave>,
497493
/// position in the physical memory mapping region
498494
buffer: u16,
499495
/// increment to add to `buffer` once the current mapped channel is done.

0 commit comments

Comments
 (0)