mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-04 17:27:16 +01:00
Merge #153
153: add "nightly" feature; replace hint::unreachable_unchecked with a panic r=korken89 a=japaric this implements the action plan described in #149 to give you a sense of the overhead of this change: it has increased the binary size of some of our examples by up to 10% but this is mainly from pulling in a panic handler that does formatting r? @korken89 Co-authored-by: Jorge Aparicio <jorge@japaric.io>
This commit is contained in:
commit
6b61cd2e3f
6 changed files with 276 additions and 118 deletions
|
@ -51,6 +51,7 @@ features = ["exit"]
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
nightly = ["cortex-m-rtfm-macros/nightly", "heapless/const-fn"]
|
||||||
timer-queue = ["cortex-m-rtfm-macros/timer-queue"]
|
timer-queue = ["cortex-m-rtfm-macros/timer-queue"]
|
||||||
|
|
||||||
[target.x86_64-unknown-linux-gnu.dev-dependencies]
|
[target.x86_64-unknown-linux-gnu.dev-dependencies]
|
||||||
|
|
46
ci/script.sh
46
ci/script.sh
|
@ -33,6 +33,11 @@ arm_example() {
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
local T=$TARGET
|
local T=$TARGET
|
||||||
|
local nightly=""
|
||||||
|
|
||||||
|
if [ $TRAVIS_RUST_VERSION = nightly ]; then
|
||||||
|
nightly="nightly"
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p ci/builds
|
mkdir -p ci/builds
|
||||||
|
|
||||||
|
@ -41,12 +46,12 @@ main() {
|
||||||
case $TRAVIS_RUST_VERSION in
|
case $TRAVIS_RUST_VERSION in
|
||||||
nightly*)
|
nightly*)
|
||||||
# TODO how to run a subset of these tests when timer-queue is disabled?
|
# TODO how to run a subset of these tests when timer-queue is disabled?
|
||||||
cargo test --features timer-queue --test compiletest --target $T
|
cargo test --features "$nightly,timer-queue" --test compiletest --target $T
|
||||||
esac
|
esac
|
||||||
|
|
||||||
cargo check --target $T
|
cargo check --target $T
|
||||||
if [ $TARGET != thumbv6m-none-eabi ]; then
|
if [ $TARGET != thumbv6m-none-eabi ]; then
|
||||||
cargo check --features timer-queue --target $T
|
cargo check --features "$nightly,timer-queue" --target $T
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $TRAVIS_RUST_VERSION != nightly ]; then
|
if [ $TRAVIS_RUST_VERSION != nightly ]; then
|
||||||
|
@ -76,9 +81,9 @@ main() {
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cargo check --target $T --examples
|
cargo check --features "$nightly" --target $T --examples
|
||||||
if [ $TARGET != thumbv6m-none-eabi ]; then
|
if [ $TARGET != thumbv6m-none-eabi ]; then
|
||||||
cargo check --features timer-queue --target $T --examples
|
cargo check --features "$nightly,timer-queue" --target $T --examples
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# run-pass tests
|
# run-pass tests
|
||||||
|
@ -115,16 +120,17 @@ main() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $ex != types ]; then
|
if [ $ex != types ]; then
|
||||||
arm_example "run" $ex "debug" "" "1"
|
arm_example "run" $ex "debug" "$nightly" "1"
|
||||||
arm_example "run" $ex "release" "" "1"
|
arm_example "run" $ex "release" "$nightly" "1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $TARGET != thumbv6m-none-eabi ]; then
|
if [ $TARGET != thumbv6m-none-eabi ]; then
|
||||||
arm_example "run" $ex "debug" "timer-queue" "1"
|
arm_example "run" $ex "debug" "$nightly,timer-queue" "1"
|
||||||
arm_example "run" $ex "release" "timer-queue" "1"
|
arm_example "run" $ex "release" "$nightly,timer-queue" "1"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
local built=()
|
||||||
cargo clean
|
cargo clean
|
||||||
for ex in ${exs[@]}; do
|
for ex in ${exs[@]}; do
|
||||||
if [ $ex = ramfunc ] && [ $T = thumbv6m-none-eabi ]; then
|
if [ $ex = ramfunc ] && [ $T = thumbv6m-none-eabi ]; then
|
||||||
|
@ -139,19 +145,27 @@ main() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $ex != types ]; then
|
if [ $ex != types ]; then
|
||||||
arm_example "build" $ex "debug" "" "2"
|
arm_example "build" $ex "debug" "$nightly" "2"
|
||||||
cmp ci/builds/${ex}_debug_1.hex ci/builds/${ex}_debug_2.hex
|
cmp ci/builds/${ex}_${nightly/nightly/nightly_}debug_1.hex \
|
||||||
arm_example "build" $ex "release" "" "2"
|
ci/builds/${ex}_${nightly/nightly/nightly_}debug_2.hex
|
||||||
cmp ci/builds/${ex}_release_1.hex ci/builds/${ex}_release_2.hex
|
arm_example "build" $ex "release" "$nightly" "2"
|
||||||
|
cmp ci/builds/${ex}_${nightly/nightly/nightly_}release_1.hex \
|
||||||
|
ci/builds/${ex}_${nightly/nightly/nightly_}release_2.hex
|
||||||
|
|
||||||
|
built+=( $ex )
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $TARGET != thumbv6m-none-eabi ]; then
|
if [ $TARGET != thumbv6m-none-eabi ]; then
|
||||||
arm_example "build" $ex "debug" "timer-queue" "2"
|
arm_example "build" $ex "debug" "$nightly,timer-queue" "2"
|
||||||
cmp ci/builds/${ex}_timer-queue_debug_1.hex ci/builds/${ex}_timer-queue_debug_2.hex
|
cmp ci/builds/${ex}_${nightly}_timer-queue_debug_1.hex \
|
||||||
arm_example "build" $ex "release" "timer-queue" "2"
|
ci/builds/${ex}_${nightly}_timer-queue_debug_2.hex
|
||||||
cmp ci/builds/${ex}_timer-queue_release_1.hex ci/builds/${ex}_timer-queue_release_2.hex
|
arm_example "build" $ex "release" "$nightly,timer-queue" "2"
|
||||||
|
cmp ci/builds/${ex}_${nightly}_timer-queue_release_1.hex \
|
||||||
|
ci/builds/${ex}_${nightly}_timer-queue_release_2.hex
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
( cd target/$TARGET/release/examples/ && size ${built[@]} )
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,3 +28,4 @@ version = "0.5.5"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
timer-queue = []
|
timer-queue = []
|
||||||
|
nightly = []
|
|
@ -283,7 +283,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
|
||||||
if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) {
|
if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) {
|
||||||
if res.mutability.is_some() {
|
if res.mutability.is_some() {
|
||||||
let ptr = if res.expr.is_none() {
|
let ptr = if res.expr.is_none() {
|
||||||
quote!(unsafe { #alias.get_mut() })
|
quote!(unsafe { &mut *#alias.as_mut_ptr() })
|
||||||
} else {
|
} else {
|
||||||
quote!(unsafe { &mut #alias })
|
quote!(unsafe { &mut #alias })
|
||||||
};
|
};
|
||||||
|
@ -494,8 +494,10 @@ fn post_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
// Enable and start the system timer
|
// Enable and start the system timer
|
||||||
if !analysis.timer_queue.tasks.is_empty() {
|
if !analysis.timer_queue.tasks.is_empty() {
|
||||||
let tq = &ctxt.timer_queue;
|
let tq = &ctxt.timer_queue;
|
||||||
exprs.push(quote!(#tq.get_mut().syst.set_clock_source(rtfm::export::SystClkSource::Core)));
|
exprs.push(
|
||||||
exprs.push(quote!(#tq.get_mut().syst.enable_counter()));
|
quote!((*#tq.as_mut_ptr()).syst.set_clock_source(rtfm::export::SystClkSource::Core)),
|
||||||
|
);
|
||||||
|
exprs.push(quote!((*#tq.as_mut_ptr()).syst.enable_counter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable cycle counter
|
// Enable cycle counter
|
||||||
|
@ -903,21 +905,21 @@ fn prelude(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let method = if mut_.is_some() {
|
let expr = if mut_.is_some() {
|
||||||
quote!(get_mut)
|
quote!(&mut *#alias.as_mut_ptr())
|
||||||
} else {
|
} else {
|
||||||
quote!(get_ref)
|
quote!(&*#alias.as_ptr())
|
||||||
};
|
};
|
||||||
|
|
||||||
if exclusive {
|
if exclusive {
|
||||||
exprs.push(quote!(
|
exprs.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#name: rtfm::Exclusive(#alias.#method())
|
#name: rtfm::Exclusive(#expr)
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
exprs.push(quote!(
|
exprs.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#name: #alias.#method()
|
#name: #expr
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1254,8 +1256,9 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
|
|
||||||
let ty = tuple_ty(inputs);
|
let ty = tuple_ty(inputs);
|
||||||
|
|
||||||
let capacity_lit = mk_capacity_literal(analysis.capacities[name]);
|
let capacity = analysis.capacities[name];
|
||||||
let capacity_ty = mk_typenum_capacity(analysis.capacities[name], true);
|
let capacity_lit = mk_capacity_literal(capacity);
|
||||||
|
let capacity_ty = mk_typenum_capacity(capacity, true);
|
||||||
|
|
||||||
let resource = mk_resource(
|
let resource = mk_resource(
|
||||||
ctxt,
|
ctxt,
|
||||||
|
@ -1263,7 +1266,11 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
&free_alias,
|
&free_alias,
|
||||||
quote!(rtfm::export::FreeQueue<#capacity_ty>),
|
quote!(rtfm::export::FreeQueue<#capacity_ty>),
|
||||||
*analysis.free_queues.get(name).unwrap_or(&0),
|
*analysis.free_queues.get(name).unwrap_or(&0),
|
||||||
quote!(#free_alias.get_mut()),
|
if cfg!(feature = "nightly") {
|
||||||
|
quote!(&mut #free_alias)
|
||||||
|
} else {
|
||||||
|
quote!(#free_alias.get_mut())
|
||||||
|
},
|
||||||
app,
|
app,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -1273,12 +1280,24 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
() => {
|
() => {
|
||||||
let scheduleds_symbol = format!("{}::SCHEDULED_TIMES::{}", name, scheduleds_alias);
|
let scheduleds_symbol = format!("{}::SCHEDULED_TIMES::{}", name, scheduleds_alias);
|
||||||
|
|
||||||
quote!(
|
if cfg!(feature = "nightly") {
|
||||||
#[doc = #scheduleds_symbol]
|
let inits =
|
||||||
static mut #scheduleds_alias:
|
(0..capacity).map(|_| quote!(rtfm::export::MaybeUninit::uninitialized()));
|
||||||
rtfm::export::MaybeUninit<[rtfm::Instant; #capacity_lit]> =
|
|
||||||
rtfm::export::MaybeUninit::uninitialized();
|
quote!(
|
||||||
)
|
#[doc = #scheduleds_symbol]
|
||||||
|
static mut #scheduleds_alias:
|
||||||
|
[rtfm::export::MaybeUninit<rtfm::Instant>; #capacity_lit] =
|
||||||
|
[#(#inits),*];
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
quote!(
|
||||||
|
#[doc = #scheduleds_symbol]
|
||||||
|
static mut #scheduleds_alias:
|
||||||
|
rtfm::export::MaybeUninit<[rtfm::Instant; #capacity_lit]> =
|
||||||
|
rtfm::export::MaybeUninit::uninitialized();
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
|
@ -1286,20 +1305,36 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
|
|
||||||
let inputs_symbol = format!("{}::INPUTS::{}", name, inputs_alias);
|
let inputs_symbol = format!("{}::INPUTS::{}", name, inputs_alias);
|
||||||
let free_symbol = format!("{}::FREE_QUEUE::{}", name, free_alias);
|
let free_symbol = format!("{}::FREE_QUEUE::{}", name, free_alias);
|
||||||
items.push(quote!(
|
if cfg!(feature = "nightly") {
|
||||||
// FIXME(MaybeUninit) MaybeUninit won't be necessary when core::mem::MaybeUninit
|
let inits = (0..capacity).map(|_| quote!(rtfm::export::MaybeUninit::uninitialized()));
|
||||||
// stabilizes because heapless constructors will work in const context
|
|
||||||
#[doc = #free_symbol]
|
items.push(quote!(
|
||||||
static mut #free_alias: rtfm::export::MaybeUninit<
|
#[doc = #free_symbol]
|
||||||
|
static mut #free_alias: rtfm::export::FreeQueue<#capacity_ty> = unsafe {
|
||||||
|
rtfm::export::FreeQueue::new_sc()
|
||||||
|
};
|
||||||
|
|
||||||
|
#[doc = #inputs_symbol]
|
||||||
|
static mut #inputs_alias: [rtfm::export::MaybeUninit<#ty>; #capacity_lit] =
|
||||||
|
[#(#inits),*];
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
items.push(quote!(
|
||||||
|
#[doc = #free_symbol]
|
||||||
|
static mut #free_alias: rtfm::export::MaybeUninit<
|
||||||
rtfm::export::FreeQueue<#capacity_ty>
|
rtfm::export::FreeQueue<#capacity_ty>
|
||||||
> = rtfm::export::MaybeUninit::uninitialized();
|
> = rtfm::export::MaybeUninit::uninitialized();
|
||||||
|
|
||||||
|
#[doc = #inputs_symbol]
|
||||||
|
static mut #inputs_alias: rtfm::export::MaybeUninit<[#ty; #capacity_lit]> =
|
||||||
|
rtfm::export::MaybeUninit::uninitialized();
|
||||||
|
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push(quote!(
|
||||||
#resource
|
#resource
|
||||||
|
|
||||||
#[doc = #inputs_symbol]
|
|
||||||
static mut #inputs_alias: rtfm::export::MaybeUninit<[#ty; #capacity_lit]> =
|
|
||||||
rtfm::export::MaybeUninit::uninitialized();
|
|
||||||
|
|
||||||
#scheduleds_static
|
#scheduleds_static
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1428,18 +1463,31 @@ fn dispatchers(
|
||||||
&ready_alias,
|
&ready_alias,
|
||||||
ty.clone(),
|
ty.clone(),
|
||||||
ceiling,
|
ceiling,
|
||||||
quote!(#ready_alias.get_mut()),
|
if cfg!(feature = "nightly") {
|
||||||
|
quote!(&mut #ready_alias)
|
||||||
|
} else {
|
||||||
|
quote!(#ready_alias.get_mut())
|
||||||
|
},
|
||||||
app,
|
app,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if cfg!(feature = "nightly") {
|
||||||
|
data.push(quote!(
|
||||||
|
#[doc = #symbol]
|
||||||
|
static mut #ready_alias: #ty = unsafe { #e::ReadyQueue::new_sc() };
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
data.push(quote!(
|
||||||
|
#[doc = #symbol]
|
||||||
|
static mut #ready_alias: #e::MaybeUninit<#ty> = #e::MaybeUninit::uninitialized();
|
||||||
|
));
|
||||||
|
}
|
||||||
data.push(quote!(
|
data.push(quote!(
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
enum #enum_alias { #(#variants,)* }
|
enum #enum_alias { #(#variants,)* }
|
||||||
|
|
||||||
#[doc = #symbol]
|
|
||||||
static mut #ready_alias: #e::MaybeUninit<#ty> = #e::MaybeUninit::uninitialized();
|
|
||||||
|
|
||||||
#resource
|
#resource
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1462,9 +1510,14 @@ fn dispatchers(
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => {
|
() => {
|
||||||
let scheduleds = &task_.scheduleds;
|
let scheduleds = &task_.scheduleds;
|
||||||
|
let scheduled = if cfg!(feature = "nightly") {
|
||||||
|
quote!(#scheduleds.get_unchecked(usize::from(index)).as_ptr())
|
||||||
|
} else {
|
||||||
|
quote!(#scheduleds.get_ref().get_unchecked(usize::from(index)))
|
||||||
|
};
|
||||||
|
|
||||||
baseline_let = quote!(
|
baseline_let = quote!(
|
||||||
let baseline =
|
let baseline = ptr::read(#scheduled);
|
||||||
ptr::read(#scheduleds.get_ref().get_unchecked(usize::from(index)));
|
|
||||||
);
|
);
|
||||||
call = quote!(#alias(&baseline, #pats));
|
call = quote!(#alias(&baseline, #pats));
|
||||||
}
|
}
|
||||||
|
@ -1475,12 +1528,24 @@ fn dispatchers(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (free_, input) = if cfg!(feature = "nightly") {
|
||||||
|
(
|
||||||
|
quote!(#free),
|
||||||
|
quote!(#inputs.get_unchecked(usize::from(index)).as_ptr()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
quote!(#free.get_mut()),
|
||||||
|
quote!(#inputs.get_ref().get_unchecked(usize::from(index))),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#enum_alias::#task => {
|
#enum_alias::#task => {
|
||||||
#baseline_let
|
#baseline_let
|
||||||
let input = ptr::read(#inputs.get_ref().get_unchecked(usize::from(index)));
|
let input = ptr::read(#input);
|
||||||
#free.get_mut().split().0.enqueue_unchecked(index);
|
#free_.split().0.enqueue_unchecked(index);
|
||||||
let (#pats) = input;
|
let (#pats) = input;
|
||||||
#call
|
#call
|
||||||
}
|
}
|
||||||
|
@ -1492,6 +1557,11 @@ fn dispatchers(
|
||||||
let interrupt = &dispatcher.interrupt;
|
let interrupt = &dispatcher.interrupt;
|
||||||
let symbol = interrupt.to_string();
|
let symbol = interrupt.to_string();
|
||||||
let alias = ctxt.ident_gen.mk_ident(None, false);
|
let alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
|
let ready_alias_ = if cfg!(feature = "nightly") {
|
||||||
|
quote!(#ready_alias)
|
||||||
|
} else {
|
||||||
|
quote!(#ready_alias.get_mut())
|
||||||
|
};
|
||||||
dispatchers.push(quote!(
|
dispatchers.push(quote!(
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#[export_name = #symbol]
|
#[export_name = #symbol]
|
||||||
|
@ -1502,7 +1572,7 @@ fn dispatchers(
|
||||||
let _ = #device::interrupt::#interrupt;
|
let _ = #device::interrupt::#interrupt;
|
||||||
|
|
||||||
rtfm::export::run(|| {
|
rtfm::export::run(|| {
|
||||||
while let Some((task, index)) = #ready_alias.get_mut().split().1.dequeue() {
|
while let Some((task, index)) = #ready_alias_.split().1.dequeue() {
|
||||||
match task {
|
match task {
|
||||||
#(#arms)*
|
#(#arms)*
|
||||||
}
|
}
|
||||||
|
@ -1550,12 +1620,21 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => {
|
() => {
|
||||||
let scheduleds = &ctxt.tasks[name].scheduleds;
|
let scheduleds = &ctxt.tasks[name].scheduleds;
|
||||||
quote!(
|
if cfg!(feature = "nightly") {
|
||||||
ptr::write(
|
quote!(
|
||||||
#scheduleds.get_mut().get_unchecked_mut(usize::from(index)),
|
ptr::write(
|
||||||
#baseline,
|
#scheduleds.get_unchecked_mut(usize::from(index)).as_mut_ptr(),
|
||||||
);
|
#baseline,
|
||||||
)
|
);
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
quote!(
|
||||||
|
ptr::write(
|
||||||
|
#scheduleds.get_mut().get_unchecked_mut(usize::from(index)),
|
||||||
|
#baseline,
|
||||||
|
);
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
|
@ -1568,6 +1647,11 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let input = if cfg!(feature = "nightly") {
|
||||||
|
quote!(#inputs.get_unchecked_mut(usize::from(index)).as_mut_ptr())
|
||||||
|
} else {
|
||||||
|
quote!(#inputs.get_mut().get_unchecked_mut(usize::from(index)))
|
||||||
|
};
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
|
@ -1581,7 +1665,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
|
||||||
use rtfm::Mutex;
|
use rtfm::Mutex;
|
||||||
|
|
||||||
if let Some(index) = (#free { #priority }).lock(|f| f.split().1.dequeue()) {
|
if let Some(index) = (#free { #priority }).lock(|f| f.split().1.dequeue()) {
|
||||||
ptr::write(#inputs.get_mut().get_unchecked_mut(usize::from(index)), (#pats));
|
ptr::write(#input, (#pats));
|
||||||
#scheduleds_write
|
#scheduleds_write
|
||||||
|
|
||||||
#ready { #priority }.lock(|rq| {
|
#ready { #priority }.lock(|rq| {
|
||||||
|
@ -1667,6 +1751,17 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream {
|
||||||
let ty = tuple_ty(args);
|
let ty = tuple_ty(args);
|
||||||
let pats = tuple_pat(args);
|
let pats = tuple_pat(args);
|
||||||
|
|
||||||
|
let input = if cfg!(feature = "nightly") {
|
||||||
|
quote!(#inputs.get_unchecked_mut(usize::from(index)).as_mut_ptr())
|
||||||
|
} else {
|
||||||
|
quote!(#inputs.get_mut().get_unchecked_mut(usize::from(index)))
|
||||||
|
};
|
||||||
|
|
||||||
|
let scheduled = if cfg!(feature = "nightly") {
|
||||||
|
quote!(#scheduleds.get_unchecked_mut(usize::from(index)).as_mut_ptr())
|
||||||
|
} else {
|
||||||
|
quote!(#scheduleds.get_mut().get_unchecked_mut(usize::from(index)))
|
||||||
|
};
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
|
@ -1680,11 +1775,8 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream {
|
||||||
use rtfm::Mutex;
|
use rtfm::Mutex;
|
||||||
|
|
||||||
if let Some(index) = (#free { #priority }).lock(|f| f.split().1.dequeue()) {
|
if let Some(index) = (#free { #priority }).lock(|f| f.split().1.dequeue()) {
|
||||||
ptr::write(#inputs.get_mut().get_unchecked_mut(usize::from(index)), (#pats));
|
ptr::write(#input, (#pats));
|
||||||
ptr::write(
|
ptr::write(#scheduled, instant);
|
||||||
#scheduleds.get_mut().get_unchecked_mut(usize::from(index)),
|
|
||||||
instant,
|
|
||||||
);
|
|
||||||
|
|
||||||
let nr = rtfm::export::NotReady {
|
let nr = rtfm::export::NotReady {
|
||||||
instant,
|
instant,
|
||||||
|
@ -1772,12 +1864,20 @@ fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro
|
||||||
let cap = mk_typenum_capacity(analysis.timer_queue.capacity, false);
|
let cap = mk_typenum_capacity(analysis.timer_queue.capacity, false);
|
||||||
let tq = &ctxt.timer_queue;
|
let tq = &ctxt.timer_queue;
|
||||||
let symbol = format!("TIMER_QUEUE::{}", tq);
|
let symbol = format!("TIMER_QUEUE::{}", tq);
|
||||||
items.push(quote!(
|
if cfg!(feature = "nightly") {
|
||||||
#[doc = #symbol]
|
items.push(quote!(
|
||||||
static mut #tq:
|
#[doc = #symbol]
|
||||||
rtfm::export::MaybeUninit<rtfm::export::TimerQueue<#enum_, #cap>> =
|
static mut #tq: rtfm::export::MaybeUninit<rtfm::export::TimerQueue<#enum_, #cap>> =
|
||||||
rtfm::export::MaybeUninit::uninitialized();
|
rtfm::export::MaybeUninit::uninitialized();
|
||||||
));
|
));
|
||||||
|
} else {
|
||||||
|
items.push(quote!(
|
||||||
|
#[doc = #symbol]
|
||||||
|
static mut #tq:
|
||||||
|
rtfm::export::MaybeUninit<rtfm::export::TimerQueue<#enum_, #cap>> =
|
||||||
|
rtfm::export::MaybeUninit::uninitialized();
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
items.push(mk_resource(
|
items.push(mk_resource(
|
||||||
ctxt,
|
ctxt,
|
||||||
|
@ -1785,7 +1885,7 @@ fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro
|
||||||
tq,
|
tq,
|
||||||
quote!(rtfm::export::TimerQueue<#enum_, #cap>),
|
quote!(rtfm::export::TimerQueue<#enum_, #cap>),
|
||||||
analysis.timer_queue.ceiling,
|
analysis.timer_queue.ceiling,
|
||||||
quote!(#tq.get_mut()),
|
quote!(&mut *#tq.as_mut_ptr()),
|
||||||
app,
|
app,
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
|
@ -1842,36 +1942,32 @@ fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro
|
||||||
fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
|
fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
|
||||||
let mut exprs = vec![];
|
let mut exprs = vec![];
|
||||||
|
|
||||||
// FIXME(MaybeUninit) Because we are using a fake MaybeUninit we need to set the Option tag to
|
if !cfg!(feature = "nightly") {
|
||||||
// Some; otherwise the get_ref and get_mut could result in UB. Also heapless collections can't
|
// these are `MaybeUninit` arrays
|
||||||
// be constructed in const context; we have to initialize them at runtime (i.e. here).
|
for task in ctxt.tasks.values() {
|
||||||
|
let inputs = &task.inputs;
|
||||||
|
exprs.push(quote!(#inputs.set(core::mem::uninitialized());))
|
||||||
|
}
|
||||||
|
|
||||||
// these are `MaybeUninit` arrays
|
#[cfg(feature = "timer-queue")]
|
||||||
for task in ctxt.tasks.values() {
|
for task in ctxt.tasks.values() {
|
||||||
let inputs = &task.inputs;
|
let scheduleds = &task.scheduleds;
|
||||||
exprs.push(quote!(#inputs.set(core::mem::uninitialized());))
|
exprs.push(quote!(#scheduleds.set(core::mem::uninitialized());))
|
||||||
|
}
|
||||||
|
|
||||||
|
// these are `MaybeUninit` `ReadyQueue`s
|
||||||
|
for dispatcher in ctxt.dispatchers.values() {
|
||||||
|
let rq = &dispatcher.ready_queue;
|
||||||
|
exprs.push(quote!(#rq.set(rtfm::export::ReadyQueue::new_sc());))
|
||||||
|
}
|
||||||
|
|
||||||
|
// these are `MaybeUninit` `FreeQueue`s
|
||||||
|
for task in ctxt.tasks.values() {
|
||||||
|
let fq = &task.free_queue;
|
||||||
|
exprs.push(quote!(#fq.set(rtfm::export::FreeQueue::new_sc());))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "timer-queue")]
|
|
||||||
for task in ctxt.tasks.values() {
|
|
||||||
let scheduleds = &task.scheduleds;
|
|
||||||
exprs.push(quote!(#scheduleds.set(core::mem::uninitialized());))
|
|
||||||
}
|
|
||||||
|
|
||||||
// these are `MaybeUninit` `ReadyQueue`s
|
|
||||||
for dispatcher in ctxt.dispatchers.values() {
|
|
||||||
let rq = &dispatcher.ready_queue;
|
|
||||||
exprs.push(quote!(#rq.set(rtfm::export::ReadyQueue::new_sc());))
|
|
||||||
}
|
|
||||||
|
|
||||||
// these are `MaybeUninit` `FreeQueue`s
|
|
||||||
for task in ctxt.tasks.values() {
|
|
||||||
let fq = &task.free_queue;
|
|
||||||
exprs.push(quote!(#fq.set(rtfm::export::FreeQueue::new_sc());))
|
|
||||||
}
|
|
||||||
|
|
||||||
// end-of-FIXME
|
|
||||||
|
|
||||||
// Initialize the timer queue
|
// Initialize the timer queue
|
||||||
if !analysis.timer_queue.tasks.is_empty() {
|
if !analysis.timer_queue.tasks.is_empty() {
|
||||||
let tq = &ctxt.timer_queue;
|
let tq = &ctxt.timer_queue;
|
||||||
|
@ -1881,10 +1977,15 @@ fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Toke
|
||||||
// Populate the `FreeQueue`s
|
// Populate the `FreeQueue`s
|
||||||
for (name, task) in &ctxt.tasks {
|
for (name, task) in &ctxt.tasks {
|
||||||
let fq = &task.free_queue;
|
let fq = &task.free_queue;
|
||||||
|
let fq_ = if cfg!(feature = "nightly") {
|
||||||
|
quote!(#fq)
|
||||||
|
} else {
|
||||||
|
quote!(#fq.get_mut())
|
||||||
|
};
|
||||||
let capacity = analysis.capacities[name];
|
let capacity = analysis.capacities[name];
|
||||||
exprs.push(quote!(
|
exprs.push(quote!(
|
||||||
for i in 0..#capacity {
|
for i in 0..#capacity {
|
||||||
#fq.get_mut().enqueue_unchecked(i);
|
#fq_.enqueue_unchecked(i);
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! IMPLEMENTATION DETAILS. DO NOT USE ANYTHING IN THIS MODULE
|
//! IMPLEMENTATION DETAILS. DO NOT USE ANYTHING IN THIS MODULE
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(feature = "nightly"))]
|
||||||
use core::hint;
|
use core::ptr;
|
||||||
use core::{cell::Cell, ptr, u8};
|
use core::{cell::Cell, u8};
|
||||||
|
|
||||||
#[cfg(armv7m)]
|
#[cfg(armv7m)]
|
||||||
use cortex_m::register::basepri;
|
use cortex_m::register::basepri;
|
||||||
|
@ -64,28 +64,69 @@ impl Priority {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(MaybeUninit) Until core::mem::MaybeUninit is stabilized we use our own (inefficient)
|
#[cfg(feature = "nightly")]
|
||||||
// implementation
|
pub struct MaybeUninit<T> {
|
||||||
|
// we newtype so the end-user doesn't need `#![feature(maybe_uninit)]` in their code
|
||||||
|
inner: core::mem::MaybeUninit<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "nightly")]
|
||||||
|
impl<T> MaybeUninit<T> {
|
||||||
|
pub const fn uninitialized() -> Self {
|
||||||
|
MaybeUninit {
|
||||||
|
inner: core::mem::MaybeUninit::uninitialized(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const T {
|
||||||
|
self.inner.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||||
|
self.inner.as_mut_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, value: T) -> &mut T {
|
||||||
|
self.inner.set(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "nightly"))]
|
||||||
pub struct MaybeUninit<T> {
|
pub struct MaybeUninit<T> {
|
||||||
value: Option<T>,
|
value: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "nightly"))]
|
||||||
|
const MSG: &str =
|
||||||
|
"you have hit a bug (UB) in RTFM implementation; try enabling this crate 'nightly' feature";
|
||||||
|
|
||||||
|
#[cfg(not(feature = "nightly"))]
|
||||||
impl<T> MaybeUninit<T> {
|
impl<T> MaybeUninit<T> {
|
||||||
pub const fn uninitialized() -> Self {
|
pub const fn uninitialized() -> Self {
|
||||||
MaybeUninit { value: None }
|
MaybeUninit { value: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const T {
|
||||||
|
if let Some(x) = self.value.as_ref() {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
unreachable!(MSG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||||
|
if let Some(x) = self.value.as_mut() {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
unreachable!(MSG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn get_ref(&self) -> &T {
|
pub unsafe fn get_ref(&self) -> &T {
|
||||||
if let Some(x) = self.value.as_ref() {
|
if let Some(x) = self.value.as_ref() {
|
||||||
x
|
x
|
||||||
} else {
|
} else {
|
||||||
match () {
|
unreachable!(MSG)
|
||||||
// Try to catch UB when compiling in release with debug assertions enabled
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
() => unreachable!(),
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
() => hint::unreachable_unchecked(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,13 +134,7 @@ impl<T> MaybeUninit<T> {
|
||||||
if let Some(x) = self.value.as_mut() {
|
if let Some(x) = self.value.as_mut() {
|
||||||
x
|
x
|
||||||
} else {
|
} else {
|
||||||
match () {
|
unreachable!(MSG)
|
||||||
// Try to catch UB when compiling in release with debug assertions enabled
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
() => unreachable!(),
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
() => hint::unreachable_unchecked(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,13 @@
|
||||||
//!
|
//!
|
||||||
//! [`Instant`]: struct.Instant.html
|
//! [`Instant`]: struct.Instant.html
|
||||||
//! [`Duration`]: struct.Duration.html
|
//! [`Duration`]: struct.Duration.html
|
||||||
|
//!
|
||||||
|
//! - `nightly`. Enabling this opt-in feature makes RTFM internally use the unstable
|
||||||
|
//! `core::mem::MaybeUninit` API and unstable `const_fn` language feature to reduce static memory
|
||||||
|
//! usage, runtime overhead and initialization overhead. This feature requires a nightly compiler
|
||||||
|
//! and may stop working at any time!
|
||||||
|
|
||||||
|
#![cfg_attr(feature = "nightly", feature(maybe_uninit))]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
Loading…
Reference in a new issue