Skip to content
This repository was archived by the owner on Jul 6, 2019. It is now read-only.

Commit f1f1175

Browse files
committed
Merge pull request #194 from bgamari/concurrency
Concurrency primitives
2 parents 08fa985 + 8967506 commit f1f1175

File tree

11 files changed

+382
-196
lines changed

11 files changed

+382
-196
lines changed

src/zinc/hal/cortex_common/irq.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Zinc, the bare metal stack for rust.
2+
// Copyright 2014 Ben Gamari <[email protected]>
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
//! Disabling and enabling interrupts
17+
18+
use core::ops::Drop;
19+
use core::intrinsics::abort;
20+
21+
/// Phantom type to indicate that interrupts are disabled.
22+
pub struct NoInterrupts {
23+
#[allow(dead_code)]
24+
contents: ()
25+
}
26+
27+
impl NoInterrupts {
28+
/// Start a new critical section
29+
pub fn new() -> NoInterrupts {
30+
unsafe {
31+
disable_irqs();
32+
}
33+
NoInterrupts { contents: () }
34+
}
35+
}
36+
37+
impl Drop for NoInterrupts {
38+
fn drop(&mut self) {
39+
unsafe {
40+
enable_irqs();
41+
}
42+
}
43+
}
44+
45+
static mut irq_level : uint = 0;
46+
47+
/// Disables all interrupts except Reset, HardFault, and NMI.
48+
/// Note that this is reference counted: if `disable_irqs` is called
49+
/// twice then interrupts will only be re-enabled upon the second call
50+
/// to `enable_irqs`.
51+
#[cfg(not(test))]
52+
#[inline(always)]
53+
unsafe fn disable_irqs() {
54+
asm!("cpsid i" :::: "volatile");
55+
irq_level += 1;
56+
}
57+
58+
#[cfg(test)]
59+
unsafe fn disable_irqs() { unimplemented!() }
60+
61+
/// Enables all interrupts except Reset, HardFault, and NMI.
62+
#[cfg(not(test))]
63+
#[inline(always)]
64+
unsafe fn enable_irqs() {
65+
if irq_level == 0 {
66+
abort();
67+
}
68+
// There is no race condition here as we know that interrupts are
69+
// disabled.
70+
irq_level -= 1;
71+
if irq_level == 0 {
72+
asm!("cpsie i" :::: "volatile");
73+
}
74+
}
75+
76+
#[cfg(test)]
77+
unsafe fn enable_irqs() { unimplemented!() }

src/zinc/hal/cortex_common/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ pub mod systick;
2121
pub mod mpu;
2222
pub mod nvic;
2323
pub mod scb;
24+
pub mod irq;

src/zinc/hal/cortex_m0/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ crate. `isr.rs` provides ISR vector table.
2323
pub use super::cortex_common::systick;
2424
pub use super::cortex_common::scb;
2525
pub use super::cortex_common::nvic;
26+
pub use super::cortex_common::irq;
2627
pub mod lock;

src/zinc/hal/cortex_m3/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ pub use super::cortex_common::systick;
2424
pub use super::cortex_common::scb;
2525
pub use super::cortex_common::nvic;
2626
pub use super::cortex_common::mpu;
27+
pub use super::cortex_common::irq;
2728
#[cfg(cfg_multitasking)] pub mod sched;
2829
#[cfg(cfg_multitasking)] pub mod lock;

src/zinc/hal/cortex_m3/sched.rs

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -100,58 +100,3 @@ unsafe fn task_finished() {
100100
#[cfg(test)]
101101
unsafe fn task_finished() { unimplemented!() }
102102

103-
/// Phantom type to indicate that interrupts are disabled.
104-
pub struct NoInterrupts {
105-
contents: ()
106-
}
107-
108-
impl NoInterrupts {
109-
pub fn new() -> NoInterrupts {
110-
unsafe {
111-
disable_irqs();
112-
}
113-
NoInterrupts { contents: () }
114-
}
115-
}
116-
117-
impl Drop for NoInterrupts {
118-
fn drop(&mut self) {
119-
unsafe {
120-
enable_irqs();
121-
}
122-
}
123-
}
124-
125-
static mut irq_level : uint = 0;
126-
127-
/// Disables all interrupts except Reset, HardFault, and NMI.
128-
/// Note that this is reference counted: if `disable_irqs` is called
129-
/// twice then interrupts will only be re-enabled upon the second call
130-
/// to `enable_irqs`.
131-
#[cfg(not(test))]
132-
#[inline(always)]
133-
unsafe fn disable_irqs() {
134-
if irq_level == 0 {
135-
asm!("cpsid i" :::: "volatile");
136-
}
137-
irq_level += 1;
138-
}
139-
140-
#[cfg(test)]
141-
unsafe fn disable_irqs() { unimplemented!() }
142-
143-
/// Enables all interrupts except Reset, HardFault, and NMI.
144-
#[cfg(not(test))]
145-
#[inline(always)]
146-
unsafe fn enable_irqs() {
147-
if irq_level == 0 {
148-
abort();
149-
}
150-
irq_level -= 1;
151-
if irq_level == 0 {
152-
asm!("cpsie i" :::: "volatile");
153-
}
154-
}
155-
156-
#[cfg(test)]
157-
unsafe fn enable_irqs() { unimplemented!() }

src/zinc/hal/cortex_m4/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ pub use super::cortex_common::systick;
2424
pub use super::cortex_common::scb;
2525
pub use super::cortex_common::nvic;
2626
pub use super::cortex_common::mpu;
27+
pub use super::cortex_common::irq;

src/zinc/os/cond_var.rs

Lines changed: 109 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,69 +13,131 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16-
use core::option::{None, Some};
17-
use core::ty::Unsafe;
18-
use core::kinds::marker;
19-
use core::kinds::Share;
16+
//! Condition variables
2017
21-
use hal::cortex_m3::sched::NoInterrupts;
22-
use util::queue::{Queue, Node};
23-
use os::task::{TaskDescriptor, Tasks};
18+
pub use os::cond_var::internal::{CondVar, COND_VAR_INIT};
2419

25-
pub struct CondVar {
26-
waiting: Queue<*mut TaskDescriptor>
27-
}
20+
#[cfg(multitasking)]
21+
mod internal {
22+
use core::option::{None, Some};
23+
use core::ty::Unsafe;
24+
use core::kinds::marker;
25+
use core::kinds::Share;
2826

29-
pub static COND_VAR_INIT: CondVar = CondVar {
30-
waiting: Queue {
31-
head: Unsafe { value: 0 as *mut Node<*mut TaskDescriptor>, marker1: marker::InvariantType },
32-
tail: Unsafe { value: 0 as *mut Node<*mut TaskDescriptor>, marker1: marker::InvariantType },
33-
}
34-
};
27+
use hal::cortex_m3::sched::NoInterrupts;
28+
use util::queue::{Queue, Node};
29+
use os::task::{TaskDescriptor, Tasks};
3530

36-
impl CondVar {
37-
pub fn new() -> CondVar {
38-
CondVar { waiting: Queue::new() }
31+
/// A condition variable
32+
pub struct CondVar {
33+
waiting: Queue<*mut TaskDescriptor>
3934
}
4035

41-
/// Wait on a condition variable.
42-
pub fn wait<'a>(&'a self) {
43-
/*
44-
* The signalling thread is responsible for removing the waiting
45-
* thread which ensures that a signal wakes up exactly one thread
46-
* whenever there is one waiting.
47-
*/
48-
unsafe {
49-
let crit = NoInterrupts::new();
50-
let mut waiting = Node::new(Tasks.current_task() as *mut TaskDescriptor);
51-
self.waiting.push(&mut waiting, &crit);
52-
Tasks.current_task().block(crit);
36+
/// Static initializer
37+
pub const COND_VAR_INIT: CondVar = CondVar {
38+
waiting: Queue {
39+
head: Unsafe { value: 0 as *mut Node<*mut TaskDescriptor>, marker1: marker::InvariantType },
40+
tail: Unsafe { value: 0 as *mut Node<*mut TaskDescriptor>, marker1: marker::InvariantType },
41+
}
42+
};
43+
44+
impl CondVar {
45+
/// Create a new condition variable
46+
pub fn new() -> CondVar {
47+
CondVar { waiting: Queue::new() }
5348
}
54-
}
5549

56-
/// Wake up a thread waiting on a condition variable.
57-
pub fn signal<'a>(&'a self) {
58-
unsafe {
59-
let crit = NoInterrupts::new();
60-
match self.waiting.pop(&crit) {
61-
None => { },
62-
Some(task) => (*(*task).data).unblock(&crit)
50+
/// Wait on a condition variable.
51+
pub fn wait(&self) {
52+
/*
53+
* The signalling thread is responsible for removing the waiting
54+
* thread which ensures that a signal wakes up exactly one thread
55+
* whenever there is one waiting.
56+
*/
57+
unsafe {
58+
let crit = NoInterrupts::new();
59+
let mut waiting = Node::new(Tasks.current_task() as *mut TaskDescriptor);
60+
self.waiting.push(&mut waiting, &crit);
61+
Tasks.current_task().block(crit);
6362
}
6463
}
65-
}
6664

67-
/// Wake up all threads waiting on a condition variable.
68-
pub fn broadcast<'a>(&'a self) {
69-
unsafe {
70-
let crit = NoInterrupts::new();
71-
loop {
65+
/// Wake up a thread waiting on a condition variable.
66+
pub fn signal(&self) {
67+
unsafe {
68+
let crit = NoInterrupts::new();
7269
match self.waiting.pop(&crit) {
73-
None => break,
70+
None => { },
7471
Some(task) => (*(*task).data).unblock(&crit)
7572
}
7673
}
7774
}
75+
76+
/// Wake up all threads waiting on a condition variable.
77+
pub fn broadcast(&self) {
78+
unsafe {
79+
let crit = NoInterrupts::new();
80+
loop {
81+
match self.waiting.pop(&crit) {
82+
None => break,
83+
Some(task) => (*(*task).data).unblock(&crit)
84+
}
85+
}
86+
}
87+
}
7888
}
89+
90+
impl Share for CondVar {}
7991
}
8092

81-
impl Share for CondVar {}
93+
#[cfg(not(multitasking))]
94+
mod internal {
95+
use core::kinds::marker;
96+
use core::kinds::Share;
97+
use core::cell::UnsafeCell;
98+
99+
/// A condition variable
100+
pub struct CondVar {
101+
waiting: UnsafeCell<bool>,
102+
nocopy: marker::NoCopy
103+
}
104+
105+
/// Static initializer
106+
pub const COND_VAR_INIT: CondVar = CondVar {
107+
waiting: UnsafeCell { value: false },
108+
nocopy: marker::NoCopy,
109+
};
110+
111+
impl CondVar {
112+
/// Create a new condition variable
113+
pub fn new() -> CondVar {
114+
CondVar {
115+
waiting: UnsafeCell::new(false),
116+
nocopy: marker::NoCopy,
117+
}
118+
}
119+
120+
/// Wait on a condition variable.
121+
pub fn wait(&self) {
122+
unsafe {
123+
while *self.waiting.get() {
124+
asm!("wfi")
125+
}
126+
}
127+
}
128+
129+
/// Wake up a thread waiting on a condition variable.
130+
pub fn signal(&self) {
131+
unsafe {
132+
*self.waiting.get() = true;
133+
}
134+
}
135+
136+
/// Wake up all threads waiting on a condition variable.
137+
pub fn broadcast(&self) {
138+
self.signal();
139+
}
140+
}
141+
142+
impl Share for CondVar {}
143+
}

src/zinc/os/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ incompatible direct hal usage in some cases.
2323
// pub mod debug;
2424
pub mod syscall;
2525
#[cfg(cfg_multitasking)] pub mod task;
26-
#[cfg(cfg_multitasking)] pub mod mutex;
27-
#[cfg(cfg_multitasking)] pub mod cond_var;
26+
pub mod mutex;
27+
pub mod cond_var;

0 commit comments

Comments
 (0)