Skip to content

Commit 15042d5

Browse files
authored
Merge pull request #170 from torfmaster/feature/libcore-futures
bors is causing trouble. Merging manually...
2 parents 6fc45ef + 9c9cb52 commit 15042d5

20 files changed

+104
-168
lines changed

.gitignore

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Cargo.lock
2-
layout.ld
3-
platform
4-
target
1+
/Cargo.lock
2+
/layout.ld
3+
/platform
4+
/target

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ branches:
66

77
language: rust
88
rust:
9-
- nightly-2020-01-16
9+
- nightly-2020-04-06
1010

1111
os:
1212
- linux

CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
- To retrieve the value of an asynchronous `value`, use `value.await`
1010
- This is only possible within an `async fn`, so either
1111
- Make the caller `fn` of `.await` an `async fn`
12-
- Not recommended: Use `core::executor::block_on(value)` to retrieve the `value`
12+
- Not recommended: Use `libtock::executor::block_on(value)` to retrieve the `value`
1313
- Most API functions, including `main()`, return a `Result<T, TockError>`
1414
- All drivers can exclusively be retrieved by `retrieve_drivers` which returns a `Drivers` singleton. Drivers can be shared between different tasks only if it is safe to do so.
15+
- The low-level functions have been moved to a new crate called `libtock-core`. This crate is intended to be less experimental and more stable.
1516

1617
### Changed APIs
1718

@@ -42,6 +43,8 @@
4243
- Targets without support for atomics can be built
4344
- The `TockAllocator` is no longer included by default and needs to to be opted-in via `--features=alloc`
4445
- `hardware_test.rs` is now called `libtock_test.rs` to make clear that the intent is to test the correctness of `libtock-rs`, not the hardware or the kernel
46+
- The panic handler can now be customized using the `custom_panic_handler` feature
47+
- The error alloc handler can now be customized using the `custom_alloc_error_handler` feature
4548

4649
## a8bb4fa9be504517d5533511fd8e607ea61f1750 (0.1.0)
4750

Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ custom_alloc_error_handler = ["libtock-core/custom_alloc_error_handler"]
1212
__internal_disable_gpio_in_integration_test = []
1313

1414
[dependencies]
15-
core = { package = "async-support", path = "async-support" }
1615
libtock-core = { path = "core" }
1716
libtock_codegen = { path = "codegen" }
1817
futures = { version = "0.3.1", default-features = false, features = ["unstable", "cfg-target-has-atomic"] }
@@ -58,7 +57,6 @@ lto = true
5857

5958
[workspace]
6059
members = [
61-
"async-support",
6260
"codegen",
6361
"core",
6462
"test-runner"

async-support/Cargo.toml

-8
This file was deleted.

async-support/src/lib.rs

-109
This file was deleted.

build.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,25 @@ use std::io::BufReader;
66
use std::path::Path;
77
use std::process;
88

9+
static LAYOUT_FILE_NAME: &str = "layout.ld";
10+
911
fn main() {
10-
static ENV_VAR: &str = "PLATFORM";
11-
static FILE_NAME: &str = "platform";
12+
static PLATFORM_ENV_VAR: &str = "PLATFORM";
13+
static PLATFORM_FILE_NAME: &str = "platform";
1214
static APP_HEAP_SIZE: &str = "APP_HEAP_SIZE";
1315
static KERNEL_HEAP_SIZE: &str = "KERNEL_HEAP_SIZE";
1416

15-
println!("cargo:rerun-if-env-changed={}", ENV_VAR);
17+
println!("cargo:rerun-if-env-changed={}", PLATFORM_ENV_VAR);
1618
println!("cargo:rerun-if-env-changed={}", APP_HEAP_SIZE);
1719
println!("cargo:rerun-if-env-changed={}", KERNEL_HEAP_SIZE);
18-
println!("cargo:rerun-if-changed={}", FILE_NAME);
20+
println!("cargo:rerun-if-changed={}", PLATFORM_FILE_NAME);
21+
println!("cargo:rerun-if-changed={}", LAYOUT_FILE_NAME);
1922

20-
let platform_name = read_env_var(ENV_VAR).or_else(|| read_board_name_from_file(FILE_NAME));
23+
let platform_name =
24+
read_env_var(PLATFORM_ENV_VAR).or_else(|| read_board_name_from_file(PLATFORM_FILE_NAME));
2125
if let Some(platform_name) = platform_name {
22-
println!("cargo:rustc-env={}={}", ENV_VAR, platform_name);
23-
copy_linker_file(&platform_name.trim());
26+
println!("cargo:rustc-env={}={}", PLATFORM_ENV_VAR, platform_name);
27+
copy_linker_file(platform_name.trim());
2428
} else {
2529
println!(
2630
"cargo:warning=No platform specified. \
@@ -66,5 +70,5 @@ fn copy_linker_file(platform_name: &str) {
6670
println!("Cannot find layout file {:?}", path);
6771
process::exit(1);
6872
}
69-
fs::copy(linker_file_name, "layout.ld").unwrap();
73+
fs::copy(linker_file_name, LAYOUT_FILE_NAME).unwrap();
7074
}

codegen/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ fn try_generate_main_wrapped(
9898
MAIN_INVOKED = true;
9999
}
100100
let _block = async #block;
101-
unsafe {::core::executor::block_on(_block) }
101+
unsafe { ::libtock::executor::block_on(_block) }
102102
}
103103
))
104104
}
@@ -126,7 +126,7 @@ mod tests {
126126
let _block = async {
127127
method_call().await;
128128
};
129-
unsafe { ::core::executor::block_on(_block) }
129+
unsafe { ::libtock::executor::block_on(_block) }
130130
}
131131
))
132132
.unwrap();

core/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ custom_panic_handler = []
1010
custom_alloc_error_handler = []
1111

1212
[dependencies]
13-
linked_list_allocator = { optional = true, version = "=0.6.5", default-features = false }
13+
linked_list_allocator = { optional = true, version = "=0.8.1", default-features = false }
1414
libtock_codegen = { path = "../codegen" }

core/src/entry_point/start_item_arm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub unsafe extern "C" fn _start(
105105
bl rust_start"
106106
: // No output operands
107107
: "{r0}"(app_start), "{r1}"(mem_start), "{r3}"(app_heap_break) // Input operands
108-
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r12",
108+
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r12",
109109
"cc", "memory" // Clobbers
110110
: "volatile" // Options
111111
);

core/src/syscalls/mod.rs

+1-17
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,7 @@ use crate::result::SubscribeError;
1010
use crate::shared_memory::SharedMemory;
1111

1212
pub mod raw {
13-
use super::platform;
14-
15-
pub use platform::*;
16-
17-
/// # Safety
18-
///
19-
/// Yielding in the main function should be safe. Nevertheless, yielding manually is not required as this is already achieved by the `async` runtime.
20-
///
21-
/// When yielding in callbacks, two problems can arise:
22-
/// - The guarantees of `FnMut` are violated. In this case, make sure your callback has `Fn` behavior.
23-
/// - Callbacks can get executed in a nested manner and overflow the stack quickly.
24-
///
25-
/// This function is exported as `libtock::syscalls::raw::yieldk`. Do not reference this name directly. Its only purpose is to establish a back-channel from `async-support`, a patched version of `core` to `libtock-rs` via linking. This workaround has been chosen to keep the `core` crate free of dependencies on platform-specific syscall implementations and is expected to get removed as soon as possible.
26-
#[export_name = "libtock::syscalls::raw::yieldk"]
27-
pub unsafe fn yieldk() {
28-
platform::yieldk()
29-
}
13+
pub use super::platform::*;
3014
}
3115

3216
pub fn subscribe<C: Consumer<T>, T>(

core/src/syscalls/platform.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ use core::cell::RefCell;
33
use std::vec::Vec;
44

55
/// yield for a callback fired by the kernel
6+
///
67
/// # Safety
7-
/// Yielding inside a callback conflicts with Rust's safety guarantees. For example,
8-
/// a FnMut closure could be triggered multiple times making a &mut a shared reference.
8+
///
9+
/// Yielding in the main function should be safe. Nevertheless, yielding manually
10+
/// is not required as this is already achieved by the `async` runtime.
11+
///
12+
/// When yielding in callbacks, two problems can arise:
13+
/// - The guarantees of `FnMut` are violated. In this case, make sure your callback has `Fn` behavior.
14+
/// - Callbacks can get executed in a nested manner and overflow the stack quickly.
915
pub unsafe fn yieldk() {
1016
EVENTS.with(|e| e.borrow_mut().push(Event::YieldK));
1117
}

rust-toolchain

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2020-01-16
1+
nightly-2020-04-06

src/console.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::callback::Identity0Consumer;
2+
use crate::executor;
23
use crate::futures;
34
use crate::result::TockResult;
45
use crate::syscalls;
56
use core::cell::Cell;
6-
use core::executor;
77
use core::fmt;
88
use core::mem;
99

src/drivers.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::gpio::GpioDriverFactory;
55
use crate::leds::LedsDriverFactory;
66
use crate::result::OtherError;
77
use crate::result::TockError;
8-
use crate::result::TockResult;
98
use crate::rng::RngDriver;
109
use crate::sensors::ninedof::NinedofDriver;
1110
use crate::sensors::AmbientLightSensor;
@@ -37,12 +36,12 @@ pub struct Drivers {
3736
}
3837

3938
/// Retrieve [Drivers] struct. Returns struct only once.
40-
pub fn retrieve_drivers() -> TockResult<Drivers> {
39+
pub fn retrieve_drivers() -> Result<Drivers, DriversAlreadyTakenError> {
4140
static mut DRIVER_TAKEN: bool = false;
4241

4342
unsafe {
4443
if DRIVER_TAKEN {
45-
Err(TockError::Other(OtherError::DriverAlreadyTaken))
44+
Err(DriversAlreadyTakenError)
4645
} else {
4746
DRIVER_TAKEN = true;
4847
Ok(retrieve_drivers_unsafe())
@@ -79,3 +78,11 @@ const DRIVERS: Drivers = Drivers {
7978
humidity_sensor: HumiditySensor,
8079
ninedof: NinedofDriver,
8180
};
81+
82+
pub struct DriversAlreadyTakenError;
83+
84+
impl From<DriversAlreadyTakenError> for TockError {
85+
fn from(_: DriversAlreadyTakenError) -> Self {
86+
TockError::Other(OtherError::DriversAlreadyTaken)
87+
}
88+
}

src/executor.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use crate::syscalls;
2+
use core::pin::Pin;
3+
use core::ptr;
4+
use core::task::Context;
5+
use core::task::Poll;
6+
use core::task::RawWaker;
7+
use core::task::RawWakerVTable;
8+
use core::task::Waker;
9+
use futures::Future;
10+
11+
/// # Safety
12+
///
13+
/// [[block_on]] yields whenever a future cannot make any progress at present. Yielding is considered unsafe.
14+
pub unsafe fn block_on<T>(mut future: impl Future<Output = T>) -> T {
15+
// Contract described in the Rustdoc: "A value, once pinned, must remain pinned forever (...).".
16+
// IOW calling Pin::new_unchecked is safe as long as no &mut future is leaked after pinning.
17+
let mut pinned_future = Pin::new_unchecked(&mut future);
18+
19+
loop {
20+
match poll(pinned_future.as_mut()) {
21+
Poll::Pending => syscalls::raw::yieldk(),
22+
Poll::Ready(value) => {
23+
return value;
24+
}
25+
}
26+
}
27+
}
28+
29+
fn poll<F: Future>(pinned_future: Pin<&mut F>) -> Poll<F::Output> {
30+
let waker = unsafe { Waker::from_raw(get_dummy_waker()) };
31+
let mut context = Context::from_waker(&waker);
32+
pinned_future.poll(&mut context)
33+
}
34+
35+
// Since Tock OS comes with waking-up functionality built-in, we use dummy wakers that do nothing at all.
36+
fn get_dummy_waker() -> RawWaker {
37+
fn clone(_x: *const ()) -> RawWaker {
38+
get_dummy_waker()
39+
}
40+
41+
fn do_nothing(_x: *const ()) {}
42+
43+
// This vtable implements the methods required for managing the lifecycle of the wakers.
44+
// Our wakers are dummies, so those functions don't do anything.
45+
static DUMMY_WAKER_VTABLE: RawWakerVTable =
46+
RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing);
47+
48+
// The wakers don't have any implementation, so the instance can simply be null.
49+
RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE)
50+
}

0 commit comments

Comments
 (0)