diff --git a/.cargo/config.toml b/.cargo/config.toml index 553cec20f95a6b998e2fa1c8a04c43b9a55cf79e..b973bcda506f0e4b037625efd476dff7ae598d7d 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -32,21 +32,13 @@ rustflags = [ "WIN10", ] -[nightly-x86_64-unknown-linux-gnu] +[target.x86_64-unknown-linux-gnu] rustflags = [ # Designated as win10 system. Some functions of the system below win10 cannot be used. "--cfg", "WIN10", ] -[x86_64-unknown-linux-gnu] -rustflags = [ - # Designated as win10 system. Some functions of the system below win10 cannot be used. - "--cfg", - "WIN10", -] - - [target.thumbv7m-none-eabi] rustflags = [ # Set the target system as Huawei liteos_ m @@ -56,9 +48,9 @@ rustflags = [ 'target_os="liteos_m"', # Specify LiteOS location "--cfg", - 'LOS_PATH="../../stm32/LiteOS"', + 'LOS_PATH="../../../c/LiteOS/"', ] -[build] -# Always compile for the instruction set of the STM32F1 -target = "thumbv7m-none-eabi" +# [build] +# # Always compile for the instruction set of the STM32F1 +# target = "thumbv7m-none-eabi" diff --git a/.gitignore b/.gitignore index 502d4f0ed10e4580a3977f8f1c079f7c6f7ecb5c..d1a77b6a829e04a382a3c4fd36a783f017ed93d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /Cargo.lock -src/liteos/config.rs +src/liteos/sysinfo.rs +src/unix/sysinfo.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 513cbeb9d40d194855d83ea90af0123f31f55eba..9939e92049e695e176be1ab81a0aa00e6b0f4d14 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,8 @@ { - "rust-analyzer.checkOnSave.allTargets": false + "rust-analyzer.checkOnSave.allTargets": true, + "lldb.displayFormat": "auto", + "lldb.dereferencePointers": true, + "lldb.consoleMode": "commands", + "editor.formatOnPaste": true, + "editor.formatOnSave": true, } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 7d7c1dfc2548415c457fae8a8cb178a3cbf896ef..f4369968827373ca1cef653c9b1efcfe7961a8e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,10 +6,18 @@ version = "0.1.0" [lib] crate-type = ["rlib"] +[features] +default = ["liteos"] +liteos = [] + [dependencies] utils = { git = "https://gitee.com/iot-ua/utils.git", branch = "develop" } - cfg-if = "1.0.0" + +[build-dependencies] +regex = "1.5.6" +num_cpus = "1.13.1" + [target.'cfg(unix)'.dependencies] libc = { version = "0.2.126", default-features = false } @@ -27,24 +35,18 @@ windows-sys = { version = "0.36.1", features = [ "Win32_System_SystemServices", ] } -[build-dependencies] -regex = "1.5.6" - - [[example]] -name = "app" -crate-type = ["staticlib"] - -[[example]] -name = "led" +name = "test_liteos" crate-type = ["staticlib"] +required-features = ["liteos"] [profile.release] opt-level = 3 debug = true -debug-assertions = false -overflow-checks = false +rpath = false lto = true -incremental = false +debug-assertions = false codegen-units = 1 -rpath = false +panic = 'abort' +incremental = false +overflow-checks = false diff --git a/build.rs b/build.rs index 2f88dcd0355cb36731d33d570d7d955c1ee05186..a8f773be8e9f994e9442a8b37bfa9941eced2896 100644 --- a/build.rs +++ b/build.rs @@ -3,29 +3,45 @@ use std::{ env, ffi::OsStr, fs::File, - io::{BufRead, BufReader, Write}, + io::{BufRead, BufReader, ErrorKind, Write}, path::PathBuf, str::FromStr, }; fn main() { + //当前构建文件所在位置 + let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); + //根据项目输入位置,推导项目根文件夹实质位置。 + let out_dir = env::var("OUT_DIR").unwrap(); + let out_path = PathBuf::from_str(&out_dir).unwrap(); + let mut top_path = PathBuf::new(); + for i in out_path.iter() { + if i == OsStr::new("target") { + break; + } + top_path.push(i); + } + //是否配置位置LITEOS,详细参见编译配置文件 ".cargo/config.toml 中的编译选项: "--cfg", "liteos", let target_os = env::var("CARGO_CFG_LITEOS").is_ok(); // Decode liteos configuration information and automatically generate configuration files. if target_os { - let out_dir = env::var("OUT_DIR").unwrap(); - let out_path = PathBuf::from_str(&out_dir).unwrap(); - let mut top_path = PathBuf::new(); - for i in out_path.iter() { - if i == OsStr::new("target") { - break; - } - top_path.push(i); - } - - let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); - let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); - + //获取LiteOS所在位置,详细参见编译配置文件 ".cargo/config.toml" 中的编译选项: "--cfg", 'LOS_PATH="../../../c/LiteOS/"'。 let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); - let los_path = top_path.join(&los_path).canonicalize().unwrap(); + //绝对路径与相对路径处理 + let los_path = if los_path.starts_with("/") || los_path.starts_with("~") { + PathBuf::from_str(&los_path).unwrap() + } else { + top_path + .join(&los_path) + .canonicalize() + .map_err(|_e| { + std::io::Error::new( + ErrorKind::Other, + top_path.join(&los_path).to_str().unwrap(), + ) + }) + .unwrap() + }; let fs = File::options() .read(true) @@ -37,15 +53,13 @@ fn main() { .write(true) .create(true) .truncate(true) - .open(manifest_path.join("src/liteos/config.rs")) + .open(manifest_path.join("src/liteos/sysinfo.rs")) .unwrap(); - + let is_empty_line = Regex::new(r"^ *?#|^ *?$").unwrap(); let kv = Regex::new(r#"^ *?(\w+) *?= *?(.*)$"#).unwrap(); - unsafe { - write!(&mut fcfg,"//The following content is automatically generated by the compiler.\n//please do not modify it.\n").unwrap_unchecked() - }; + write!(fcfg,"//The following content is automatically generated by the compiler.\n//please do not modify it.\n").unwrap(); for line in fs.lines() { if let Ok(s) = line { @@ -64,14 +78,30 @@ fn main() { } } } + println!("cargo:rustc-cfg={}", "liteos"); + println!("cargo:rustc-cfg={}", "feature=\"liteos\""); println!( "cargo:rerun-if-changed={}", los_path.join(".config").to_str().unwrap() ); - println!( - "cargo:rerun-if-changed={}", - top_path.join(".cargo/config.toml").to_str().unwrap() - ) + } else { + let system = env::var("CARGO_CFG_TARGET_FAMILY").unwrap(); + let cfgfile = format!("src/{}/sysinfo.rs", system); + let mut fcfg = File::options() + .write(true) + .create(true) + .truncate(true) + .open(manifest_path.join(cfgfile)) + .unwrap(); + let cpus = num_cpus::get(); + + write!(fcfg,"//The following content is automatically generated by the compiler.\n//please do not modify it.\n").unwrap(); + + write!(fcfg, "pub const CPU_CORE_NUMBERS: usize = {}usize;", cpus).unwrap(); } println!("cargo:rerun-if-changed=build.rs"); + println!( + "cargo:rerun-if-changed={}", + top_path.join(".cargo/config.toml").to_str().unwrap() + ); } diff --git a/examples/app.rs b/examples/app.rs deleted file mode 100644 index 695e21028e2e492c3ba862325e4a72eed23a2856..0000000000000000000000000000000000000000 --- a/examples/app.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![no_std] -#![feature(default_alloc_error_handler)] -extern crate alloc; -use alloc::boxed::Box; -use arch::{ - os::printf, - thread::{self, Thread}, -}; -#[no_mangle] -extern "C" fn app_init() { - let _ = unsafe { - Thread::new( - 800, - Box::new(|| loop { - printf("test\n\0".as_ptr().cast()); - thread::Thread::sleep(1000); - }), - ) - }; -} - -#[cfg(not(test))] -#[panic_handler] -pub fn painc_handler(_info: &core::panic::PanicInfo<'_>) -> ! { - loop {} -} diff --git a/examples/led.rs b/examples/led.rs deleted file mode 100644 index 43af96f1eaa013872535d68fea97d1c79143b5ba..0000000000000000000000000000000000000000 --- a/examples/led.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -#![feature(default_alloc_error_handler)] -extern crate alloc; -use alloc::boxed::Box; -use arch::{ - thread::{self, Thread}, -}; - -extern "C" { - fn led_toggle(); -} -#[no_mangle] -extern "C" fn app_init() { - let _ = unsafe { - Thread::new( - 800, - Box::new(|| loop { - led_toggle(); - thread::Thread::sleep(1000); - }), - ) - }; -} - -#[cfg(not(test))] -#[panic_handler] -pub fn painc_handler(_info: &core::panic::PanicInfo<'_>) -> ! { - loop {} -} diff --git a/examples/liteos/lazyobj_test.rs b/examples/liteos/lazyobj_test.rs new file mode 100644 index 0000000000000000000000000000000000000000..73087c7522098e0f64b2da58086301f6eb8027d4 --- /dev/null +++ b/examples/liteos/lazyobj_test.rs @@ -0,0 +1,141 @@ +use arch::instant::Instant; +use arch::os::printf; +use arch::{lazy::*, thread}; +use core::mem::MaybeUninit; + +struct TestStruct { + a: u32, + q: u64, +} +impl Drop for TestStruct { + fn drop(&mut self) { + unsafe { printf("Droped1\n\0".as_ptr()) }; + } +} +impl LazyObjInit for TestStruct { + fn init(v: &mut MaybeUninit) { + let vv = TestStruct { a: 33, q: 64 }; + v.write(vv); + } +} +pub fn lazyobj_test() { + let abc: LazyObj = LazyObj::new(); + let c = abc.a; + assert_eq!(c, 33); + assert_eq!(abc.q, 64); +} + +struct TestStruct2 { + a: u32, + q: u128, +} +impl Drop for TestStruct2 { + fn drop(&mut self) { + unsafe { printf("Droped2\n\0".as_ptr()) }; + } +} +impl LazyObjInit for TestStruct2 { + fn init(v: &mut MaybeUninit) { + let vv = TestStruct2 { a: 33, q: 64 }; + v.write(vv); + } +} +pub fn lazyobj_test2() { + let abc: LazyObj = LazyObj::new(); + let c = abc.a; + assert_eq!(c, 33); + assert_eq!(abc.q, 64); +} + +struct TestStruct3 { + a: u32, + q: u16, +} +impl Drop for TestStruct3 { + fn drop(&mut self) { + unsafe { printf("Droped3\n\0".as_ptr()) }; + } +} +impl LazyObjInit for TestStruct3 { + fn init(v: &mut MaybeUninit) { + let vv = TestStruct3 { a: 33, q: 64 }; + v.write(vv); + } +} +pub fn lazyobj_test3() { + let abc: LazyObj = LazyObj::new(); + let c = abc.a; + assert_eq!(c, 33); + assert_eq!(abc.q, 64); +} + +struct TestStruct4 { + a: u32, + q: u8, +} +impl Drop for TestStruct4 { + fn drop(&mut self) { + unsafe { printf("Droped4\n\0".as_ptr()) }; + } +} +impl LazyObjInit for TestStruct4 { + fn init(v: &mut MaybeUninit) { + let vv = TestStruct4 { a: 33, q: 64 }; + v.write(vv); + } +} +pub fn lazyobj_test4() { + let abc: LazyObj = LazyObj::new(); + let c = abc.a; + assert_eq!(c, 33); + assert_eq!(abc.q, 64); +} + +struct TestStruct5 { + a: u32, +} +impl Drop for TestStruct5 { + fn drop(&mut self) { + unsafe { printf("Droped5\n\0".as_ptr()) }; + } +} +impl LazyObjInit for TestStruct5 { + fn init(v: &mut MaybeUninit) { + let vv = TestStruct5 { a: 33 }; + v.write(vv); + } +} + +pub fn lazyobj_test5() { + let abc: LazyObj = LazyObj::new(); + let c = abc.a; + assert_eq!(c, 33); +} + +struct TestStruct6 { + a: u8, +} +impl Drop for TestStruct6 { + fn drop(&mut self) { + unsafe { printf("Droped6\n\0".as_ptr()) }; + } +} +impl LazyObjInit for TestStruct6 { + fn init(v: &mut MaybeUninit) { + let vv = TestStruct6 { a: 33 }; + v.write(vv); + } +} + +pub fn lazyobj_test6() { + let abc: LazyObj = LazyObj::new(); + let c = abc.a; + assert_eq!(c, 33); +} + +pub fn get_tickcount_test() { + let i = Instant::now(); + thread::Thread::sleep(100); + let t = i.elapsed(); + unsafe { printf("elapsed time:%d\n\r".as_ptr(), t) }; +} diff --git a/examples/liteos/mod.rs b/examples/liteos/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..21c9e9ddd67d94067f1f31592c84fc6ee53e3200 --- /dev/null +++ b/examples/liteos/mod.rs @@ -0,0 +1,2 @@ +mod lazyobj_test; +pub use lazyobj_test::*; diff --git a/examples/test_liteos.rs b/examples/test_liteos.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d51fc93f20478187d3ccbe9b5ae6907e6ee83cf --- /dev/null +++ b/examples/test_liteos.rs @@ -0,0 +1,47 @@ +#![no_std] +#![feature(default_alloc_error_handler)] +#![feature(panic_info_message)] +#![feature(bench_black_box)] + +use alloc::string::ToString; +use arch::os::printf; + +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; +#[allow(unused)] +extern "C" { + fn led_toggle(); + fn DemoEntry(); +} + +// #[cfg(not(test))] +#[panic_handler] +pub unsafe fn painc_handler(info: &core::panic::PanicInfo<'_>) -> ! { + let s = info.to_string(); + printf("%s\n\0".as_ptr().cast(), s.as_ptr()); + loop {} +} + +mod liteos; +use liteos::*; +#[no_mangle] +unsafe extern "C" fn app_init() { + DemoEntry(); + printf("\n\0".as_ptr()); + printf("LazyObj Test1 Start\n\0".as_ptr()); + lazyobj_test(); + + printf("LazyObj Test2 Start\n\0".as_ptr()); + lazyobj_test2(); + printf("LazyObj Test3 Start\n\0".as_ptr()); + lazyobj_test3(); + printf("LazyObj Test4 Start\n\0".as_ptr()); + lazyobj_test4(); + printf("LazyObj Test5 Start\n\0".as_ptr()); + lazyobj_test5(); + printf("LazyObj Test6 Start\n\0".as_ptr()); + lazyobj_test6(); + printf("getTickCount Test\n\0".as_ptr()); + get_tickcount_test(); +} diff --git a/src/common/instant.rs b/src/common/instant.rs index 35a4a7d177db88e526d44d0e3d9859ad7a470932..057dbbd35ef8c5faad33c378dfecc549b9fa3c2b 100644 --- a/src/common/instant.rs +++ b/src/common/instant.rs @@ -1,16 +1,16 @@ -#[cfg(test)] +#[cfg(all(test, not(liteos)))] mod tests; use core::ops::{Deref, DerefMut}; -use crate::os::get_tick_count; +use crate::os::get_tickcount; #[derive(Clone, Copy)] pub struct Instant(u32); impl Instant { #[inline] pub fn now() -> Self { - Self(get_tick_count()) + Self(get_tickcount()) } #[inline] pub fn elapsed(&self) -> u32 { diff --git a/src/common/lazyobj.rs b/src/common/lazyobj.rs new file mode 100644 index 0000000000000000000000000000000000000000..23e6a56dc1d3dd92433c67b86fe0183e7f6226e2 --- /dev/null +++ b/src/common/lazyobj.rs @@ -0,0 +1,149 @@ +#[cfg(all(test, not(target_os = "none")))] +mod tests; +use alloc::alloc::{alloc, dealloc}; + +use crate::{os::CPU_CORE_NUMBERS, thread}; +use core::{ + alloc::Layout, + marker::PhantomData, + mem::{size_of, transmute, transmute_copy, MaybeUninit}, + ops::{Deref, DerefMut}, + sync::atomic::{ + AtomicUsize, + Ordering::{Acquire, Relaxed, Release}, + }, +}; +const EMPTY: usize = usize::MAX; +const RUNING: usize = usize::MAX - 1; +const COMPLETE: usize = usize::MAX - 2; +pub trait LazyObjInit +where + Self: Sized, +{ + fn init(v: &mut MaybeUninit); +} +pub struct LazyObj() > size_of::() }> { + value: AtomicUsize, + _phantom: PhantomData, +} +impl LazyObj { + const LY: Layout = Layout::new::(); + #[inline] + pub const fn new() -> Self { + Self { + value: AtomicUsize::new(EMPTY), + _phantom: PhantomData, + } + } + #[inline] + fn get_pointer(&self) -> *mut T { + let mut state = self.value.load(Acquire); + if state > COMPLETE { + if ISBOX { + state = initialize_box(&self.value, state, Self::LY, unsafe { + transmute(T::init as *mut u8) + }); + } else { + state = + initialize_nobox(&self.value, state, unsafe { transmute(T::init as *mut u8) }); + } + } + if ISBOX { + unsafe { transmute(state) } + } else { + unsafe { transmute(self.value.as_mut_ptr()) } + } + } +} +//放置到全局的目的是禁止泛化,造成的代码膨胀。 +#[cold] +fn initialize_box(ptr: &AtomicUsize, mut state: usize, ly: Layout, init: fn(*mut ())) -> usize { + loop { + match state { + EMPTY => { + let result = ptr.compare_exchange_weak(state, RUNING, Acquire, Acquire); + if let Err(old) = result { + state = old; + continue; + } + let t = unsafe { alloc(ly).cast::<()>() }; + init(t); + ptr.swap(t.addr(), Release); + return t.addr(); + } + s if s < RUNING => return state, + _ => { + if CPU_CORE_NUMBERS > 1 { + core::hint::spin_loop(); + } else { + thread::Thread::yield_now(); + } + debug_assert!(state == RUNING); + state = ptr.load(Acquire); + continue; + } + } + } +} +#[cold] +//放置到全局的目的是禁止泛化,造成的代码膨胀。 +fn initialize_nobox(ptr: &AtomicUsize, mut status: usize, init: fn(*mut ())) -> usize { + loop { + match status { + EMPTY => { + let result = ptr.compare_exchange_weak(status, RUNING, Acquire, Acquire); + if let Err(old) = result { + status = old; + continue; + } + unsafe { init(transmute(&status)) }; + ptr.swap(status, Release); + return ptr.as_mut_ptr().addr(); + } + s if s < RUNING => return status, + _ => { + if CPU_CORE_NUMBERS > 1 { + core::hint::spin_loop(); + } else { + thread::Thread::yield_now(); + } + debug_assert!(status == RUNING); + status = ptr.load(Acquire); + continue; + } + } + } +} + +impl Deref for LazyObj { + type Target = T; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*self.get_pointer() } + } +} + +impl DerefMut for LazyObj { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.get_pointer() } + } +} + +impl Drop for LazyObj { + fn drop(&mut self) { + let t = self.value.load(Relaxed); + unsafe { + if t < RUNING { + if ISBOX { + let t: *mut T = transmute(t); + t.read(); + let ly = Layout::new::(); + dealloc(t.cast(), ly); + } else { + drop::(transmute_copy(&t)); + } + } + }; + } +} diff --git a/src/common/lazyobj/tests.rs b/src/common/lazyobj/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..64eedfae308ab421a29fb3339465e6ffb0ebb31c --- /dev/null +++ b/src/common/lazyobj/tests.rs @@ -0,0 +1,27 @@ +extern crate std; +use super::LazyObj; +use super::LazyObjInit; +use core::mem::MaybeUninit; +use std::println; +struct TestStruct { + a: u32, + q: u64, +} +impl Drop for TestStruct { + fn drop(&mut self) { + println!("Droped"); + } +} +impl LazyObjInit for TestStruct { + fn init(v: &mut MaybeUninit) { + let vv = TestStruct { a: 33, q: 66 }; + v.write(vv); + } +} +#[test] +fn lazybox() { + let abc: LazyObj = LazyObj::new(); + let c = abc.a; + assert_eq!(c, 33); + assert_eq!(abc.q, 66); +} diff --git a/src/common/mod.rs b/src/common/mod.rs index ea7508d29c6d6cbee724eafb13e140848a2704d7..59dfc2b522013e9afafb29839a607242835b9961 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -2,7 +2,11 @@ use cfg_if::cfg_if; pub mod cachepad; pub mod error; pub mod instant; +mod lazyobj; pub(crate) mod malloc; +pub mod lazy { + pub use super::lazyobj::*; +} pub trait FastDiv { fn fast_div(self, b: u32) -> (u32, u32); } diff --git a/src/lib.rs b/src/lib.rs index 1a9b19f05604d37a7242af1451e38d3525cd5681..3cc5f3bf4b7cb111264644c084098583f51e50bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,15 @@ #![feature(new_uninit)] #![feature(associated_type_bounds)] #![feature(core_intrinsics)] +#![feature(strict_provenance)] +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] +#![feature(atomic_mut_ptr)] +#![feature(negative_impls)] +#![feature(const_mut_refs)] +#![feature(mem_copy_fn)] +#![feature(bench_black_box)] + #[allow(unused_imports)] #[macro_use] extern crate alloc; @@ -11,21 +20,20 @@ use cfg_if::cfg_if; //-------------------------------------------------// mod common; -pub use common::{cachepad, error, instant}; +pub use common::{cachepad, error, instant, lazy}; cfg_if! { if #[cfg(unix)]{ mod unix; - pub use unix::locks; pub use unix::os; + pub use unix::locks; pub use unix::thread; - }else if #[cfg(windows)]{ mod windows; }else if #[cfg(liteos)]{ mod liteos; pub use liteos::os; + pub use liteos::locks; pub use liteos::thread; } } - diff --git a/src/liteos/libc.rs b/src/liteos/libc.rs index 935ba129c462665a8e184299557f3b6790f5fdbc..db52e604958c96f868bda80cb0ac085684dc4314 100644 --- a/src/liteos/libc.rs +++ b/src/liteos/libc.rs @@ -1,5 +1,4 @@ -#[path = "./config.rs"] -mod config; +use super::sysinfo::*; pub type size_t = usize; pub mod heap { #[repr(C)] @@ -90,12 +89,14 @@ pub mod heap { } pub mod sys { use super::size_t; - + pub const LOS_OK: u32 = 0; + pub const LOS_WAIT_FOREVER: u32 = u32::MAX; extern "C" { pub fn abort() -> !; pub fn __errno_location() -> *const i32; pub fn strerror_r(err: i32, buf: *mut u8, buflen: size_t) -> i32; pub fn strnlen(cs: *const u8, maxlen: size_t) -> size_t; + pub fn LOS_TickCountGet() -> u64; } } pub mod pthread { @@ -105,8 +106,8 @@ pub mod pthread { pub type pthread_t = isize; pub const PR_SET_NAME: i32 = 15i32; - pub const MIN_STACK_SIZE: usize = super::config::LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE; - pub const DEFAULT_STACK_SIZE: usize = super::config::LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; + pub const MIN_STACK_SIZE: usize = super::LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE; + pub const DEFAULT_STACK_SIZE: usize = super::LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; #[repr(C)] pub struct pthread_attr_t { __size: [u32; 15], @@ -127,7 +128,6 @@ pub mod pthread { pub fn pthread_join(thread: pthread_t, retVal: *const *const c_void) -> i32; pub fn pthread_detach(thread: pthread_t) -> i32; pub fn sched_yield() -> i32; - pub fn prctl(op: i32, ...) -> i32; } } pub mod timer { @@ -136,7 +136,48 @@ pub mod timer { } } pub mod task { + use super::LOSCFG_BASE_CORE_TSK_LIMIT; + + pub const KERNEL_TSK_LIMIT: u32 = LOSCFG_BASE_CORE_TSK_LIMIT as u32; + pub const LOS_ERRNO_TSK_ID_INVALID: u32 = 0x02000207; extern "C" { pub fn LOS_TaskDelay(tick: u32) -> u32; + pub fn LOS_CurTaskIDGet() -> u32; + pub fn LOS_TaskSuspend(taskId: u32) -> u32; + pub fn LOS_TaskResume(taskId: u32) -> u32; + } +} +pub mod mutex { + pub const LOS_ERRNO_MUX_ALL_BUSY: u32 = 0x02001d03; + pub const LOS_ERRNO_MUX_TIMEOUT: u32 = 0x02001d07; + extern "C" { + pub fn LOS_MuxCreate(muxHandle: *mut u32) -> u32; + pub fn LOS_MuxDelete(muxHandle: u32) -> u32; + pub fn LOS_MuxPend(muxHandle: u32, timeout: u32) -> u32; + pub fn LOS_MuxPost(muxHandle: u32) -> u32; + + } +} +pub mod event { + + pub const LOS_WAITMODE_AND: u32 = 4u32; + pub const LOS_WAITMODE_CLR: u32 = 1u32; + pub const LOS_WAITMODE_OR: u32 = 2u32; + pub const LOS_ERRNO_EVENT_READ_TIMEOUT: u32 = 0x02001c01; + #[repr(C)] + pub struct EVENT_CB_S { + uwEventID: u32, + list: [usize; 2], + } + extern "C" { + pub fn LOS_EventInit(eventCB: *const EVENT_CB_S) -> u32; + pub fn LOS_EventRead( + eventCB: *const EVENT_CB_S, + eventMask: u32, + mode: u32, + timeout: u32, + ) -> u32; + pub fn LOS_EventWrite(eventCB: *const EVENT_CB_S, events: u32) -> u32; + pub fn LOS_EventDestroy(eventCB: *const EVENT_CB_S) -> u32; } } diff --git a/src/liteos/locks/mod.rs b/src/liteos/locks/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..aad438cdfb273c6bc8c2391683d7cae4a08c2ea2 --- /dev/null +++ b/src/liteos/locks/mod.rs @@ -0,0 +1,3 @@ +mod mutex; +pub use mutex::*; +pub mod parker; diff --git a/src/liteos/locks/mutex.rs b/src/liteos/locks/mutex.rs new file mode 100644 index 0000000000000000000000000000000000000000..e9fc1ebf7158e18b145a9b05cc96bb5a09e59771 --- /dev/null +++ b/src/liteos/locks/mutex.rs @@ -0,0 +1,49 @@ +use crate::lazy::{LazyObj, LazyObjInit}; +use crate::liteos::libc::{ + mutex::{LOS_MuxCreate, LOS_MuxDelete, LOS_MuxPend, LOS_MuxPost, LOS_ERRNO_MUX_TIMEOUT}, + sys::{LOS_OK, LOS_WAIT_FOREVER}, +}; +use core::mem::MaybeUninit; +pub type MovableMutex = LazyObj; +pub struct Mutex(u32); + +impl LazyObjInit for Mutex { + fn init(v: &mut MaybeUninit) { + let v = v.write(Mutex::new()); + unsafe { v.init() }; + } +} +impl Mutex { + #[inline] + pub const fn new() -> Self { + Mutex(u32::MAX) + } + #[inline] + pub unsafe fn init(&mut self) { + let rtn = LOS_MuxCreate(&mut self.0); + debug_assert!(rtn == LOS_OK); + } + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let rtn = LOS_MuxPend(self.0, 0); + debug_assert!(rtn == LOS_OK || rtn == LOS_ERRNO_MUX_TIMEOUT); + rtn == LOS_OK + } + + #[inline] + pub unsafe fn lock(&self) { + let rtn = LOS_MuxPend(self.0, LOS_WAIT_FOREVER); + debug_assert!(rtn == LOS_OK); + } + #[inline] + pub unsafe fn unlock(&self) { + let rtn = LOS_MuxPost(self.0); + debug_assert!(rtn == LOS_OK); + } +} + +impl Drop for Mutex { + fn drop(&mut self) { + unsafe { LOS_MuxDelete(self.0) }; + } +} diff --git a/src/liteos/locks/parker.rs b/src/liteos/locks/parker.rs new file mode 100644 index 0000000000000000000000000000000000000000..c5c933ccffd18d17140d3126c6059f384aae508d --- /dev/null +++ b/src/liteos/locks/parker.rs @@ -0,0 +1,156 @@ +use crate::liteos::libc::event::{ + LOS_EventDestroy, LOS_EventInit, LOS_EventRead, LOS_EventWrite, EVENT_CB_S, + LOS_ERRNO_EVENT_READ_TIMEOUT, LOS_WAITMODE_AND, LOS_WAITMODE_CLR, +}; +use crate::liteos::libc::sys::{LOS_OK, LOS_WAIT_FOREVER}; +use alloc::boxed::Box; + +use core::mem::MaybeUninit; +use core::ptr::NonNull; +use core::sync::atomic::{ + AtomicU32, + Ordering::{Acquire, Relaxed}, +}; +#[allow(unused)] +const PARKED: u32 = 0x00000000; +const EMPTY: u32 = 0x1; +const NOTIFIED: u32 = 0x2; + +struct Inner { + cnt: AtomicU32, + flag: AtomicU32, + evb: EVENT_CB_S, +} +impl Inner { + #[inline] + const unsafe fn new() -> Self { + Self { + cnt: AtomicU32::new(1), + flag: AtomicU32::new(EMPTY), + evb: MaybeUninit::uninit().assume_init(), + } + } + #[inline] + unsafe fn init(&self) { + let rtn = LOS_EventInit(&self.evb); + debug_assert!(rtn == LOS_OK); + } + unsafe fn park(&self) { + if self.flag.fetch_sub(EMPTY, Acquire) == NOTIFIED { + return; + } + let rtn = LOS_EventRead( + &self.evb, + 1, + LOS_WAITMODE_AND | LOS_WAITMODE_CLR, + LOS_WAIT_FOREVER, + ); + debug_assert!(rtn == 1 || rtn == LOS_ERRNO_EVENT_READ_TIMEOUT); + self.flag.swap(EMPTY, Relaxed); + } + unsafe fn park_timeout(&self, timeout: u32) -> bool { + if self.flag.fetch_sub(EMPTY, Acquire) == NOTIFIED { + return true; + } + let rtn = LOS_EventRead(&self.evb, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, timeout); + debug_assert!(rtn == 1 || rtn == LOS_ERRNO_EVENT_READ_TIMEOUT); + if self.flag.swap(EMPTY, Acquire) == NOTIFIED { + true + } else { + false + } + } + unsafe fn unpark(&self) -> bool { + match self.flag.swap(NOTIFIED, Acquire) { + EMPTY => return true, + NOTIFIED => return false, + _ => { + let rtn = LOS_EventWrite(&self.evb, 1); + debug_assert!(rtn == LOS_OK); + return true; + } + }; + } +} +impl Drop for Inner { + #[inline] + fn drop(&mut self) { + let rtn = unsafe { LOS_EventDestroy(&self.evb) }; + debug_assert!(rtn == LOS_OK); + } +} + +pub struct Parker { + unparker: Unparker, +} +unsafe impl Send for Parker {} +unsafe impl Sync for Parker {} +impl Parker { + pub fn new() -> Self { + Parker { + unparker: Unparker::new(), + } + } + pub fn park(&self) { + self.unparker.park() + } + pub fn park_timeout(&self, timeout: u32) -> bool { + self.unparker.park_timeout(timeout) + } + pub fn unpark(&self) -> bool { + self.unparker.unpark() + } + pub fn unparker(&self) -> Unparker { + self.unparker.clone() + } +} +pub struct Unparker { + inner: NonNull, +} +impl Unparker { + fn new() -> Self { + let inner = box unsafe { Inner::new() }; + unsafe { inner.init() }; + Self::from_inner(Box::leak(inner).into()) + } + #[inline] + fn inner(&self) -> &Inner { + unsafe { self.inner.as_ref() } + } + #[inline] + fn from_inner(inner: NonNull) -> Self { + Self { inner } + } + #[inline] + fn park(&self) { + unsafe { self.inner().park() }; + } + #[inline] + fn park_timeout(&self, timeout: u32) -> bool { + unsafe { self.inner().park_timeout(timeout) } + } + #[inline] + pub fn unpark(&self) -> bool { + unsafe { self.inner().unpark() } + } +} +unsafe impl Send for Unparker {} +unsafe impl Sync for Unparker {} +impl Clone for Unparker { + fn clone(&self) -> Self { + self.inner().cnt.fetch_add(1, Relaxed); + Self::from_inner(self.inner) + } +} +impl Drop for Unparker { + fn drop(&mut self) { + if self.inner().cnt.fetch_sub(1, Acquire) == 1 { + let _ = unsafe { Box::from_raw(self.inner.as_ptr()) }; + } + } +} +pub fn pair() -> (Parker, Unparker) { + let p = Parker::new(); + let u = p.unparker(); + (p, u) +} diff --git a/src/liteos/mod.rs b/src/liteos/mod.rs index 5bc3e593912faff961daae92ba4c7eabc915cf8b..1f766684d1b7c8c80b950fe596907e08f316553e 100644 --- a/src/liteos/mod.rs +++ b/src/liteos/mod.rs @@ -1,5 +1,9 @@ #[allow(unused, non_camel_case_types, non_snake_case)] mod libc; +pub mod locks; mod malloc; pub mod os; +#[allow(unused, non_camel_case_types, non_snake_case)] +mod sysinfo; + pub mod thread; diff --git a/src/liteos/os.rs b/src/liteos/os.rs index 51b1f87deb11f3244179f4c96ca6150a9b0679c6..8da174246a4b6d22b2903ecdae73e25907cc4f0d 100644 --- a/src/liteos/os.rs +++ b/src/liteos/os.rs @@ -1,6 +1,9 @@ use core::str::from_utf8_unchecked; -use super::libc::sys::{self, *}; +use super::{ + libc::sys::{self, *}, + sysinfo::LOSCFG_BASE_CORE_TICK_PER_SECOND, +}; use alloc::string::{String, ToString}; #[inline(always)] pub fn errno() -> i32 { @@ -17,15 +20,22 @@ pub fn error_msg(errno: i32) -> String { } } extern "C" { - pub fn printf(fmt: *const i8, ...) -> i32; + pub fn printf(fmt: *const u8, ...) -> i32; } #[inline(always)] pub(crate) fn page_size() -> usize { 4 } -pub(crate) fn get_tick_count() -> u32 { - 222 +#[inline(always)] +pub(crate) fn get_tickcount() -> u32 { + unsafe { (LOS_TickCountGet() as u32) * (1000 / LOSCFG_BASE_CORE_TICK_PER_SECOND) as u32 } } + +#[cfg(LOSCFG_KERNEL_SMP)] +pub const CPU_CORE_NUMBERS: usize = super::sysinfo::LOSCFG_KERNEL_SMP_CORE_NUM; +#[cfg(not(LOSCFG_KERNEL_SMP))] +pub const CPU_CORE_NUMBERS: usize = 1; + #[allow(dead_code)] #[inline] pub fn abort() -> ! { diff --git a/src/unix/locks/mod.rs b/src/unix/locks/mod.rs index 858918a194c9b52a1a75415bedce89e5bff551bb..8c4a021f445d6abe7ab167af34f09f3bc6aec961 100644 --- a/src/unix/locks/mod.rs +++ b/src/unix/locks/mod.rs @@ -1,6 +1,5 @@ mod futex; mod futex_rwlock; -mod parker; +pub mod parker; pub use futex::*; pub use futex_rwlock::{MovableRwLock, RwLock}; -pub use parker::*; diff --git a/src/unix/locks/parker.rs b/src/unix/locks/parker.rs index c8591ba79c51e1ea1bb514611417ae6d1fe1652c..a6a63cb9956c3c07adea505afa8e667b73447315 100644 --- a/src/unix/locks/parker.rs +++ b/src/unix/locks/parker.rs @@ -1,80 +1,131 @@ #[cfg(test)] mod tests; +use alloc::boxed::Box; + use crate::unix::utils::{futex_wait, futex_wake}; +use core::ptr::NonNull; use core::sync::atomic::AtomicU32; -use core::sync::atomic::Ordering::{Acquire, Release}; +use core::sync::atomic::Ordering::{Acquire, Relaxed}; const PARKED: u32 = u32::MAX; const EMPTY: u32 = 0; const NOTIFIED: u32 = 1; -pub struct Parker { +struct Inner { + cnt: AtomicU32, state: AtomicU32, } -impl Parker { +impl Inner { #[inline] - pub const fn new() -> Self { - Parker { + pub fn new() -> Self { + Inner { + cnt: AtomicU32::new(1), state: AtomicU32::new(EMPTY), } } - - // Assumes this is only called by the thread that owns the Parker, - // which means that `self.state != PARKED`. - pub unsafe fn park(&self) { - // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the - // first case. - if self.state.fetch_sub(1, Acquire) == NOTIFIED { - return; - } - loop { - // Wait for something to happen, assuming it's still set to PARKED. + fn park(&self) { + if self.state.fetch_sub(1, Acquire) != NOTIFIED { futex_wait(&self.state, PARKED, u32::MAX); - // Change NOTIFIED=>EMPTY and return in that case. - if self - .state - .compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire) - .is_ok() - { - return; - } else { - // Spurious wake up. We loop to try again. - } + self.state.swap(EMPTY, Relaxed); } } - // Assumes this is only called by the thread that owns the Parker, - // which means that `self.state != PARKED`. - pub unsafe fn park_timeout(&self, timeout: u32) { - // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the - // first case. + fn park_timeout(&self, timeout: u32) -> bool { if self.state.fetch_sub(1, Acquire) == NOTIFIED { - return; + return true; } - // Wait for something to happen, assuming it's still set to PARKED. futex_wait(&self.state, PARKED, timeout); - // This is not just a store, because we need to establish a - // release-acquire ordering with unpark(). if self.state.swap(EMPTY, Acquire) == NOTIFIED { - // Woke up because of unpark(). + true } else { - // Timeout or spurious wake up. - // We return either way, because we can't easily tell if it was the - // timeout or not. + false } } #[inline] - pub fn unpark(&self) { - // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and - // wake the thread in the first case. - // - // Note that even NOTIFIED=>NOTIFIED results in a write. This is on - // purpose, to make sure every unpark() has a release-acquire ordering - // with park(). - if self.state.swap(NOTIFIED, Release) == PARKED { - futex_wake(&self.state); + fn unpark(&self) -> bool { + match self.state.swap(NOTIFIED, Acquire) { + EMPTY => return true, + NOTIFIED => return false, + _ => {} + }; + futex_wake(&self.state); + true + } +} + +pub struct Parker { + inner: Unparker, +} +unsafe impl Send for Parker {} +unsafe impl Sync for Parker {} +impl Parker { + #[inline] + pub fn new() -> Self { + Self { + inner: Unparker::new(), + } + } + #[inline] + pub fn park(&self) { + self.inner.park(); + } + #[inline] + pub fn park_timeout(&self, timeout: u32) -> bool { + self.inner.park_timeout(timeout) + } + #[inline] + pub fn unpark(&self) -> bool { + self.inner.unpark() + } + #[inline] + pub fn unparker(&self) -> Unparker { + self.inner.clone() + } +} + +pub struct Unparker { + inner: NonNull, +} +unsafe impl Send for Unparker {} +unsafe impl Sync for Unparker {} +impl Unparker { + fn new() -> Self { + let inner = box Inner::new(); + Self::from_inner(Box::leak(inner).into()) + } + fn inner(&self) -> &Inner { + unsafe { self.inner.as_ref() } + } + fn from_inner(inner: NonNull) -> Self { + Self { inner } + } + pub fn park(&self) { + self.inner().park(); + } + pub fn park_timeout(&self, ms: u32) -> bool { + self.inner().park_timeout(ms) + } + pub fn unpark(&self) -> bool { + self.inner().unpark() + } +} +impl Clone for Unparker { + fn clone(&self) -> Self { + self.inner().cnt.fetch_add(1, Relaxed); + Self { inner: self.inner } + } +} +impl Drop for Unparker { + fn drop(&mut self) { + if self.inner().cnt.fetch_sub(1, Acquire) == 1 { + unsafe { Box::from_raw(self.inner.as_ptr()) }; } } } +pub fn pair() -> (Parker, Unparker) { + let p = Parker::new(); + let u = p.unparker(); + (p, u) +} diff --git a/src/unix/locks/parker/tests.rs b/src/unix/locks/parker/tests.rs index 156dcbcd9fbcc368ac7b836054eedf0f16f8ddc7..24e6057c45780de48188df77e8b3b7f493ee120b 100644 --- a/src/unix/locks/parker/tests.rs +++ b/src/unix/locks/parker/tests.rs @@ -3,11 +3,9 @@ fn somke() { use super::Parker; let p = Parker::new(); p.unpark(); - unsafe { - p.park(); - p.unpark(); - p.park_timeout(1000); - } + p.park(); + p.unpark(); + p.park_timeout(1000); } #[test] diff --git a/src/unix/mod.rs b/src/unix/mod.rs index 94115de8e6cc7d81687ba666c6cb499a9f6bbd2d..96608223dd0c69cdcd8711310bc3b0db2b2f73ba 100644 --- a/src/unix/mod.rs +++ b/src/unix/mod.rs @@ -1,5 +1,6 @@ pub mod locks; mod malloc; pub mod os; +mod sysinfo; pub mod thread; mod utils; diff --git a/src/unix/os.rs b/src/unix/os.rs index df5e650357f589b1a43dac775aa680df1169ed36..eb6592ce984a5fd9354bbf4b7316c8c71f9ada47 100644 --- a/src/unix/os.rs +++ b/src/unix/os.rs @@ -1,5 +1,6 @@ #[cfg(test)] mod tests; +pub use super::sysinfo::CPU_CORE_NUMBERS; use super::utils::dlsym; use super::utils::TimeSpec; use alloc::string::String; @@ -29,8 +30,10 @@ pub(crate) fn page_size() -> usize { pub fn abort() -> ! { unsafe { libc::abort() }; } -pub use libc::printf; -pub(crate) fn get_tick_count() -> u32 { +extern "C" { + pub fn printf(fmt: *const u8, ...) -> i32; +} +pub(crate) fn get_tickcount() -> u32 { libc::timespec::now(libc::CLOCK_MONOTONIC).to_millisec() } dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); diff --git a/src/unix/thread.rs b/src/unix/thread.rs index ff3dd233815100b398f40f4f44986ef26218bb67..1d28d4248fb59687e52a88a0ad97b1cceac73c42 100644 --- a/src/unix/thread.rs +++ b/src/unix/thread.rs @@ -1,4 +1,4 @@ -#[cfg(test)] +#[cfg(all(test, not(target_os = "none")))] mod tests; use crate::{ error::{Error, Result}, @@ -59,7 +59,7 @@ impl Thread { #[inline] pub fn set_name(name: &str) { unsafe { - debug_assert!(libc::strnlen(name.as_ptr() as *const _, name.len()) <= name.len()); + debug_assert!(libc::strnlen(name.as_ptr() as *const _, name.len()) < name.len()); } unsafe { libc::prctl( diff --git a/src/unix/thread/tests.rs b/src/unix/thread/tests.rs index b79413fa97c4a50747f5fa7eadc0a170066bae78..260156779f459c84153e24fba7ea7f4d6d79a6da 100644 --- a/src/unix/thread/tests.rs +++ b/src/unix/thread/tests.rs @@ -1,4 +1,4 @@ -use crate::locks::Parker; +use crate::locks::parker::*; use super::Thread; @@ -49,3 +49,21 @@ fn test_thread_park() { fn test_sleep() { Thread::sleep(100); } +#[test] +fn test_thread_name() { + use super::Thread; + unsafe { + static mut TEST: [u8; 16] = [0u8; 16]; + let abc = Thread::new(1024 * 64, box || { + let name = [0u8; 16]; + Thread::set_name("0123456789abcdefg\0"); + libc::prctl(libc::PR_GET_NAME, &name); + Thread::sleep(100); + TEST = name; + assert_eq!(1, 1); + }) + .unwrap(); + abc.join(); + assert_eq!(&TEST, b"0123456789abcde\0"); + } +}