aboutsummaryrefslogtreecommitdiff
path: root/tests/cfail/token-transfer.rs
blob: 1d81e8f707e31e569c0f4d4a45d782492b93fe3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#![feature(const_fn)]
#![feature(optin_builtin_traits)]
#![feature(used)]

#[macro_use]
extern crate cortex_m_rtfm as rtfm;

use core::cell::RefCell;

use rtfm::{C2, Local, P0, P1, P2, Resource, T0, T1, T2, TMax};
use device::interrupt::{Exti0, Exti1};

tasks!(device, {
    t1: Task {
        interrupt: Exti0,
        priority: P1,
        enabled: true,
    },
    t2: Task {
        interrupt: Exti1,
        priority: P2,
        enabled: true,
    },
});

fn init(_: P0, _: &TMax) {}

fn idle(_: P0, _: T0) -> ! {
    rtfm::request(t1);
    rtfm::request(t1);

    loop {}
}

static CHANNEL: Resource<RefCell<Option<Exti0>>, C2> = {
    //~^ error: Send
    Resource::new(RefCell::new(None))
};

static LOCAL: Local<i32, Exti0> = Local::new(0);

fn t1(mut task: Exti0, ref priority: P1, ref threshold: T1) {
    // First run
    static FIRST: Local<bool, Exti0> = Local::new(true);

    let first = *FIRST.borrow(&task);

    if first {
        // toggle
        *FIRST.borrow_mut(&mut task) = false;
    }

    if first {
        threshold.raise(
            &CHANNEL, move |threshold| {
                let channel = CHANNEL.access(priority, threshold);

                // BAD: give up task token
                *channel.borrow_mut() = Some(task);
            }
        );

        return;
    }

    let _local = LOCAL.borrow_mut(&mut task);

    // ..

    // `t2` will preempt `t1`
    rtfm::request(t2);

    // ..

    // `LOCAL` mutably borrowed up to this point
}

fn t2(_task: Exti1, ref priority: P2, ref threshold: T2) {
    let channel = CHANNEL.access(priority, threshold);
    let mut channel = channel.borrow_mut();

    if let Some(mut other_task) = channel.take() {
        // BAD: `t2` has access to `t1`'s task token
        // so it can now mutably access local while `t1` is also using it
        let _local = LOCAL.borrow_mut(&mut other_task);

    }
}

// fake device crate
extern crate core;
extern crate cortex_m;

mod device {
    pub mod interrupt {
        use cortex_m::ctxt::Context;
        use cortex_m::interrupt::Nr;

        extern "C" fn default_handler<T>(_: T) {}

        pub struct Handlers {
            pub Exti0: extern "C" fn(Exti0),
            pub Exti1: extern "C" fn(Exti1),
            pub Exti2: extern "C" fn(Exti2),
        }

        pub struct Exti0;
        pub struct Exti1;
        pub struct Exti2;

        pub enum Interrupt {
            Exti0,
            Exti1,
            Exti2,
        }

        unsafe impl Nr for Interrupt {
            fn nr(&self) -> u8 {
                0
            }
        }

        unsafe impl Context for Exti0 {}

        unsafe impl Nr for Exti0 {
            fn nr(&self) -> u8 {
                0
            }
        }

        impl !Send for Exti0 {}

        unsafe impl Context for Exti1 {}

        unsafe impl Nr for Exti1 {
            fn nr(&self) -> u8 {
                0
            }
        }

        impl !Send for Exti1 {}

        unsafe impl Context for Exti2 {}

        unsafe impl Nr for Exti2 {
            fn nr(&self) -> u8 {
                0
            }
        }

        impl !Send for Exti2 {}

        pub const DEFAULT_HANDLERS: Handlers = Handlers {
            Exti0: default_handler,
            Exti1: default_handler,
            Exti2: default_handler,
        };
    }
}