Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Decommission async-support #170

Merged
merged 8 commits into from
Apr 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Cargo.lock
layout.ld
platform
target
/Cargo.lock
/layout.ld
/platform
/target
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ branches:

language: rust
rust:
- nightly-2020-01-16
- nightly-2020-04-06

os:
- linux
Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
- To retrieve the value of an asynchronous `value`, use `value.await`
- This is only possible within an `async fn`, so either
- Make the caller `fn` of `.await` an `async fn`
- Not recommended: Use `core::executor::block_on(value)` to retrieve the `value`
- Not recommended: Use `libtock::executor::block_on(value)` to retrieve the `value`
- Most API functions, including `main()`, return a `Result<T, TockError>`
- 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.
- 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.

### Changed APIs

Expand Down Expand Up @@ -42,6 +43,8 @@
- Targets without support for atomics can be built
- The `TockAllocator` is no longer included by default and needs to to be opted-in via `--features=alloc`
- `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
- The panic handler can now be customized using the `custom_panic_handler` feature
- The error alloc handler can now be customized using the `custom_alloc_error_handler` feature

## a8bb4fa9be504517d5533511fd8e607ea61f1750 (0.1.0)

Expand Down
2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ custom_alloc_error_handler = ["libtock-core/custom_alloc_error_handler"]
__internal_disable_gpio_in_integration_test = []

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

[workspace]
members = [
"async-support",
"codegen",
"core",
"test-runner"
Expand Down
8 changes: 0 additions & 8 deletions async-support/Cargo.toml

This file was deleted.

109 changes: 0 additions & 109 deletions async-support/src/lib.rs

This file was deleted.

20 changes: 12 additions & 8 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ use std::io::BufReader;
use std::path::Path;
use std::process;

static LAYOUT_FILE_NAME: &str = "layout.ld";

fn main() {
static ENV_VAR: &str = "PLATFORM";
static FILE_NAME: &str = "platform";
static PLATFORM_ENV_VAR: &str = "PLATFORM";
static PLATFORM_FILE_NAME: &str = "platform";
static APP_HEAP_SIZE: &str = "APP_HEAP_SIZE";
static KERNEL_HEAP_SIZE: &str = "KERNEL_HEAP_SIZE";

println!("cargo:rerun-if-env-changed={}", ENV_VAR);
println!("cargo:rerun-if-env-changed={}", PLATFORM_ENV_VAR);
println!("cargo:rerun-if-env-changed={}", APP_HEAP_SIZE);
println!("cargo:rerun-if-env-changed={}", KERNEL_HEAP_SIZE);
println!("cargo:rerun-if-changed={}", FILE_NAME);
println!("cargo:rerun-if-changed={}", PLATFORM_FILE_NAME);
println!("cargo:rerun-if-changed={}", LAYOUT_FILE_NAME);

let platform_name = read_env_var(ENV_VAR).or_else(|| read_board_name_from_file(FILE_NAME));
let platform_name =
read_env_var(PLATFORM_ENV_VAR).or_else(|| read_board_name_from_file(PLATFORM_FILE_NAME));
if let Some(platform_name) = platform_name {
println!("cargo:rustc-env={}={}", ENV_VAR, platform_name);
copy_linker_file(&platform_name.trim());
println!("cargo:rustc-env={}={}", PLATFORM_ENV_VAR, platform_name);
copy_linker_file(platform_name.trim());
} else {
println!(
"cargo:warning=No platform specified. \
Expand Down Expand Up @@ -66,5 +70,5 @@ fn copy_linker_file(platform_name: &str) {
println!("Cannot find layout file {:?}", path);
process::exit(1);
}
fs::copy(linker_file_name, "layout.ld").unwrap();
fs::copy(linker_file_name, LAYOUT_FILE_NAME).unwrap();
}
4 changes: 2 additions & 2 deletions codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fn try_generate_main_wrapped(
MAIN_INVOKED = true;
}
let _block = async #block;
unsafe {::core::executor::block_on(_block) }
unsafe { ::libtock::executor::block_on(_block) }
}
))
}
Expand Down Expand Up @@ -126,7 +126,7 @@ mod tests {
let _block = async {
method_call().await;
};
unsafe { ::core::executor::block_on(_block) }
unsafe { ::libtock::executor::block_on(_block) }
}
))
.unwrap();
Expand Down
2 changes: 1 addition & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ custom_panic_handler = []
custom_alloc_error_handler = []

[dependencies]
linked_list_allocator = { optional = true, version = "=0.6.5", default-features = false }
linked_list_allocator = { optional = true, version = "=0.8.1", default-features = false }
libtock_codegen = { path = "../codegen" }
2 changes: 1 addition & 1 deletion core/src/entry_point/start_item_arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub unsafe extern "C" fn _start(
bl rust_start"
: // No output operands
: "{r0}"(app_start), "{r1}"(mem_start), "{r3}"(app_heap_break) // Input operands
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r12",
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r12",
"cc", "memory" // Clobbers
: "volatile" // Options
);
Expand Down
18 changes: 1 addition & 17 deletions core/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,7 @@ use crate::result::SubscribeError;
use crate::shared_memory::SharedMemory;

pub mod raw {
use super::platform;

pub use platform::*;

/// # Safety
///
/// Yielding in the main function should be safe. Nevertheless, yielding manually is not required as this is already achieved by the `async` runtime.
///
/// When yielding in callbacks, two problems can arise:
/// - The guarantees of `FnMut` are violated. In this case, make sure your callback has `Fn` behavior.
/// - Callbacks can get executed in a nested manner and overflow the stack quickly.
///
/// 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.
#[export_name = "libtock::syscalls::raw::yieldk"]
pub unsafe fn yieldk() {
platform::yieldk()
}
pub use super::platform::*;
}

pub fn subscribe<C: Consumer<T>, T>(
Expand Down
10 changes: 8 additions & 2 deletions core/src/syscalls/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ use core::cell::RefCell;
use std::vec::Vec;

/// yield for a callback fired by the kernel
///
/// # Safety
/// Yielding inside a callback conflicts with Rust's safety guarantees. For example,
/// a FnMut closure could be triggered multiple times making a &mut a shared reference.
///
/// Yielding in the main function should be safe. Nevertheless, yielding manually
/// is not required as this is already achieved by the `async` runtime.
///
/// When yielding in callbacks, two problems can arise:
/// - The guarantees of `FnMut` are violated. In this case, make sure your callback has `Fn` behavior.
/// - Callbacks can get executed in a nested manner and overflow the stack quickly.
pub unsafe fn yieldk() {
EVENTS.with(|e| e.borrow_mut().push(Event::YieldK));
}
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nightly-2020-01-16
nightly-2020-04-06
2 changes: 1 addition & 1 deletion src/console.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::callback::Identity0Consumer;
use crate::executor;
use crate::futures;
use crate::result::TockResult;
use crate::syscalls;
use core::cell::Cell;
use core::executor;
use core::fmt;
use core::mem;

Expand Down
13 changes: 10 additions & 3 deletions src/drivers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::gpio::GpioDriverFactory;
use crate::leds::LedsDriverFactory;
use crate::result::OtherError;
use crate::result::TockError;
use crate::result::TockResult;
use crate::rng::RngDriver;
use crate::sensors::ninedof::NinedofDriver;
use crate::sensors::AmbientLightSensor;
Expand Down Expand Up @@ -37,12 +36,12 @@ pub struct Drivers {
}

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

unsafe {
if DRIVER_TAKEN {
Err(TockError::Other(OtherError::DriverAlreadyTaken))
Err(DriversAlreadyTakenError)
} else {
DRIVER_TAKEN = true;
Ok(retrieve_drivers_unsafe())
Expand Down Expand Up @@ -79,3 +78,11 @@ const DRIVERS: Drivers = Drivers {
humidity_sensor: HumiditySensor,
ninedof: NinedofDriver,
};

pub struct DriversAlreadyTakenError;

impl From<DriversAlreadyTakenError> for TockError {
fn from(_: DriversAlreadyTakenError) -> Self {
TockError::Other(OtherError::DriversAlreadyTaken)
}
}
50 changes: 50 additions & 0 deletions src/executor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::syscalls;
use core::pin::Pin;
use core::ptr;
use core::task::Context;
use core::task::Poll;
use core::task::RawWaker;
use core::task::RawWakerVTable;
use core::task::Waker;
use futures::Future;

/// # Safety
///
/// [[block_on]] yields whenever a future cannot make any progress at present. Yielding is considered unsafe.
pub unsafe fn block_on<T>(mut future: impl Future<Output = T>) -> T {
// Contract described in the Rustdoc: "A value, once pinned, must remain pinned forever (...).".
// IOW calling Pin::new_unchecked is safe as long as no &mut future is leaked after pinning.
let mut pinned_future = Pin::new_unchecked(&mut future);

loop {
match poll(pinned_future.as_mut()) {
Poll::Pending => syscalls::raw::yieldk(),
Poll::Ready(value) => {
return value;
}
}
}
}

fn poll<F: Future>(pinned_future: Pin<&mut F>) -> Poll<F::Output> {
let waker = unsafe { Waker::from_raw(get_dummy_waker()) };
let mut context = Context::from_waker(&waker);
pinned_future.poll(&mut context)
}

// Since Tock OS comes with waking-up functionality built-in, we use dummy wakers that do nothing at all.
fn get_dummy_waker() -> RawWaker {
fn clone(_x: *const ()) -> RawWaker {
get_dummy_waker()
}

fn do_nothing(_x: *const ()) {}

// This vtable implements the methods required for managing the lifecycle of the wakers.
// Our wakers are dummies, so those functions don't do anything.
static DUMMY_WAKER_VTABLE: RawWakerVTable =
RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing);

// The wakers don't have any implementation, so the instance can simply be null.
RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE)
}
Loading