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

Commit 4579253

Browse files
committed
First chunk of work on a new scheduler
1 parent 05c8f3c commit 4579253

File tree

8 files changed

+316
-1
lines changed

8 files changed

+316
-1
lines changed

src/hal/systick.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Zinc, the bare metal stack for rust.
2+
// Copyright 2014 Vladimir "farcaller" Pouzanov <[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+
/*!
17+
Interface to Systick timer.
18+
19+
This might be merged into generic timer interface. Systick is a bit specific in
20+
terms of interrupts, but PT should make the difference negligible.
21+
*/
22+
23+
pub trait Systick {
24+
/// Starts the systick timer.
25+
fn start(&self);
26+
}

src/os/sched/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Zinc, the bare metal stack for rust.
2+
// Copyright 2014 Vladimir "farcaller" Pouzanov <[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+
/// Tasks scheduling and management.
17+
18+
pub mod scheduler;
19+
pub mod stack;
20+
pub mod task;

src/os/sched/scheduler.rs

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// Zinc, the bare metal stack for rust.
2+
// Copyright 2014 Vladimir "farcaller" Pouzanov <[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+
/*!
17+
Basic round-robin scheduler.
18+
19+
TODO(farcaller): it's not round-robin, actually. A stricter time slice
20+
accounting must be done.
21+
*/
22+
23+
use core::collections::Collection;
24+
25+
use super::task;
26+
use super::stack::StackManager;
27+
use hal::systick::Systick;
28+
29+
/// Scheduler interface.
30+
pub struct Scheduler<'a, T, S> {
31+
index: task::TasksIndex<'a>,
32+
context_switch: ||:'a,
33+
systick: &'a T,
34+
stack_manager: &'a S,
35+
}
36+
37+
impl<'a, T: Systick, S: StackManager> Scheduler<'a, T, S> {
38+
/// Creates a new scheduler given a list of tasks, systick timer and
39+
/// management routines.
40+
///
41+
/// At least one task must be defined in task index.
42+
pub fn new(ti: task::TasksIndex<'a>, systick: &'a T,
43+
stack_manager: &'a S, ctx_switch: ||:'a)
44+
-> Scheduler<'a, T, S> {
45+
Scheduler {
46+
index: ti,
47+
context_switch: ctx_switch,
48+
systick: systick,
49+
stack_manager: stack_manager,
50+
}
51+
}
52+
53+
/// Starts a scheduler and switches to first task. Never returns.
54+
pub fn start(&mut self) {
55+
self.stack_manager.set_task_stack_pointer(self.index.tasks[0].stack_start);
56+
self.systick.start();
57+
(self.context_switch)();
58+
}
59+
60+
/// Switches to next task.
61+
///
62+
/// Intended to be run by systick ISR, not invoked directly.
63+
pub fn switch(&mut self) {
64+
self.index.tasks[self.index.current_task_index as uint].stack_start =
65+
self.stack_manager.get_task_stack_pointer();
66+
67+
self.index.current_task_index += 1;
68+
if (self.index.current_task_index as uint) == self.index.tasks.len() {
69+
self.index.current_task_index = 0;
70+
}
71+
72+
self.stack_manager.set_task_stack_pointer(
73+
self.index.tasks[self.index.current_task_index as uint].stack_start);
74+
}
75+
76+
fn current_task_index(&self) -> u8 {
77+
self.index.current_task_index
78+
}
79+
80+
fn index(&self) -> &task::TasksIndex {
81+
&self.index
82+
}
83+
}
84+
85+
#[cfg(test)]
86+
mod test {
87+
use hamcrest::{assert_that, is, equal_to};
88+
use std::cell::Cell;
89+
use std::kinds::marker;
90+
91+
use hal::systick::Systick;
92+
use os::sched::stack::StackManager;
93+
use os::sched::task;
94+
use super::Scheduler;
95+
96+
struct FakeSystick {
97+
pub started: Cell<bool>
98+
}
99+
100+
impl FakeSystick {
101+
pub fn new() -> FakeSystick { FakeSystick { started: Cell::new(false) } }
102+
}
103+
impl Systick for FakeSystick {
104+
fn start(&self) { self.started.set(true); }
105+
}
106+
107+
struct FakeStackManager {
108+
pub sp: Cell<u32>
109+
}
110+
impl FakeStackManager {
111+
pub fn new() -> FakeStackManager { FakeStackManager { sp: Cell::new(0) } }
112+
}
113+
impl StackManager for FakeStackManager {
114+
fn get_task_stack_pointer(&self) -> u32 {
115+
self.sp.get()
116+
}
117+
fn set_task_stack_pointer(&self, sp: u32) {
118+
self.sp.set(sp);
119+
}
120+
}
121+
122+
describe!(
123+
before_each {
124+
let tick = FakeSystick::new();
125+
let mut tasks = [task::Task {
126+
state: task::Runnable,
127+
stack_start: 100,
128+
stack_end: 200,
129+
},
130+
task::Task {
131+
state: task::Runnable,
132+
stack_start: 200,
133+
stack_end: 300,
134+
}];
135+
let ti = task::TasksIndex {
136+
tasks: tasks,
137+
current_task_index: 0,
138+
no_copy: marker::NoCopy,
139+
};
140+
let fsm = FakeStackManager::new();
141+
}
142+
143+
it "calls a context switch with first task" {
144+
let mut called = false;
145+
146+
{
147+
let mut scheduler = Scheduler::new(ti, &tick, &fsm, || { called = true });
148+
scheduler.start();
149+
}
150+
151+
assert_that(called, is(equal_to(true)));
152+
}
153+
154+
it "schedules second task on timer interrupt" {
155+
let mut scheduler = Scheduler::new(ti, &tick, &fsm, || {});
156+
scheduler.start();
157+
158+
scheduler.switch();
159+
160+
assert_that(scheduler.current_task_index(), is(equal_to(1u8)));
161+
}
162+
163+
it "wraps over to first task when all tasks are done" {
164+
let mut scheduler = Scheduler::new(ti, &tick, &fsm, || {});
165+
scheduler.start();
166+
167+
scheduler.switch();
168+
scheduler.switch();
169+
170+
assert_that(scheduler.current_task_index(), is(equal_to(0u8)));
171+
}
172+
173+
it "enables systick timer on start" {
174+
let mut scheduler = Scheduler::new(ti, &tick, &fsm, || {});
175+
scheduler.start();
176+
177+
assert_that(tick.started.get(), is(equal_to(true)));
178+
}
179+
180+
it "loads first task stack pointer" {
181+
let mut scheduler = Scheduler::new(ti, &tick, &fsm, || {});
182+
scheduler.start();
183+
184+
assert_that(fsm.sp.get(), is(equal_to(100u32)));
185+
}
186+
187+
it "saves stack pointer to current task on switch" {
188+
let mut scheduler = Scheduler::new(ti, &tick, &fsm, || {});
189+
scheduler.start();
190+
191+
fsm.sp.set(110);
192+
scheduler.switch();
193+
194+
assert_that(scheduler.index().tasks[0].stack_start, is(equal_to(110u32)));
195+
}
196+
197+
it "loads stack pointer to next task on switch" {
198+
let mut scheduler = Scheduler::new(ti, &tick, &fsm, || {});
199+
scheduler.start();
200+
201+
scheduler.switch();
202+
203+
assert_that(fsm.sp.get(), is(equal_to(200u32)));
204+
}
205+
)
206+
}

src/os/sched/stack.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Zinc, the bare metal stack for rust.
2+
// Copyright 2014 Vladimir "farcaller" Pouzanov <[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+
/// Tasks stack management.
17+
18+
/// StackManager provides scheduler with interface to manage task-specific stack
19+
/// pointer.
20+
pub trait StackManager {
21+
/// Returns stack pointer for currently scheduled task.
22+
fn get_task_stack_pointer(&self) -> u32;
23+
24+
/// Sets stack pointer for currently scheduled task.
25+
fn set_task_stack_pointer(&self, sp: u32);
26+
}

src/os/sched/task.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Zinc, the bare metal stack for rust.
2+
// Copyright 2014 Vladimir "farcaller" Pouzanov <[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+
use core::kinds::marker;
17+
18+
pub enum State {
19+
Runnable
20+
}
21+
22+
pub struct Task {
23+
pub state: State,
24+
pub stack_start: u32,
25+
pub stack_end: u32,
26+
}
27+
28+
#[packed]
29+
pub struct TasksIndex<'a> {
30+
pub tasks: &'a mut [Task],
31+
pub current_task_index: u8,
32+
33+
pub no_copy: marker::NoCopy,
34+
}

src/zinc/hal/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ pub mod spi;
3737
pub mod stack;
3838
pub mod timer;
3939
pub mod uart;
40+
pub mod systick;

src/zinc/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ extern crate core;
4848
extern crate rlibc;
4949

5050
#[cfg(test)] #[phase(plugin,link)] extern crate std;
51+
#[cfg(test)] #[phase(plugin,link)] extern crate shiny;
5152
#[cfg(test)] extern crate native;
53+
#[cfg(test)] extern crate hamcrest;
5254
#[phase(plugin)] extern crate macro_ioreg;
5355

5456
pub mod drivers;

src/zinc/os/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ This module is a higher level abstraction over hardware than hal. It might be
2020
incompatible direct hal usage in some cases.
2121
*/
2222

23-
// pub mod debug;
2423
pub mod syscall;
2524
#[cfg(cfg_multitasking)] pub mod task;
2625
pub mod mutex;
2726
pub mod cond_var;
2827
pub mod debug;
28+
pub mod sched;

0 commit comments

Comments
 (0)