Skip to content

Commit add1c7a

Browse files
Merge pull request #2 from RusPiRo/feature/new_data_lock
add DataLock
2 parents ff89363 + b6c93ec commit add1c7a

File tree

10 files changed

+245
-36
lines changed

10 files changed

+245
-36
lines changed

.travis.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ matrix:
1111

1212
include:
1313
- rust: nightly
14-
env:
15-
- TARGET=armv7-unknown-linux-gnueabihf
16-
- CFLAGS='-std=c11 -mfpu=neon-fp-armv8 -mfloat-abi=hard -march=armv8-a -Wall -O3 -nostartfiles -ffreestanding -mtune=cortex-a53'
17-
- RUSTFLAGS='-C target-cpu=cortex-a53 -C target-feature=+a53,+fp-armv8,+v8,+vfp3,+d16,+thumb2,+neon'
1814

19-
script:
20-
cargo build --target armv7-unknown-linux-gnueabihf --verbose
15+
script: ./travis-build.sh
2116

2217
install:
18+
# install cross compiler toolchain
2319
- sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
24-
- rustup target add armv7-unknown-linux-gnueabihf
20+
# install cargo xbuild to proper cross compile
21+
- cargo install cargo-xbuild
22+
# add the build target used for Raspbarry Pi targeting builds
23+
- rustup target add armv7-unknown-linux-gnueabihf
24+
- rustup component add rust-src
25+
- sudo chmod ugo+x ./travis-build.sh

Cargo.lock

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
[package]
22
name = "ruspiro-lock"
33
authors = ["André Borrmann <[email protected]>"]
4-
version = "0.1.0" # remember to update html_root_url
5-
description = "This crates provide 2 simple atomic locks to be used to ensure safe atomic access to data. This is Spinlock and Semaphore"
4+
version = "0.2.0" # remember to update html_root_url
5+
description = """
6+
Simple atomic locking and safe data access (mutual exclusive) cross cores on Raspberry Pi.
7+
"""
68
license = "Apache-2.0"
7-
repository = "https://github.com/RusPiRo/ruspiro-lock/tree/v0.1.0"
8-
documentation = "https://docs.rs/ruspiro-lock/0.1.0"
9+
repository = "https://github.com/RusPiRo/ruspiro-lock/tree/v0.2.0"
10+
documentation = "https://docs.rs/ruspiro-lock/0.2.0"
911
readme = "README.md"
10-
keywords = ["RusPiRo", "spinlock", "semaphore", "raspberrypi"]
12+
keywords = ["RusPiRo", "spinlock", "semaphore", "datalock", "raspberrypi"]
1113
categories = ["no-std", "embedded"]
1214
edition = "2018"
1315

16+
[badges]
17+
travis-ci = { repository = "RusPiRo/ruspiro-lock", branch = "master" }
18+
maintenance = { status = "actively-developed" }
19+
1420
[lib]
1521

1622
[dependencies]
23+
ruspiro-interrupt-core = "0.2"
1724

1825
[features]
26+
default = ["ruspiro_pi3"]
27+
ruspiro_pi3 = []

README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# RusPiRo Lock crate
22

3-
This crates provide two simple abstractions on low level atomic locks. The ``Spinlock`` and the ``Semaphore``.
3+
Simple to use abstractions on low level atomic locks:
4+
- ``Spinlock``: blocking lock to secure cross core mutual exclusive access (requires a configured MMU on Raspberry Pi)
5+
- ``Semaphore``: counting blocking or nonblocking lock to secure cross core exclusive access
6+
- ``DataLock``: data container guarded by a nonblocking atomic lock to secure cross core mutual exclusive access
47

58
[![Travis-CI Status](https://api.travis-ci.org/RusPiRo/ruspiro-lock.svg?branch=master)](https://travis-ci.org/RusPiRo/ruspiro-lock)
69
[![Latest Version](https://img.shields.io/crates/v/ruspiro-lock.svg)](https://crates.io/crates/ruspiro-lock)
@@ -12,7 +15,7 @@ This crates provide two simple abstractions on low level atomic locks. The ``Spi
1215
To use this crate simply add the dependency to your ``Cargo.toml`` file:
1316
```
1417
[dependencies]
15-
ruspiro-lock = "0.1.0"
18+
ruspiro-lock = "0.2"
1619
```
1720

1821
Once done the definition and usage of the locks is as follows:
@@ -48,5 +51,26 @@ fn main() {
4851
}
4952
```
5053

54+
Using data container with atmic lock guard:
55+
```
56+
use ruspiro_lock::*;
57+
58+
static DATA: DataLock<u32> = DataLock::new(0);
59+
60+
fn main() {
61+
if let Some(mut data) = DATA.try_lock() {
62+
*data = 20;
63+
}
64+
// once the data goes ot of scope the lock will be released
65+
if let Some(data) = DATA.try_lock() {
66+
println!("data: {}", *data);
67+
68+
// another lock should fail inside this scope
69+
assert_eq!(DATA.try_lock(), None);
70+
}
71+
}
72+
```
73+
74+
5175
## License
5276
Licensed under Apache License, Version 2.0, ([LICENSE](LICENSE) or http://www.apache.org/licenses/LICENSE-2.0)

Xargo.toml

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/datalock.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/***********************************************************************************************************************
2+
* Copyright (c) 2019 by the authors
3+
*
4+
* Author: André Borrmann
5+
* License: Apache License 2.0
6+
**********************************************************************************************************************/
7+
8+
//! # Data Lock
9+
//!
10+
//! Enable exclusive access to data guarded by a cross core atomic lock
11+
//!
12+
//! # Example
13+
//! ```
14+
//! static DATA: DataLock<u32> = DataLock::new(0);
15+
//!
16+
//! fn main() {
17+
//! if let Some(mut data) = DATA.try_lock() {
18+
//! *data = 20;
19+
//! }
20+
//! // once the data goes ot of scope the lock will be released
21+
//! if let Some(data) = DATA.try_lock() {
22+
//! println!("data: {}", *data);
23+
//!
24+
//! // another lock should fail inside this scope
25+
//! assert_eq!(DATA.try_lock(), None);
26+
//! }
27+
//! }
28+
//! ```
29+
//!
30+
31+
use core::sync::atomic::{AtomicBool, Ordering};
32+
use core::cell::UnsafeCell;
33+
use core::ops::{Deref, DerefMut};
34+
35+
/// An exclusive access lock around the given data
36+
pub struct DataLock<T> {
37+
locked: AtomicBool,
38+
data: UnsafeCell<T>,
39+
}
40+
41+
/// Result of trying to access the data using ``try_lock`` on the data lock
42+
/// If the result goes out of scope the lock is released
43+
pub struct TryDataLock<'a, T> {
44+
_data: &'a DataLock<T>,
45+
}
46+
47+
impl<T> DataLock<T> {
48+
/// Create a new data access guarding lock
49+
pub fn new(value: T) -> Self {
50+
DataLock {
51+
locked: AtomicBool::new(false),
52+
data: UnsafeCell::new(value),
53+
}
54+
}
55+
56+
/// Try to lock the guarded data for mutual exclusive access. Returns ``None`` if the lock failes
57+
/// or ``Some(TryDataLock)``. The actual data, the TryDataLock wraps could be conviniently accessed by
58+
/// dereferencing it.
59+
///
60+
/// # Example
61+
/// ```
62+
/// # fn doc() {
63+
/// let secure_data: DataLock<u32> = DataLock::new(10);
64+
///
65+
/// if let Some(data) = secure_data.try_lock() {
66+
/// assert_eq!(*data, 10);
67+
/// }
68+
/// # }
69+
/// ```
70+
pub fn try_lock(&self) -> Option<TryDataLock<T>> {
71+
// do the atomic operation to set the lock
72+
crate::disable_interrupts();
73+
let data_lock = if !self.locked.swap(true, Ordering::SeqCst) {
74+
// has been false previously means we now have the lock
75+
Some(TryDataLock{
76+
_data: self,
77+
})
78+
} else {
79+
// we couldn't set the lock
80+
None
81+
};
82+
crate::re_enable_interrupts();
83+
data_lock
84+
}
85+
}
86+
87+
// when the TryDataLock is dropped release the owning lock
88+
impl<T> Drop for TryDataLock<'_, T> {
89+
fn drop(&mut self) {
90+
self._data.locked.swap(false, Ordering::SeqCst);
91+
}
92+
}
93+
94+
// dereferencing the value contained in the TryDataLock
95+
// this ok as the TryDataLock does only exist if the exclusive access to the data could
96+
// be ensures. Therefore also only one ``TryDataLock`` could ever exist for one specific ``DataLock``, which makes it
97+
// safe to return immutable and mutable references.
98+
impl <T> Deref for TryDataLock<'_, T> {
99+
type Target = T;
100+
101+
fn deref(&self) -> &T {
102+
unsafe { &*self._data.data.get() }
103+
}
104+
}
105+
106+
impl <T> DerefMut for TryDataLock<'_, T> {
107+
fn deref_mut(&mut self) -> &mut T {
108+
unsafe { &mut *self._data.data.get() }
109+
}
110+
}

src/lib.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Author: André Borrmann
55
* License: Apache License 2.0
66
**********************************************************************************************************************/
7-
#![doc(html_root_url = "https://docs.rs/ruspiro-lock/0.1.0")]
7+
#![doc(html_root_url = "https://docs.rs/ruspiro-lock/0.2.0")]
88
#![no_std]
99
#![feature(asm)]
1010

@@ -31,7 +31,7 @@
3131
//! }
3232
//! ```
3333
//!
34-
//! using a Semaphore to specify how often specific access is valid
34+
//! Using a Semaphore to specify how often specific access is valid.
3535
//!
3636
//! ```
3737
//! use ruspriro_lock::*;
@@ -49,9 +49,38 @@
4949
//! }
5050
//! ```
5151
//!
52+
//! Using data container with atmic lock guard.
53+
//! ```
54+
//! use ruspiro_lock::*;
55+
//!
56+
//! static DATA: DataLock<u32> = DataLock::new(0);
57+
//!
58+
//! fn main() {
59+
//! if let Some(mut data) = DATA.try_lock() {
60+
//! *data = 20;
61+
//! }
62+
//! // once the data goes ot of scope the lock will be released
63+
//! if let Some(data) = DATA.try_lock() {
64+
//! println!("data: {}", *data);
65+
//!
66+
//! // another lock should fail inside this scope
67+
//! assert_eq!(DATA.try_lock(), None);
68+
//! }
69+
//! }
70+
//! ```
71+
//!
5272
73+
74+
// re-export the spinlock
5375
pub mod spinlock;
54-
pub use self::spinlock::*;
76+
pub use spinlock::*;
5577

78+
// re-export the semaphore
5679
pub mod semaphore;
57-
pub use self::semaphore::*;
80+
pub use semaphore::*;
81+
82+
// re-export the data-lock
83+
pub mod datalock;
84+
pub use datalock::*;
85+
86+
use ruspiro_interrupt_core::*;

0 commit comments

Comments
 (0)