Skip to content

Commit c6ff4e1

Browse files
committed
[rust] Enhance app framework within Rust
Create a framework for defining LK applications in Rust, simplifying app creation and management. The `LkApp` trait can be applied to a type, with the `lkapp!` macro then generating the boilerplate needed to integrate the app with LK. Signed-off-by: David Brown <[email protected]>
1 parent e0dae4b commit c6ff4e1

File tree

3 files changed

+95
-17
lines changed

3 files changed

+95
-17
lines changed

app/rust_hello/src/lib.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,30 @@
22

33
#![no_std]
44

5-
use core::ffi::c_void;
5+
extern crate alloc;
66

7-
use lk::sys::{APP_FLAG_NO_AUTOSTART, app_descriptor};
7+
use alloc::boxed::Box;
8+
9+
use lk::{app::LkApp, lkapp};
810

911
pub fn must_link() {}
1012

11-
/// Manual, and unsafe declration of an app.
12-
#[unsafe(link_section = "apps")]
13-
#[used]
14-
static APP_RUST_HELLO: app_descriptor = app_descriptor {
15-
name: c"rust_hello".as_ptr(),
16-
init: Some(init),
17-
entry: Some(main),
18-
flags: APP_FLAG_NO_AUTOSTART,
19-
stack_size: 0,
20-
};
21-
22-
extern "C" fn init(_desc: *const app_descriptor) {
23-
log::info!("Rust hello app init");
13+
struct MyApp {
14+
count: usize,
2415
}
2516

26-
extern "C" fn main(_desc: *const app_descriptor, _args: *mut c_void) {
27-
log::info!("Rust hello app main");
17+
impl LkApp for MyApp {
18+
fn new() -> Option<Self> {
19+
Some(MyApp { count: 0 })
20+
}
21+
22+
fn main(&mut self) {
23+
self.count += 1;
24+
log::info!("App has been invoked {} times", self.count);
25+
}
2826
}
27+
28+
lkapp!(
29+
c"rust_hello",
30+
APP_RUST_HELLO,
31+
pub static MY_APP: MyApp);

rust/lk/src/app.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//! Application support
2+
//!
3+
//! Applications in LK are managed through a descriptor, the combines a name,
4+
//! some flags, a possible stack size override, with an `init` and `main`
5+
//! function pointer.
6+
//!
7+
//! This Rust module provides a more Rust-friendly way to define applications.
8+
//! Applications for Rust consist of someting that implements the `LkApp` trait.
9+
//! The `init` function from lk is used to invoke the constructor for this
10+
//! object. Then each invocation of `main` will invoke the `main` method on the
11+
//! object. Because of multiple, uncoordinated invocations of `main`, a given
12+
//! call from lk on `main` will only invoke the `main` method after previous
13+
//! invocations have completed. This allows the struct to only require `Send`
14+
//! (as it is sent to the thread created for the app), and not `Sync`.
15+
16+
/// Something that implements an LK application. The 'new' method is invoked
17+
/// during initialization time to create one of these, and then the 'main'
18+
/// method is invoked each time the application is started.
19+
pub trait LkApp: Sized + Send + 'static {
20+
/// Construct a new instance of the application.
21+
///
22+
/// If "None" is returned, the application will not be started.
23+
fn new() -> Option<Self>;
24+
25+
/// Application main function.
26+
fn main(&mut self);
27+
}
28+
29+
#[macro_export]
30+
macro_rules! lkapp {
31+
($cname:literal,
32+
$appname:ident,
33+
$vis:vis static $name:ident: $app:ty
34+
) => {
35+
$vis static $name: ::core::sync::atomic::AtomicPtr<$app> = ::core::sync::atomic::AtomicPtr::new(::core::ptr::null_mut());
36+
37+
#[unsafe(link_section = "apps")]
38+
#[used]
39+
static $appname: $crate::sys::app_descriptor = $crate::sys::app_descriptor {
40+
name: $cname.as_ptr(),
41+
init: Some(init),
42+
entry: Some(main),
43+
flags: $crate::sys::APP_FLAG_NO_AUTOSTART,
44+
stack_size: 0,
45+
};
46+
47+
extern "C" fn init(_desc: *const $crate::sys::app_descriptor) {
48+
::log::info!("Rust app init");
49+
50+
let app = match <$app>::new() {
51+
Some(a) => a,
52+
None => {
53+
::log::error!("App constructor returned None");
54+
return;
55+
}
56+
};
57+
58+
let app_box = Box::new(app);
59+
let app_ptr = Box::into_raw(app_box);
60+
$name.store(app_ptr, ::core::sync::atomic::Ordering::SeqCst);
61+
}
62+
63+
extern "C" fn main(_desc: *const $crate::sys::app_descriptor, _args: *mut ::core::ffi::c_void) {
64+
let app_ptr = $name.load(::core::sync::atomic::Ordering::SeqCst);
65+
if !app_ptr.is_null() {
66+
// Safe because we ensure only one 'main' runs at a time.
67+
let app = unsafe { &mut *app_ptr };
68+
app.main();
69+
return;
70+
}
71+
::log::error!("App already running");
72+
}
73+
};
74+
}

rust/lk/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use core::{
2020
panic::PanicInfo,
2121
};
2222

23+
pub mod app;
2324
pub mod cbuf;
2425
pub mod init;
2526
pub mod lkonce;

0 commit comments

Comments
 (0)