From 798e50ef0deb7d3a37965704975657ca029a1847 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Fri, 1 Jul 2022 08:05:38 +0000 Subject: [PATCH 01/27] LiteOS MemAlloc --- .cargo/config.toml | 11 +++--- .vscode/settings.json | 3 ++ src/common/malloc.rs | 40 +++++++++---------- src/liteos/lite_os_fn.rs | 83 ++++++++++++++++++++++++++++++++++++++++ src/liteos/malloc.rs | 40 ++++++++----------- src/liteos/mod.rs | 1 + src/liteos/os.rs | 14 +------ 7 files changed, 130 insertions(+), 62 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/liteos/lite_os_fn.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index c0f9ac1..c8a9230 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,4 +1,4 @@ -[target.x86_64-pc-windows-msvc] +[target.x86_64-pc-windows-msvc.arch] rustflags = [ "-C", "target-feature=-crt-static", # "-C",'link_arg=/ENTRY:main', @@ -18,8 +18,9 @@ rustflags = [ "--cfg", "liteos", "--cfg", - 'target_os="liteos"', # "--crate-type", # 'staticlib', + 'target_os="liteos_m"', ] -# [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/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..513cbeb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.checkOnSave.allTargets": false +} \ No newline at end of file diff --git a/src/common/malloc.rs b/src/common/malloc.rs index 5bddd1e..acdcd7b 100644 --- a/src/common/malloc.rs +++ b/src/common/malloc.rs @@ -36,28 +36,24 @@ pub const MIN_ALIGN: usize = 16; )))] pub const MIN_ALIGN: usize = 4; -cfg_if::cfg_if! { - if #[cfg(not(liteos))]{ - use core::{ - alloc::{GlobalAlloc, Layout}, - cmp, ptr, - }; - pub unsafe fn realloc_fallback( - alloc: &System, - ptr: *mut u8, - old_layout: Layout, - new_size: usize, - ) -> *mut u8 { - // Docs for GlobalAlloc::realloc require this to be valid: - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); +use core::{ + alloc::{GlobalAlloc, Layout}, + cmp, ptr, +}; +pub unsafe fn realloc_fallback( + alloc: &System, + ptr: *mut u8, + old_layout: Layout, + new_size: usize, +) -> *mut u8 { + // Docs for GlobalAlloc::realloc require this to be valid: + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); - let new_ptr = GlobalAlloc::alloc(alloc, new_layout); - if !new_ptr.is_null() { - let size = cmp::min(old_layout.size(), new_size); - ptr::copy_nonoverlapping(ptr, new_ptr, size); - GlobalAlloc::dealloc(alloc, ptr, old_layout); - } - new_ptr - } + let new_ptr = GlobalAlloc::alloc(alloc, new_layout); + if !new_ptr.is_null() { + let size = cmp::min(old_layout.size(), new_size); + ptr::copy_nonoverlapping(ptr, new_ptr, size); + GlobalAlloc::dealloc(alloc, ptr, old_layout); } + new_ptr } diff --git a/src/liteos/lite_os_fn.rs b/src/liteos/lite_os_fn.rs new file mode 100644 index 0000000..7990973 --- /dev/null +++ b/src/liteos/lite_os_fn.rs @@ -0,0 +1,83 @@ + +#[allow(unused)] +extern "C" { + // 初始化和删除内存池 + // LOS_MemInit 初始化一块指定的动态内存池,大小为size + pub fn LOS_MemInit(poll: *mut u8, size: u32) -> u32; + // LOS_MemDeInit 删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效 + pub fn LOS_MemDeInit(poll: *mut u8) -> u32; + + // 申请、释放动态内存 + // LOS_MemAlloc 从指定动态内存池中申请size长度的内存 + pub fn LOS_MemAlloc(pool: *mut u8, size: u32) -> *mut u8; + // LOS_MemFree 释放已申请的内存 + pub fn LOS_MemFree(poll: *mut u8, ptr: *mut u8) -> u32; + // LOS_MemRealloc 按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块 + pub fn LOS_MemRealloc(pool: *mut u8, ptr: *mut u8, size: u32) -> *mut u8; + // LOS_MemAllocAlign 从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存 + pub fn LOS_MemAllocAlign(pool: *mut u8, size: u32, boundary: u32) -> *mut u8; + + // 获取内存池信息 + // LOS_MemPoolSizeGet 获取指定动态内存池的总大小 + pub fn LOS_MemPoolSizeGet(pool: *const u8) -> u32; + // LOS_MemTotalUsedGet 获取指定动态内存池的总使用量大小 + pub fn LOS_MemTotalUsedGet(poll: *mut u8) -> u32; + // LOS_MemInfoGet 获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小 + pub fn LOS_MemInfoGet(pool: *mut u8, poolStatus: *mut LOS_MEM_POOL_STATUS) -> u32; + // LOS_MemPoolList 打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效 + pub fn LOS_MemPoolList() -> u32; + + // 获取内存块信息 + // LOS_MemFreeBlksGet 获取指定内存池的空闲内存块数量 + pub fn LOS_MemFreeBlksGet(pool: *mut u8) -> u32; + // LOS_MemUsedBlksGet 获取指定内存池已使用的内存块数量 + pub fn LOS_MemUsedBlksGet(pool: *mut u8) -> u32; + // LOS_MemTaskIdGet 获取申请了指定内存块的任务ID + pub fn LOS_MemTaskIdGet(ptr: *const u8) -> u32; + // LOS_MemLastUsedGet 获取内存池最后一个已使用内存块的结束地址 + pub fn LOS_MemLastUsedGet(pool: *mut u8) -> u32; + // LOS_MemNodeSizeCheck 获取指定内存块的总大小和可用大小,仅打开LOSCFG_BASE_MEM_NODE_SIZE_CHECK时有效 + pub fn LOS_MemNodeSizeCheck( + pool: *mut u8, + ptr: *mut u8, + totalSize: *mut u32, + availSize: *mut u32, + ) -> u32; + // LOS_MemFreeNodeShow 打印指定内存池的空闲内存块的大小及数量 + pub fn LOS_MemFreeNodeShow(pool: *mut u8) -> u32; + + // 检查指定内存池的完整性 + // LOS_MemIntegrityCheck 对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效 + pub fn LOS_MemIntegrityCheck(pool: *mut u8) -> u32; + + // 设置、获取内存检查级别,仅打开LOSCFG_BASE_MEM_NODE_SIZE_CHECK时有效 + // LOS_MemCheckLevelSet 设置内存检查级别 + pub fn LOS_MemCheckLevelSet(checkLevel: u8) -> u32; + // LOS_MemCheckLevelGet 获取内存检查级别 + pub fn LOS_MemCheckLevelGet() -> u8; + + // 为指定模块申请、释放动态内存,仅打开LOSCFG_MEM_MUL_MODULE时有效 + // LOS_MemMalloc 从指定动态内存池分配size长度的内存给指定模块,并纳入模块 + pub fn LOS_MemMalloc(pool: *mut u8, size: u32, moduleId: u32) -> *mut u8; + // LOS_MemMfree 释放已经申请的内存块,并纳入模块统计 + pub fn LOS_MemMfree(pool: *mut u8, ptr: *mut u8, moduleId: u32) -> u32; + // LOS_MemMallocAlign 从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存给指定模块,并纳入模块统计 + pub fn LOS_MemMallocAlign(pool: *mut u8, size: u32, boundary: u32, moduleId: u32) -> *mut u8; + // LOS_MemMrealloc 按size大小重新分配内存块给指定模块,并将原内存块内容拷贝到新内存块,同时纳入模块统计。如果新内存块申请成功,则释放原内存块 + pub fn LOS_MemMrealloc(pool: *mut u8, ptr: *mut u8, size: u32, moduleId: u32) -> *mut u8; + + // 获取指定模块的内存使用量 + // LOS_MemMusedGet 获取指定模块的内存使用量,仅打开LOSCFG_MEM_MUL_MODULE时有效 + pub fn LOS_MemMusedGet(mouduleId: u32) -> u32; + +} +#[allow(non_snake_case)] +#[repr(C)] +pub struct LOS_MEM_POOL_STATUS { + uwTotalUsedSize: u32, + uwTotalFreeSize: u32, + uwMaxFreeNodeSize: u32, + uwUsedNodeNum: u32, + uwFreeNodeNum: u32, + uwUsageWaterLine: u32, +} diff --git a/src/liteos/malloc.rs b/src/liteos/malloc.rs index 10a9cfe..9cce163 100644 --- a/src/liteos/malloc.rs +++ b/src/liteos/malloc.rs @@ -1,37 +1,31 @@ +use super::lite_os_fn::*; +use crate::common::malloc::{realloc_fallback, System, MIN_ALIGN}; use core::alloc::{GlobalAlloc, Layout}; - -use crate::{ - common::malloc::{System, MIN_ALIGN}, - os::{LOS_MemAllocAlign, LOS_MemFree, LOS_MemInit, LOS_MemRealloc, LOS_NOK}, -}; - -use core::ptr; -static POOL: [u8; 1024 * 64] = [0; 1024 * 64]; +extern "C" { + #[link_name = "__los_heap_addr_start__"] + static mut POOL: u8; +} unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if LOS_MemInit(POOL.as_ptr(), 1024 * 64) == LOS_NOK { - panic!("Memory initialization error.") + let ptr = if layout.align() <= MIN_ALIGN { + LOS_MemAlloc(&mut POOL, layout.size() as u32) + } else { + LOS_MemAllocAlign(&mut POOL, layout.size() as u32, layout.align() as u32) }; - LOS_MemAllocAlign(POOL.as_ptr(), layout.size(), MIN_ALIGN) - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - let ptr = self.alloc(layout); - if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); - } ptr } - #[inline] unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - LOS_MemFree(POOL.as_ptr(), ptr); + LOS_MemFree(&mut POOL, ptr); } #[inline] - unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 { - LOS_MemRealloc(POOL.as_ptr(), ptr, new_size) + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN { + LOS_MemRealloc(&mut POOL, ptr, new_size as u32) + } else { + realloc_fallback(self, ptr, layout, new_size) + } } } diff --git a/src/liteos/mod.rs b/src/liteos/mod.rs index 4c82ad2..21dbae7 100644 --- a/src/liteos/mod.rs +++ b/src/liteos/mod.rs @@ -1,3 +1,4 @@ +mod lite_os_fn; mod malloc; pub(crate) mod os; pub mod thread; diff --git a/src/liteos/os.rs b/src/liteos/os.rs index d583d69..d099ce1 100644 --- a/src/liteos/os.rs +++ b/src/liteos/os.rs @@ -1,19 +1,9 @@ use alloc::string::{String, ToString}; -pub const LOS_NOK: u32 = 1; -pub const LOS_OK: u32 = 0; - -extern "C" { - pub fn LOS_MemInit(pool: *const u8, size: u32) -> ErrorType; - pub fn LOS_MemAllocAlign(pool: *const u8, size: usize, boundary: usize) -> *mut u8; - pub fn LOS_MemFree(pool: *const u8, ptr: *const u8) -> ErrorType; - pub fn LOS_MemRealloc(pool: *const u8, ptr: *const u8, size: usize) -> *mut u8; -} -pub type ErrorType = u32; -pub fn errno() -> ErrorType { +pub fn errno() -> i32 { 0 } -pub fn error_msg(_no: ErrorType) -> String { +pub fn error_msg(_no: i32) -> String { "0".to_string() } pub(crate) fn get_tick_count() -> u32 { -- Gitee From af80c545c6fcbfc733d1e739ee0e3714d0059dbb Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 02:40:43 +0000 Subject: [PATCH 02/27] =?UTF-8?q?LiteOS=20=E7=BA=BF=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cargo/config.toml | 14 ++- Cargo.toml | 4 + README.md | 9 ++ build.rs | 56 ++++++++++ doc/build_and_tools.md | 0 doc/code_info.md | 18 ++++ src/lib.rs | 3 +- src/liteos/libc.rs | 145 ++++++++++++++++++++++++++ src/liteos/libc/config.rs | 16 +++ src/liteos/lite_os_fn.rs | 83 --------------- src/liteos/malloc.rs | 14 ++- src/liteos/mod.rs | 5 +- src/liteos/os.rs | 29 ++++-- src/liteos/thread.rs | 80 +++++++++++++- src/liteos/thread/tests.rs | 0 src/unix/locks/futex_rwlock/tests.rs | 2 +- src/unix/thread.rs | 16 +-- src/unix/thread/{test.rs => tests.rs} | 0 src/unix/utils/timespec.rs | 3 +- 19 files changed, 387 insertions(+), 110 deletions(-) create mode 100644 build.rs create mode 100644 doc/build_and_tools.md create mode 100644 doc/code_info.md create mode 100644 src/liteos/libc.rs create mode 100644 src/liteos/libc/config.rs delete mode 100644 src/liteos/lite_os_fn.rs create mode 100644 src/liteos/thread/tests.rs rename src/unix/thread/{test.rs => tests.rs} (100%) diff --git a/.cargo/config.toml b/.cargo/config.toml index c8a9230..450e903 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,8 @@ [target.x86_64-pc-windows-msvc.arch] rustflags = [ "-C", - "target-feature=-crt-static", # "-C",'link_arg=/ENTRY:main', + "target-feature=-crt-static", + # "-C",'link_arg=/ENTRY:main', "-C", "link_arg=legacy_stdio_definitions.lib", "-C", @@ -9,16 +10,23 @@ rustflags = [ "-C", "link_arg=ucrt.lib", "-C", - "link_arg=msvcrt.lib", # "-C","link_arg=libvcruntime.lib" # "-C","link_arg=libucrt.lib", # "-C","link_arg=libcmt.lib", + "link_arg=msvcrt.lib", + # "-C","link_arg=libvcruntime.lib" + # "-C","link_arg=libucrt.lib", + # "-C","link_arg=libcmt.lib", "--cfg", "WIN10", ] [target.thumbv7m-none-eabi] rustflags = [ + # Set the target system as Huawei liteos_ m "--cfg", "liteos", "--cfg", - 'target_os="liteos_m"', + 'target_os="liteos_m"', + # Specify LiteOS location + "--cfg", + 'LOS_PATH="../../stm32/LiteOS"', ] [build] diff --git a/Cargo.toml b/Cargo.toml index caae4ff..3262de7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,3 +28,7 @@ windows-sys = { version = "0.36.1", features = [ ] } [target.'cfg(liteos)'.dependencies] +libc = { version = "0.2.126", default-features = false } + +[build-dependencies] +regex = "1.5.6" diff --git a/README.md b/README.md index 9a92250..bfe70e9 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,12 @@ #### 介绍 操作系统级抽象,用来提供底层功能支持,例如线程,互斥锁,内存分配器等。 +#### 代码导读 +[Arch 源代码目录说明](./doc/code_info.md) + +文档主要对代码目录组织结构进行简要说明。 + +#### 编译介绍和开发工具 +[编译介绍和开发工具](./doc/build_and_tools.md) + +文档主要介绍嵌入式平台下编译环境搭建,及配置方法。对于Windows,Linux等大型系统,直接使用Rust常规编译即可。 \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..b1c5ab3 --- /dev/null +++ b/build.rs @@ -0,0 +1,56 @@ +use regex::Regex; +use std::{ + env, + fs::File, + io::{BufRead, BufReader, Write}, + path::PathBuf, + str::FromStr, +}; +fn main() { + let target_os = env::var("CARGO_CFG_LITEOS").is_ok(); + //解码LiteOS 配置信息,并自动生成配置文件。 + if target_os { + let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); + let los_path = PathBuf::from_str(&los_path).unwrap(); + let fs = File::options() + .read(true) + .open(los_path.join(".config")) + .unwrap(); + let fs = BufReader::new(fs); + let mut fcfg = File::options() + .write(true) + .create(true) + .truncate(true) + .open("./src/liteos/libc/config.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() + }; + + for line in fs.lines() { + if let Ok(s) = line { + if is_empty_line.is_match(&s) { + continue; + } + let mc = kv.captures(&s).unwrap(); + let key = mc.get(1).unwrap().as_str(); + let value = mc.get(2).unwrap().as_str(); + if value.parse::().is_ok() { + write!(&mut fcfg, "pub const {}: usize = {}usize;\n", key, value).unwrap(); + } else if value == "y" { + println!("cargo:rustc-cfg={}", key); + } else if value.len() > 0 { + println!("cargo:rustc_cfg='{}={}'", key, value); + } + } + } + println!( + "cargo:rerun-if-changed={}", + los_path.join(".config").to_str().unwrap() + ); + } + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/doc/build_and_tools.md b/doc/build_and_tools.md new file mode 100644 index 0000000..e69de29 diff --git a/doc/code_info.md b/doc/code_info.md new file mode 100644 index 0000000..7edab6e --- /dev/null +++ b/doc/code_info.md @@ -0,0 +1,18 @@ +### 平台架构层目录结构说明 + +关于代码树中各个目录存放的源代码的相关内容简介如下: + +| 一级目录 | 二级目录 | 三级目录 | 说明 | +| ---------- | ----------------------- | --------------------- | -------------------------- | +| .cargo | | | Cargo 编译配置文件 | +|doc | | | 文档 | +|scr | | | 原码 | +| |common | |平台无关部分代码| +| |liteos | |华为LiteOS_M 相关实现| +| | |libc |编译时生成的 Lite_OS 配置信息| +| |unix | |类Unix系统相关实现| +| | |locks |Mutex,parker,rwlock...| +| | |malloc |内存分配单元测试| +| | |os |系统功能单元测试| +| | |thread |线程功能单元测试| +| | |utils |timespec等辅助代码| \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 75f5d5c..1a9b19f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,8 @@ cfg_if! { mod windows; }else if #[cfg(liteos)]{ mod liteos; - use liteos::os; + pub use liteos::os; pub use liteos::thread; } } + diff --git a/src/liteos/libc.rs b/src/liteos/libc.rs new file mode 100644 index 0000000..2ee7280 --- /dev/null +++ b/src/liteos/libc.rs @@ -0,0 +1,145 @@ +mod config; +pub type size_t = usize; +pub mod heap { + #[repr(C)] + pub struct LOS_MEM_POOL_STATUS { + uwTotalUsedSize: u32, + uwTotalFreeSize: u32, + uwMaxFreeNodeSize: u32, + uwUsedNodeNum: u32, + uwFreeNodeNum: u32, + #[cfg(LOSCFG_MEM_TASK_STAT)] + uwUsageWaterLine: u32, + } + extern "C" { + // 初始化和删除内存池 + // LOS_MemInit 初始化一块指定的动态内存池,大小为size + pub fn LOS_MemInit(poll: *mut u8, size: u32) -> u32; + // LOS_MemDeInit 删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效 + pub fn LOS_MemDeInit(poll: *mut u8) -> u32; + + // 申请、释放动态内存 + // LOS_MemAlloc 从指定动态内存池中申请size长度的内存 + pub fn LOS_MemAlloc(pool: *mut u8, size: u32) -> *mut u8; + // LOS_MemFree 释放已申请的内存 + pub fn LOS_MemFree(poll: *mut u8, ptr: *mut u8) -> u32; + // LOS_MemRealloc 按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块 + pub fn LOS_MemRealloc(pool: *mut u8, ptr: *mut u8, size: u32) -> *mut u8; + // LOS_MemAllocAlign 从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存 + pub fn LOS_MemAllocAlign(pool: *mut u8, size: u32, boundary: u32) -> *mut u8; + + // 获取内存池信息 + // LOS_MemPoolSizeGet 获取指定动态内存池的总大小 + pub fn LOS_MemPoolSizeGet(pool: *const u8) -> u32; + // LOS_MemTotalUsedGet 获取指定动态内存池的总使用量大小 + pub fn LOS_MemTotalUsedGet(poll: *mut u8) -> u32; + // LOS_MemInfoGet 获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小 + pub fn LOS_MemInfoGet(pool: *mut u8, poolStatus: *mut LOS_MEM_POOL_STATUS) -> u32; + // LOS_MemPoolList 打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效 + pub fn LOS_MemPoolList() -> u32; + + // 获取内存块信息 + // LOS_MemFreeBlksGet 获取指定内存池的空闲内存块数量 + pub fn LOS_MemFreeBlksGet(pool: *mut u8) -> u32; + // LOS_MemUsedBlksGet 获取指定内存池已使用的内存块数量 + pub fn LOS_MemUsedBlksGet(pool: *mut u8) -> u32; + // LOS_MemTaskIdGet 获取申请了指定内存块的任务ID + pub fn LOS_MemTaskIdGet(ptr: *const u8) -> u32; + // LOS_MemLastUsedGet 获取内存池最后一个已使用内存块的结束地址 + pub fn LOS_MemLastUsedGet(pool: *mut u8) -> u32; + // LOS_MemNodeSizeCheck 获取指定内存块的总大小和可用大小,仅打开LOSCFG_BASE_MEM_NODE_SIZE_CHECK时有效 + pub fn LOS_MemNodeSizeCheck( + pool: *mut u8, + ptr: *mut u8, + totalSize: *mut u32, + availSize: *mut u32, + ) -> u32; + // LOS_MemFreeNodeShow 打印指定内存池的空闲内存块的大小及数量 + pub fn LOS_MemFreeNodeShow(pool: *mut u8) -> u32; + + // 检查指定内存池的完整性 + // LOS_MemIntegrityCheck 对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效 + pub fn LOS_MemIntegrityCheck(pool: *mut u8) -> u32; + + // 设置、获取内存检查级别,仅打开LOSCFG_BASE_MEM_NODE_SIZE_CHECK时有效 + // LOS_MemCheckLevelSet 设置内存检查级别 + pub fn LOS_MemCheckLevelSet(checkLevel: u8) -> u32; + // LOS_MemCheckLevelGet 获取内存检查级别 + pub fn LOS_MemCheckLevelGet() -> u8; + + // 为指定模块申请、释放动态内存,仅打开LOSCFG_MEM_MUL_MODULE时有效 + // LOS_MemMalloc 从指定动态内存池分配size长度的内存给指定模块,并纳入模块 + pub fn LOS_MemMalloc(pool: *mut u8, size: u32, moduleId: u32) -> *mut u8; + // LOS_MemMfree 释放已经申请的内存块,并纳入模块统计 + pub fn LOS_MemMfree(pool: *mut u8, ptr: *mut u8, moduleId: u32) -> u32; + // LOS_MemMallocAlign 从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存给指定模块,并纳入模块统计 + pub fn LOS_MemMallocAlign( + pool: *mut u8, + size: u32, + boundary: u32, + moduleId: u32, + ) -> *mut u8; + // LOS_MemMrealloc 按size大小重新分配内存块给指定模块,并将原内存块内容拷贝到新内存块,同时纳入模块统计。如果新内存块申请成功,则释放原内存块 + pub fn LOS_MemMrealloc(pool: *mut u8, ptr: *mut u8, size: u32, moduleId: u32) -> *mut u8; + + // 获取指定模块的内存使用量 + // LOS_MemMusedGet 获取指定模块的内存使用量,仅打开LOSCFG_MEM_MUL_MODULE时有效 + pub fn LOS_MemMusedGet(mouduleId: u32) -> u32; + } +} +pub mod sys { + use super::size_t; + + 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 mod pthread { + use core::ffi::c_void; + + use super::size_t; + + 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; + #[repr(C)] + pub struct pthread_attr_t { + __size: [u32; 15], + #[cfg(LOSCFG_KERNEL_SMP)] + __size1: [usize; 128 / core::mem::size_of::()], + } + extern "C" { + pub fn pthread_attr_init(attr: *mut pthread_attr_t) -> i32; + pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> i32; + pub fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, stackSize: size_t) -> i32; + pub fn pthread_create( + thread: *mut pthread_t, + attr: *const pthread_attr_t, + f: extern "C" fn(*mut core::ffi::c_void) -> *mut core::ffi::c_void, + arg: *mut c_void, + ) -> i32; + + 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 { + extern "C" { + pub fn LOS_MS2Tick(millisec: u32) -> u32; + } +} +pub mod task { + extern "C" { + pub fn LOS_TaskDelay(tick: u32) -> u32; + } +} + +extern "C" { + pub fn printf(fmt: *const u8, ...) -> i32; +} diff --git a/src/liteos/libc/config.rs b/src/liteos/libc/config.rs new file mode 100644 index 0000000..5bdbe1b --- /dev/null +++ b/src/liteos/libc/config.rs @@ -0,0 +1,16 @@ +//The following content is automatically generated by the compiler. +//please do not modify it. +pub const LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT: usize = 20usize; +pub const LOSCFG_BASE_CORE_TSK_LIMIT: usize = 20usize; +pub const LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE: usize = 400usize; +pub const LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE: usize = 800usize; +pub const LOSCFG_BASE_CORE_TSK_SWTMR_STACK_SIZE: usize = 800usize; +pub const LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE: usize = 400usize; +pub const LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO: usize = 10usize; +pub const LOSCFG_BASE_CORE_TICK_PER_SECOND: usize = 1000usize; +pub const LOSCFG_PLATFORM_HWI_LIMIT: usize = 256usize; +pub const LOSCFG_HWI_PRIO_LIMIT: usize = 32usize; +pub const LOSCFG_BASE_CORE_SWTMR_LIMIT: usize = 1usize; +pub const LOSCFG_BASE_IPC_QUEUE_LIMIT: usize = 1usize; +pub const LOSCFG_BASE_IPC_MUX_LIMIT: usize = 1usize; +pub const LOSCFG_BASE_IPC_SEM_LIMIT: usize = 20usize; diff --git a/src/liteos/lite_os_fn.rs b/src/liteos/lite_os_fn.rs deleted file mode 100644 index 7990973..0000000 --- a/src/liteos/lite_os_fn.rs +++ /dev/null @@ -1,83 +0,0 @@ - -#[allow(unused)] -extern "C" { - // 初始化和删除内存池 - // LOS_MemInit 初始化一块指定的动态内存池,大小为size - pub fn LOS_MemInit(poll: *mut u8, size: u32) -> u32; - // LOS_MemDeInit 删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效 - pub fn LOS_MemDeInit(poll: *mut u8) -> u32; - - // 申请、释放动态内存 - // LOS_MemAlloc 从指定动态内存池中申请size长度的内存 - pub fn LOS_MemAlloc(pool: *mut u8, size: u32) -> *mut u8; - // LOS_MemFree 释放已申请的内存 - pub fn LOS_MemFree(poll: *mut u8, ptr: *mut u8) -> u32; - // LOS_MemRealloc 按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块 - pub fn LOS_MemRealloc(pool: *mut u8, ptr: *mut u8, size: u32) -> *mut u8; - // LOS_MemAllocAlign 从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存 - pub fn LOS_MemAllocAlign(pool: *mut u8, size: u32, boundary: u32) -> *mut u8; - - // 获取内存池信息 - // LOS_MemPoolSizeGet 获取指定动态内存池的总大小 - pub fn LOS_MemPoolSizeGet(pool: *const u8) -> u32; - // LOS_MemTotalUsedGet 获取指定动态内存池的总使用量大小 - pub fn LOS_MemTotalUsedGet(poll: *mut u8) -> u32; - // LOS_MemInfoGet 获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小 - pub fn LOS_MemInfoGet(pool: *mut u8, poolStatus: *mut LOS_MEM_POOL_STATUS) -> u32; - // LOS_MemPoolList 打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效 - pub fn LOS_MemPoolList() -> u32; - - // 获取内存块信息 - // LOS_MemFreeBlksGet 获取指定内存池的空闲内存块数量 - pub fn LOS_MemFreeBlksGet(pool: *mut u8) -> u32; - // LOS_MemUsedBlksGet 获取指定内存池已使用的内存块数量 - pub fn LOS_MemUsedBlksGet(pool: *mut u8) -> u32; - // LOS_MemTaskIdGet 获取申请了指定内存块的任务ID - pub fn LOS_MemTaskIdGet(ptr: *const u8) -> u32; - // LOS_MemLastUsedGet 获取内存池最后一个已使用内存块的结束地址 - pub fn LOS_MemLastUsedGet(pool: *mut u8) -> u32; - // LOS_MemNodeSizeCheck 获取指定内存块的总大小和可用大小,仅打开LOSCFG_BASE_MEM_NODE_SIZE_CHECK时有效 - pub fn LOS_MemNodeSizeCheck( - pool: *mut u8, - ptr: *mut u8, - totalSize: *mut u32, - availSize: *mut u32, - ) -> u32; - // LOS_MemFreeNodeShow 打印指定内存池的空闲内存块的大小及数量 - pub fn LOS_MemFreeNodeShow(pool: *mut u8) -> u32; - - // 检查指定内存池的完整性 - // LOS_MemIntegrityCheck 对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效 - pub fn LOS_MemIntegrityCheck(pool: *mut u8) -> u32; - - // 设置、获取内存检查级别,仅打开LOSCFG_BASE_MEM_NODE_SIZE_CHECK时有效 - // LOS_MemCheckLevelSet 设置内存检查级别 - pub fn LOS_MemCheckLevelSet(checkLevel: u8) -> u32; - // LOS_MemCheckLevelGet 获取内存检查级别 - pub fn LOS_MemCheckLevelGet() -> u8; - - // 为指定模块申请、释放动态内存,仅打开LOSCFG_MEM_MUL_MODULE时有效 - // LOS_MemMalloc 从指定动态内存池分配size长度的内存给指定模块,并纳入模块 - pub fn LOS_MemMalloc(pool: *mut u8, size: u32, moduleId: u32) -> *mut u8; - // LOS_MemMfree 释放已经申请的内存块,并纳入模块统计 - pub fn LOS_MemMfree(pool: *mut u8, ptr: *mut u8, moduleId: u32) -> u32; - // LOS_MemMallocAlign 从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存给指定模块,并纳入模块统计 - pub fn LOS_MemMallocAlign(pool: *mut u8, size: u32, boundary: u32, moduleId: u32) -> *mut u8; - // LOS_MemMrealloc 按size大小重新分配内存块给指定模块,并将原内存块内容拷贝到新内存块,同时纳入模块统计。如果新内存块申请成功,则释放原内存块 - pub fn LOS_MemMrealloc(pool: *mut u8, ptr: *mut u8, size: u32, moduleId: u32) -> *mut u8; - - // 获取指定模块的内存使用量 - // LOS_MemMusedGet 获取指定模块的内存使用量,仅打开LOSCFG_MEM_MUL_MODULE时有效 - pub fn LOS_MemMusedGet(mouduleId: u32) -> u32; - -} -#[allow(non_snake_case)] -#[repr(C)] -pub struct LOS_MEM_POOL_STATUS { - uwTotalUsedSize: u32, - uwTotalFreeSize: u32, - uwMaxFreeNodeSize: u32, - uwUsedNodeNum: u32, - uwFreeNodeNum: u32, - uwUsageWaterLine: u32, -} diff --git a/src/liteos/malloc.rs b/src/liteos/malloc.rs index 9cce163..19c78cc 100644 --- a/src/liteos/malloc.rs +++ b/src/liteos/malloc.rs @@ -1,6 +1,7 @@ -use super::lite_os_fn::*; +use super::libc::heap::*; use crate::common::malloc::{realloc_fallback, System, MIN_ALIGN}; use core::alloc::{GlobalAlloc, Layout}; + extern "C" { #[link_name = "__los_heap_addr_start__"] static mut POOL: u8; @@ -8,10 +9,13 @@ extern "C" { unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // Liteos requires that the length of memory allocation must be the 4-byte alignment + let size = layout.size() as u32; + let size = (size + (4 - 1)) & (-4i32 as u32); let ptr = if layout.align() <= MIN_ALIGN { - LOS_MemAlloc(&mut POOL, layout.size() as u32) + LOS_MemAlloc(&mut POOL, size) } else { - LOS_MemAllocAlign(&mut POOL, layout.size() as u32, layout.align() as u32) + LOS_MemAllocAlign(&mut POOL, size, layout.align() as u32) }; ptr } @@ -22,8 +26,10 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + let size = new_size as u32; + let size = (size + (4 - 1)) & (-4i32 as u32); if layout.align() <= MIN_ALIGN { - LOS_MemRealloc(&mut POOL, ptr, new_size as u32) + LOS_MemRealloc(&mut POOL, ptr, size) } else { realloc_fallback(self, ptr, layout, new_size) } diff --git a/src/liteos/mod.rs b/src/liteos/mod.rs index 21dbae7..5bc3e59 100644 --- a/src/liteos/mod.rs +++ b/src/liteos/mod.rs @@ -1,4 +1,5 @@ -mod lite_os_fn; +#[allow(unused, non_camel_case_types, non_snake_case)] +mod libc; mod malloc; -pub(crate) mod os; +pub mod os; pub mod thread; diff --git a/src/liteos/os.rs b/src/liteos/os.rs index d099ce1..6ad6163 100644 --- a/src/liteos/os.rs +++ b/src/liteos/os.rs @@ -1,13 +1,30 @@ -use alloc::string::{String, ToString}; +use core::str::from_utf8_unchecked; +use super::libc::sys::{self, *}; +use alloc::string::{String, ToString}; +#[inline(always)] pub fn errno() -> i32 { - 0 + unsafe { *__errno_location() as i32 } } -pub fn error_msg(_no: i32) -> String { - "0".to_string() +pub fn error_msg(errno: i32) -> String { + let mut buf = [0u8; 256]; + unsafe { + if strerror_r(errno, buf.as_mut_ptr(), buf.len()) < 0 { + panic!("strerror_r failure"); + } + let len = strnlen(buf.as_mut_ptr(), buf.len()); + from_utf8_unchecked(&buf[0..len]).to_string() + } +} +#[inline(always)] +pub(crate) fn page_size() -> usize { + 4 } pub(crate) fn get_tick_count() -> u32 { 222 } -#[cfg(target_arch = "v7m")] -fn test_shuaihu() {} +#[allow(dead_code)] +#[inline] +pub fn abort() -> ! { + unsafe { sys::abort() }; +} diff --git a/src/liteos/thread.rs b/src/liteos/thread.rs index 0ce5e12..4c3d8d0 100644 --- a/src/liteos/thread.rs +++ b/src/liteos/thread.rs @@ -1,4 +1,80 @@ -pub struct Thread(); +#[cfg(test)] +mod tests; +use crate::{ + error::{Error, Result}, + os::{self, errno, error_msg}, +}; +use alloc::boxed::Box; +use core::{cmp, mem, ptr}; +pub const DEFAULT_STACK_SIZE: usize = super::libc::pthread::DEFAULT_STACK_SIZE; +use super::libc::{pthread::*, task::LOS_TaskDelay, timer::LOS_MS2Tick}; + +pub struct Thread { + id: pthread_t, +} + impl Thread { - pub fn sleep(_ms: u32) {} + pub unsafe fn new(stack: usize, p: Box) -> Result { + let p = Box::into_raw(box p); + let mut native: pthread_t = mem::MaybeUninit::uninit().assume_init(); + let mut attr: pthread_attr_t = mem::MaybeUninit::uninit().assume_init(); + let rtn = pthread_attr_init(&mut attr); + debug_assert_eq!(rtn, 0); + let mut attr = utils::Defer(attr, |f| { + let rtn = pthread_attr_destroy(f); + debug_assert_eq!(rtn, 0); + }); + let stack_size = cmp::max(stack, MIN_STACK_SIZE); + + let page_size = os::page_size(); + let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); + let rtn = pthread_attr_setstacksize(&mut *attr, stack_size); + debug_assert_eq!(rtn, 0); + + let ret = pthread_create(&mut native, &*attr, thread_start, p as *mut _); + + return if ret != 0 { + // The thread failed to start and as a result p was not consumed. Therefore, it is + // safe to reconstruct the box so that it gets deallocated. + drop(Box::from_raw(p)); + Err(Error::from_raw_os_error(ret)) + } else { + Ok(Thread { id: native }) + }; + + extern "C" fn thread_start(main: *mut core::ffi::c_void) -> *mut core::ffi::c_void { + unsafe { + // Finally, let's run some code. + Box::from_raw(main as *mut Box)(); + } + ptr::null_mut() + } + } + #[inline] + pub fn yield_now() { + let ret = unsafe { sched_yield() }; + debug_assert_eq!(ret, 0); + } + #[inline] + pub fn set_name(_name: &str) {} + pub fn join(self) { + unsafe { + let ret = pthread_join(self.id, ptr::null_mut()); + mem::forget(self); + debug_assert!(ret == 0, "failed to join thread: {}", error_msg(errno())); + } + } + pub fn sleep(ms: u32) { + unsafe { + let ms = LOS_MS2Tick(ms); + LOS_TaskDelay(ms); + } + } +} + +impl Drop for Thread { + fn drop(&mut self) { + let ret = unsafe { pthread_detach(self.id) }; + debug_assert_eq!(ret, 0); + } } diff --git a/src/liteos/thread/tests.rs b/src/liteos/thread/tests.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/unix/locks/futex_rwlock/tests.rs b/src/unix/locks/futex_rwlock/tests.rs index c86c6d1..f414cc4 100644 --- a/src/unix/locks/futex_rwlock/tests.rs +++ b/src/unix/locks/futex_rwlock/tests.rs @@ -30,6 +30,6 @@ fn test_rwlock_multiple_read() { let abc = rw.try_write(); assert_eq!(abc, true); let abc = rw.try_read(); - debug_assert_eq!(abc, false); + assert_eq!(abc, false); } } diff --git a/src/unix/thread.rs b/src/unix/thread.rs index 9f34594..ff3dd23 100644 --- a/src/unix/thread.rs +++ b/src/unix/thread.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod test; +mod tests; use crate::{ error::{Error, Result}, os::{self, __pthread_get_minstack, errno, error_msg}, @@ -17,18 +17,20 @@ pub struct Thread { impl Thread { pub unsafe fn new(stack: usize, p: Box) -> Result { let p = Box::into_raw(box p); - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - - debug_assert_eq!(libc::pthread_attr_init(&mut attr), 0); + let mut native: libc::pthread_t = mem::MaybeUninit::uninit().assume_init(); + let mut attr: libc::pthread_attr_t = mem::MaybeUninit::uninit().assume_init(); + let rtn = libc::pthread_attr_init(&mut attr); + debug_assert_eq!(rtn, 0); let mut attr = utils::Defer(attr, |f| { - debug_assert_eq!(libc::pthread_attr_destroy(f), 0); + let rtn = libc::pthread_attr_destroy(f); + debug_assert_eq!(rtn, 0); }); let stack_size = cmp::max(stack, min_stack_size(&attr)); let page_size = os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - debug_assert_eq!(libc::pthread_attr_setstacksize(&mut *attr, stack_size), 0); + let rtn = libc::pthread_attr_setstacksize(&mut *attr, stack_size); + debug_assert_eq!(rtn, 0); let ret = libc::pthread_create(&mut native, &*attr, thread_start, p as *mut _); diff --git a/src/unix/thread/test.rs b/src/unix/thread/tests.rs similarity index 100% rename from src/unix/thread/test.rs rename to src/unix/thread/tests.rs diff --git a/src/unix/utils/timespec.rs b/src/unix/utils/timespec.rs index feb96cd..3710be0 100644 --- a/src/unix/utils/timespec.rs +++ b/src/unix/utils/timespec.rs @@ -23,7 +23,8 @@ impl TimeSpec for libc::timespec { fn now(id: libc::clockid_t) -> Self { let mut tp = MaybeUninit::uninit(); unsafe { - debug_assert_eq!(libc::clock_gettime(id, tp.as_mut_ptr()), 0); + let rtn =libc::clock_gettime(id, tp.as_mut_ptr()); + debug_assert_eq!(rtn, 0); tp.assume_init() } } -- Gitee From 405962129b5543e82a72a964cf468afc7a2fbd22 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 05:53:39 +0000 Subject: [PATCH 03/27] readme --- Cargo.toml | 21 +++++++++++++--- README.md | 8 +++--- doc/build_and_tools.md | 53 +++++++++++++++++++++++++++++++++++++++ examples/app.rs | 26 +++++++++++++++++++ src/liteos/libc.rs | 6 +---- src/liteos/libc/config.rs | 10 ++++---- src/liteos/os.rs | 3 +++ src/unix/os.rs | 1 + 8 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 examples/app.rs diff --git a/Cargo.toml b/Cargo.toml index 3262de7..6cbcf9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ crate-type = ["rlib"] [dependencies] cfg-if = "1.0.0" -utils = { path = "../utils" } +utils = { git = "https://gitee.com/iot-ua/utils.git" } [target.'cfg(unix)'.dependencies] libc = { version = "0.2.126", default-features = false } @@ -27,8 +27,21 @@ windows-sys = { version = "0.36.1", features = [ "Win32_System_SystemServices", ] } -[target.'cfg(liteos)'.dependencies] -libc = { version = "0.2.126", default-features = false } - [build-dependencies] regex = "1.5.6" + + +[[example]] +name="app" +crate-type=["staticlib"] + +[profile.release] +opt-level = 3 +debug = true +debug-assertions = false +overflow-checks = false +lto = true +panic = 'abort' +incremental = false +codegen-units = 1 +rpath = false \ No newline at end of file diff --git a/README.md b/README.md index bfe70e9..951e33f 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,10 @@ #### 介绍 操作系统级抽象,用来提供底层功能支持,例如线程,互斥锁,内存分配器等。 -#### 代码导读 -[Arch 源代码目录说明](./doc/code_info.md) +#### [Arch 源代码目录说明](./doc/code_info.md) 文档主要对代码目录组织结构进行简要说明。 -#### 编译介绍和开发工具 -[编译介绍和开发工具](./doc/build_and_tools.md) +#### [编译介绍和开发工具](./doc/build_and_tools.md) -文档主要介绍嵌入式平台下编译环境搭建,及配置方法。对于Windows,Linux等大型系统,直接使用Rust常规编译即可。 \ No newline at end of file +文档主要介绍嵌入式平台LiteOS_M下编译环境搭建,及配置方法。对于Windows,Linux等大型系统,直接使用Rust nightly常规编译即可。 \ No newline at end of file diff --git a/doc/build_and_tools.md b/doc/build_and_tools.md index e69de29..969a547 100644 --- a/doc/build_and_tools.md +++ b/doc/build_and_tools.md @@ -0,0 +1,53 @@ +### 目录 +- [配置&编译框架简介](#1) +- [配置文件说明](#2) + +

编译框架简介

+ +对于嵌入式平台构建应用的方式有两种方案:第一种方案是由Rust来编译构建应用,并生成可下载到硬件平台的二进行文件。第二种方案是Rust负责将应用编译为静态库,再由嵌入式系统连接并构建为可下载到硬件平台的二进制文件。这里我们选择的是第二种方案。这种方案可以更好的将系统移植与应用开发解耦。使应用开发人员只需要使用标准的Rust构建工具[cargo],加极少量的配置,就可以生成应用。 + +

配置文件说明

+ +平台抽象层使用标准的Rust构建工具进行配置。配置文件主要由 [.cargo](../.cargo) 文件夹下的[config](../.cargo/config.toml)文件,根文件夹下的[Cargo.toml](../Cargo.toml),[build.rs](../build.rs)的设置来完成. + +- [.cargo/config.toml](../.cargo/config.toml) 详细说明: + +``` +[target.x86_64-pc-windows-msvc.arch] # Mircrosoft Visual Studio 编译配置 +rustflags = [ + "-C", + "target-feature=-crt-static", # 静态连接 C 运行时库 + # "-C",'link_arg=/ENTRY:main', # 程序入口点函数为main + "-C", + "link_arg=legacy_stdio_definitions.lib", # printf 函数引入,在MSVC平台,printf默认被实现为了宏, + # 所以需要这个库来引入printf IO输出功能 + "-C", + "link_arg=vcruntime.lib", # VC运行时库 + # 参考 https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 + "-C", + "link_arg=ucrt.lib", + "-C", + "link_arg=msvcrt.lib", + # "-C","link_arg=libvcruntime.lib" + # "-C","link_arg=libucrt.lib", + # "-C","link_arg=libcmt.lib", + "--cfg", + "WIN10", +] +[target.thumbv7m-none-eabi] +rustflags = [ + # Set the target system as Huawei liteos_ m + "--cfg", + "liteos", + "--cfg", + 'target_os="liteos_m"', + # Specify LiteOS location + "--cfg", + 'LOS_PATH="../../stm32/LiteOS"', +] + +[build] +# Always compile for the instruction set of the STM32F1 +target = "thumbv7m-none-eabi" + +``` \ No newline at end of file diff --git a/examples/app.rs b/examples/app.rs new file mode 100644 index 0000000..695e210 --- /dev/null +++ b/examples/app.rs @@ -0,0 +1,26 @@ +#![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/src/liteos/libc.rs b/src/liteos/libc.rs index 2ee7280..c398d4b 100644 --- a/src/liteos/libc.rs +++ b/src/liteos/libc.rs @@ -138,8 +138,4 @@ pub mod task { extern "C" { pub fn LOS_TaskDelay(tick: u32) -> u32; } -} - -extern "C" { - pub fn printf(fmt: *const u8, ...) -> i32; -} +} \ No newline at end of file diff --git a/src/liteos/libc/config.rs b/src/liteos/libc/config.rs index 5bdbe1b..0e58341 100644 --- a/src/liteos/libc/config.rs +++ b/src/liteos/libc/config.rs @@ -1,7 +1,7 @@ //The following content is automatically generated by the compiler. //please do not modify it. -pub const LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT: usize = 20usize; -pub const LOSCFG_BASE_CORE_TSK_LIMIT: usize = 20usize; +pub const LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT: usize = 2usize; +pub const LOSCFG_BASE_CORE_TSK_LIMIT: usize = 12usize; pub const LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE: usize = 400usize; pub const LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE: usize = 800usize; pub const LOSCFG_BASE_CORE_TSK_SWTMR_STACK_SIZE: usize = 800usize; @@ -10,7 +10,7 @@ pub const LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO: usize = 10usize; pub const LOSCFG_BASE_CORE_TICK_PER_SECOND: usize = 1000usize; pub const LOSCFG_PLATFORM_HWI_LIMIT: usize = 256usize; pub const LOSCFG_HWI_PRIO_LIMIT: usize = 32usize; -pub const LOSCFG_BASE_CORE_SWTMR_LIMIT: usize = 1usize; -pub const LOSCFG_BASE_IPC_QUEUE_LIMIT: usize = 1usize; -pub const LOSCFG_BASE_IPC_MUX_LIMIT: usize = 1usize; +pub const LOSCFG_BASE_CORE_SWTMR_LIMIT: usize = 16usize; +pub const LOSCFG_BASE_IPC_QUEUE_LIMIT: usize = 10usize; +pub const LOSCFG_BASE_IPC_MUX_LIMIT: usize = 20usize; pub const LOSCFG_BASE_IPC_SEM_LIMIT: usize = 20usize; diff --git a/src/liteos/os.rs b/src/liteos/os.rs index 6ad6163..51b1f87 100644 --- a/src/liteos/os.rs +++ b/src/liteos/os.rs @@ -16,6 +16,9 @@ pub fn error_msg(errno: i32) -> String { from_utf8_unchecked(&buf[0..len]).to_string() } } +extern "C" { + pub fn printf(fmt: *const i8, ...) -> i32; +} #[inline(always)] pub(crate) fn page_size() -> usize { 4 diff --git a/src/unix/os.rs b/src/unix/os.rs index 23eaf76..df5e650 100644 --- a/src/unix/os.rs +++ b/src/unix/os.rs @@ -29,6 +29,7 @@ pub(crate) fn page_size() -> usize { pub fn abort() -> ! { unsafe { libc::abort() }; } +pub use libc::printf; pub(crate) fn get_tick_count() -> u32 { libc::timespec::now(libc::CLOCK_MONOTONIC).to_millisec() } -- Gitee From a009cc5ebd4f990cdac928c105f694346a654ae7 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 07:13:07 +0000 Subject: [PATCH 04/27] readme --- .cargo/config.toml | 34 +++++++++- Cargo.toml | 11 +-- README.md | 3 +- build.rs | 2 +- doc/build_and_tools.md | 151 +++++++++++++++++++++++++++++++++-------- examples/led.rs | 29 ++++++++ 6 files changed, 192 insertions(+), 38 deletions(-) create mode 100644 examples/led.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 450e903..553cec2 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,22 +1,52 @@ +# Mircrosoft Visual Studio 目标配置(ARM平台不需要) [target.x86_64-pc-windows-msvc.arch] rustflags = [ + # +crt_static Indicates a static connection to the C runtime library + # -crt_static Indicates dynamic connection to the C runtime library "-C", "target-feature=-crt-static", - # "-C",'link_arg=/ENTRY:main', + + # Program entry point function is main + # "-C",'link_arg=/ENTRY:main', + + # On MSVC platform, printf is implemented as macro by default, + # Therefore, this library is needed to import the printf function "-C", "link_arg=legacy_stdio_definitions.lib", + + # VC runtime library (dynamic connection) + # Reference: https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 "-C", "link_arg=vcruntime.lib", "-C", "link_arg=ucrt.lib", "-C", "link_arg=msvcrt.lib", - # "-C","link_arg=libvcruntime.lib" + # VC runtime library (static connection) + # "-C","link_arg=libvcruntime.lib" # "-C","link_arg=libucrt.lib", # "-C","link_arg=libcmt.lib", + + # Designated as win10 system. Some functions of the system below win10 cannot be used. + "--cfg", + "WIN10", +] + +[nightly-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 diff --git a/Cargo.toml b/Cargo.toml index 6cbcf9e..8321d77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,8 +32,12 @@ regex = "1.5.6" [[example]] -name="app" -crate-type=["staticlib"] +name = "app" +crate-type = ["staticlib"] + +[[example]] +name = "led" +crate-type = ["staticlib"] [profile.release] opt-level = 3 @@ -41,7 +45,6 @@ debug = true debug-assertions = false overflow-checks = false lto = true -panic = 'abort' incremental = false codegen-units = 1 -rpath = false \ No newline at end of file +rpath = false diff --git a/README.md b/README.md index 951e33f..ef390db 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,5 @@ #### [编译介绍和开发工具](./doc/build_and_tools.md) -文档主要介绍嵌入式平台LiteOS_M下编译环境搭建,及配置方法。对于Windows,Linux等大型系统,直接使用Rust nightly常规编译即可。 \ No newline at end of file +文档主要介绍嵌入式平台LiteOS_M下编译环境搭建,及配置方法。对于Windows,Linux等大型系统,直接使用Rust nightly常规编译即可。 + diff --git a/build.rs b/build.rs index b1c5ab3..822a128 100644 --- a/build.rs +++ b/build.rs @@ -8,7 +8,7 @@ use std::{ }; fn main() { let target_os = env::var("CARGO_CFG_LITEOS").is_ok(); - //解码LiteOS 配置信息,并自动生成配置文件。 + // Decode liteos configuration information and automatically generate configuration files. if target_os { let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); let los_path = PathBuf::from_str(&los_path).unwrap(); diff --git a/doc/build_and_tools.md b/doc/build_and_tools.md index 969a547..2589bc2 100644 --- a/doc/build_and_tools.md +++ b/doc/build_and_tools.md @@ -8,46 +8,137 @@

配置文件说明

-平台抽象层使用标准的Rust构建工具进行配置。配置文件主要由 [.cargo](../.cargo) 文件夹下的[config](../.cargo/config.toml)文件,根文件夹下的[Cargo.toml](../Cargo.toml),[build.rs](../build.rs)的设置来完成. +平台抽象层使用标准的Rust构建工具进行配置。配置文件主要由 [.cargo](../.cargo) 文件夹下的[config](../.cargo/config.toml)文件,根文件夹下的[Cargo.toml](../Cargo.toml),[build.rs](../build.rs)的设置来完成. -- [.cargo/config.toml](../.cargo/config.toml) 详细说明: +下面以 [野火_STM32F103指南者](https://embedfire.com/products/)为例,详细说明一下配置方法. + +- [.cargo/config.toml](../.cargo/config.toml) 详细内容如下: ``` -[target.x86_64-pc-windows-msvc.arch] # Mircrosoft Visual Studio 编译配置 -rustflags = [ - "-C", - "target-feature=-crt-static", # 静态连接 C 运行时库 - # "-C",'link_arg=/ENTRY:main', # 程序入口点函数为main - "-C", - "link_arg=legacy_stdio_definitions.lib", # printf 函数引入,在MSVC平台,printf默认被实现为了宏, - # 所以需要这个库来引入printf IO输出功能 - "-C", - "link_arg=vcruntime.lib", # VC运行时库 - # 参考 https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 - "-C", - "link_arg=ucrt.lib", - "-C", - "link_arg=msvcrt.lib", - # "-C","link_arg=libvcruntime.lib" - # "-C","link_arg=libucrt.lib", - # "-C","link_arg=libcmt.lib", - "--cfg", - "WIN10", -] +# 嵌入式ARM Cortex-M3 目标设置 [target.thumbv7m-none-eabi] rustflags = [ - # Set the target system as Huawei liteos_ m - "--cfg", + "--cfg", # 配置目标系统架构为LiteOS "liteos", - "--cfg", + + "--cfg", # 配置目标系统详细架构为Liteos-M 'target_os="liteos_m"', - # Specify LiteOS location - "--cfg", + + "--cfg", # 指定LiteOS系统Top文件夹位置 'LOS_PATH="../../stm32/LiteOS"', ] [build] -# Always compile for the instruction set of the STM32F1 +# 指定默认编译目标为 thumbv7m-none-eabi target = "thumbv7m-none-eabi" -``` \ No newline at end of file +``` + +对于嵌入式交叉编译来说,Cargo config 主要指定系统的类别及 Top 文件夹位置。 + +- [Cargo.toml](../Cargo.toml) 详细说内容如下: + +``` +[package] +edition = "2021" +name = "arch" +version = "0.1.0" + +[lib] +crate-type = ["rlib"] + +[dependencies] +cfg-if = "1.0.0" +utils = { git = "https://gitee.com/iot-ua/utils.git" } + +# 构建时-依赖正规则库 +[build-dependencies] +regex = "1.5.6" + + +[[example]] # 示例 app 配置 +name="app" +crate-type=["staticlib"] # 将示例生成为静态库 + +[[example]] +name = "led" # 示例 led 配置 +crate-type = ["staticlib"] # 将示例生成为静态库 + +[profile.release] # 编译信息 +opt-level = 2 # 优化层,在嵌入式系统上不启用优化将导致大量的栈空间使用,所以这里优化为2 +debug = true # 输出Debug 信息 +debug-assertions = false # 是不允许debug-assert 功能。这里不启用 +overflow-checks = false # 数据计算溢出检查是否启用,如果启用,出现溢出时将导致异常 +lto = true # 连接时优化 +incremental = false # 是否增量编译 +codegen-units = 1 # 代码生成并行库,值越少,越有利于优化,但速度越慢 +rpath = false # 调试信息使用相对路径,这里选择false. +``` +Cargo.toml 需要特别注意的是生成目标需要调整为静态库,以及优化级别的选择,优化级别为零时,将导致全部函数调用变更为非内联(inline),因此会导致很深的函数调用.也就意味着需要很大的运行时堆栈空间.因此, 不建议使用零级别优化. + +"debug = true" 会输出调试信息,如果需要使用 jtag 或 swd 接口进行调试的话,必须设置为 true. + + +- [build.rs](../build.rs) 详细说内容如下: + +``` +fn main() { + let target_os = env::var("CARGO_CFG_LITEOS").is_ok(); + //解码LiteOS 配置信息,并自动生成配置文件。 + if target_os { + //取得 LiteOS Top 文件夹 + let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); + let los_path = PathBuf::from_str(&los_path).unwrap(); + + //打开 LiteOS 配置文件 + let fs = File::options() + .read(true) + .open(los_path.join(".config")) + .unwrap(); + let fs = BufReader::new(fs); + let mut fcfg = File::options() + .write(true) + .create(true) + .truncate(true) + .open("./src/liteos/libc/config.rs") + .unwrap(); + unsafe { + write!(&mut fcfg,"//The following content is automatically generated by the compiler.\n//please do not modify it.\n").unwrap_unchecked() + }; + + let is_empty_line = Regex::new(r"^ *?#|^ *?$").unwrap(); + let kv = Regex::new(r#"^ *?(\w+) *?= *?(.*)$"#).unwrap(); + + // 分析配置文件内容,并生成Rust常量配置文件及feature配置信息。 + for line in fs.lines() { + if let Ok(s) = line { + if is_empty_line.is_match(&s) { + continue; + } + let mc = kv.captures(&s).unwrap(); + let key = mc.get(1).unwrap().as_str(); + let value = mc.get(2).unwrap().as_str(); + if value.parse::().is_ok() { + write!(&mut fcfg, "pub const {}: usize = {}usize;\n", key, value).unwrap(); + } else if value == "y" { + println!("cargo:rustc-cfg={}", key); + } else if value.len() > 0 { + println!("cargo:rustc_cfg='{}={}'", key, value); + } + } + } + // 当 LiteOS 配置文件发生变化时重新构建。 + println!( + "cargo:rerun-if-changed={}", + los_path.join(".config").to_str().unwrap() + ); + } + // 当 build.rs 文件发生变化时重新构建 + println!("cargo:rerun-if-changed=build.rs"); +} + +``` + +build.rs 构建脚本主要用于分析 LiteOS 配置信息,并生成 Rust 可使用的配置信息。这个脚本输出的内容在两个地方 ,一个是在 [src/liteos/libc/config.rs](../src/liteos/libc/config.rs),另一个在[target/thumbv7m-none-eabi/release/build/arch.../output](../target/thumbv7m-none-eabi/release/build/arch-b3f29851170e2ade/output). + +可通过查看这两个输出文件来分析编译器是否正常运行。 \ No newline at end of file diff --git a/examples/led.rs b/examples/led.rs new file mode 100644 index 0000000..43af96f --- /dev/null +++ b/examples/led.rs @@ -0,0 +1,29 @@ +#![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 {} +} -- Gitee From 112ad5c8f3ccda44648c057d9ee7c9f5ab2d57f3 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 07:53:52 +0000 Subject: [PATCH 05/27] build_and_tools.md --- doc/build_and_tools.md | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/doc/build_and_tools.md b/doc/build_and_tools.md index 2589bc2..d6dbc37 100644 --- a/doc/build_and_tools.md +++ b/doc/build_and_tools.md @@ -1,6 +1,7 @@ ### 目录 - [配置&编译框架简介](#1) - [配置文件说明](#2) +- [将应用添加到LiteOS系统](#3)

编译框架简介

@@ -10,7 +11,7 @@ 平台抽象层使用标准的Rust构建工具进行配置。配置文件主要由 [.cargo](../.cargo) 文件夹下的[config](../.cargo/config.toml)文件,根文件夹下的[Cargo.toml](../Cargo.toml),[build.rs](../build.rs)的设置来完成. -下面以 [野火_STM32F103指南者](https://embedfire.com/products/)为例,详细说明一下配置方法. +下面以 [野火_STM32F103指南者](https://embedfire.com/products/) 为例,详细说明一下配置方法. - [.cargo/config.toml](../.cargo/config.toml) 详细内容如下: @@ -141,4 +142,35 @@ fn main() { build.rs 构建脚本主要用于分析 LiteOS 配置信息,并生成 Rust 可使用的配置信息。这个脚本输出的内容在两个地方 ,一个是在 [src/liteos/libc/config.rs](../src/liteos/libc/config.rs),另一个在[target/thumbv7m-none-eabi/release/build/arch.../output](../target/thumbv7m-none-eabi/release/build/arch-b3f29851170e2ade/output). -可通过查看这两个输出文件来分析编译器是否正常运行。 \ No newline at end of file +可通过查看这两个输出文件来分析编译器是否正常运行。 + +

将App添加到LiteOS系统

+ +- 修改 [LiteOS/build/mk/los_config.mk](https://gitee.com/LiteOS/LiteOS/blob/master/build/mk/los_config.mk)以下位置: + +``` +40a41,42 +> ## 将应用添加到静态库列表 ## +> LITEOS_BASELIB :=-lled +125c127,129 +< WARNING_AS_ERROR := -Wall -Werror +--- +> WARNING_AS_ERROR := -Wall -Werror +> ## 新版 GCC 编译器会将数据下标访问警告转变为错误,所以这里需要修改检查等级 +> WARNING_AS_ERROR += -Werror=array-parameter=0 +302a307,308 +> ## 将输出路径添加到 C 静态库搜索路径 ## +> LITEOS_LD_PATH += -L"/home/shuaihu/project/rust/opcua/arch/target/thumbv7m-none-eabi/release/examples" +``` +这里主要目标是将 Rust 编译的静态库连接到 LiteOS 应用。 + +- 注释掉 [LiteOS/targets/STM32F103_FIRE_Arbitrary/Src/user_task.c](https://gitee.com/LiteOS/LiteOS/blob/master/targets/STM32F103_FIRE_Arbitrary/Src/user_task.c) 全部代码,并添加以下内容。 + +``` +void led_toggle(void) +{ + HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5); +} +``` +这里主要是实现 [野火_STM32F103指南者](https://embedfire.com/products/) 开发板的 LED 指示灯闪烁。 + -- Gitee From c1bf503d75c165c92566dafb54b2ea75830dd26a Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 08:06:09 +0000 Subject: [PATCH 06/27] build --- doc/build_and_tools.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/build_and_tools.md b/doc/build_and_tools.md index d6dbc37..5b755f0 100644 --- a/doc/build_and_tools.md +++ b/doc/build_and_tools.md @@ -2,6 +2,7 @@ - [配置&编译框架简介](#1) - [配置文件说明](#2) - [将应用添加到LiteOS系统](#3) +- [LiteOS 配置并运行Example](#3)

编译框架简介

@@ -174,3 +175,12 @@ void led_toggle(void) ``` 这里主要是实现 [野火_STM32F103指南者](https://embedfire.com/products/) 开发板的 LED 指示灯闪烁。 +

LiteOS 配置并运行Example

+ +首先参考以下内容,将LiteOS系统编译为bin文件. + +- [LiteOS-搭建Linux编译环境](https://gitee.com/LiteOS/LiteOS/blob/master/doc/LiteOS_Build_and_IDE.md#4-1) 搭建 LiteOS 编译开发环境. + +- [Linux下编译流程](https://gitee.com/LiteOS/LiteOS/blob/master/doc/LiteOS_Build_and_IDE.md#linux%E4%B8%8B%E7%BC%96%E8%AF%91%E6%B5%81%E7%A8%8B) 配置并编译LiteOS. + +然后通过 JLink 或 ST-Link 将编译好的 bin 文件下载到开发板.即可以看到开发板的 LED 指示灯以 1 秒为间隔闪烁. 至此,所有工作完成. 可以开始快乐的用 Rust 构建你的嵌入式应用了. \ No newline at end of file -- Gitee From 96073e256af7b572fbced078f7051a19d9960faf Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 08:14:47 +0000 Subject: [PATCH 07/27] build tools --- doc/build_and_tools.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/build_and_tools.md b/doc/build_and_tools.md index 5b755f0..69c1d12 100644 --- a/doc/build_and_tools.md +++ b/doc/build_and_tools.md @@ -69,11 +69,11 @@ crate-type = ["staticlib"] # 将示例生成为静态库 [profile.release] # 编译信息 opt-level = 2 # 优化层,在嵌入式系统上不启用优化将导致大量的栈空间使用,所以这里优化为2 debug = true # 输出Debug 信息 -debug-assertions = false # 是不允许debug-assert 功能。这里不启用 +debug-assertions = false # 是否允许debug-assert 功能。这里不启用 overflow-checks = false # 数据计算溢出检查是否启用,如果启用,出现溢出时将导致异常 lto = true # 连接时优化 incremental = false # 是否增量编译 -codegen-units = 1 # 代码生成并行库,值越少,越有利于优化,但速度越慢 +codegen-units = 1 # 代码生成并行库,值越少,越有利于优化,但编译速度越慢 rpath = false # 调试信息使用相对路径,这里选择false. ``` Cargo.toml 需要特别注意的是生成目标需要调整为静态库,以及优化级别的选择,优化级别为零时,将导致全部函数调用变更为非内联(inline),因此会导致很深的函数调用.也就意味着需要很大的运行时堆栈空间.因此, 不建议使用零级别优化. -- Gitee From 55e079729b163cb74ab5bf83598dc03794cc1f10 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 11:10:22 +0000 Subject: [PATCH 08/27] =?UTF-8?q?!6=20build.rs=20=E7=9B=B8=E5=AF=B9?= =?UTF-8?q?=E8=B7=AF=E5=BE=84Bug=20Fix=20*=20Merge=20branch=20'master'=20o?= =?UTF-8?q?f=20https://gitee.com/mini-tiger/arch=20*=20build=20=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=20*=20update=20src/liteos/libc.rs.=20*=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=96=87=E4=BB=B6=20src/liteos/libc=20*=20gitignore?= =?UTF-8?q?=20*=20delete=20config.rs=20*=20path=20bug=20*=20test=20*=20cur?= =?UTF-8?q?dir=20*=20build=20test=20*=20aafasdf=20*=20build.rs=20buf=20*?= =?UTF-8?q?=20=E6=89=93=E5=AD=97=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + Cargo.toml | 4 ++-- build.rs | 11 +++++++++-- doc/code_info.md | 2 +- src/liteos/libc.rs | 3 ++- src/liteos/libc/config.rs | 16 ---------------- 6 files changed, 15 insertions(+), 22 deletions(-) delete mode 100644 src/liteos/libc/config.rs diff --git a/.gitignore b/.gitignore index 4fffb2f..502d4f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target /Cargo.lock +src/liteos/config.rs diff --git a/Cargo.toml b/Cargo.toml index 8321d77..7d7c1df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,9 @@ version = "0.1.0" crate-type = ["rlib"] [dependencies] -cfg-if = "1.0.0" -utils = { git = "https://gitee.com/iot-ua/utils.git" } +utils = { git = "https://gitee.com/iot-ua/utils.git", branch = "develop" } +cfg-if = "1.0.0" [target.'cfg(unix)'.dependencies] libc = { version = "0.2.126", default-features = false } diff --git a/build.rs b/build.rs index 822a128..7430808 100644 --- a/build.rs +++ b/build.rs @@ -10,18 +10,25 @@ fn main() { let target_os = env::var("CARGO_CFG_LITEOS").is_ok(); // Decode liteos configuration information and automatically generate configuration files. if target_os { + let pwd = env::var("PWD").unwrap(); + let pwd = PathBuf::from_str(&pwd).unwrap(); + let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); + let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); - let los_path = PathBuf::from_str(&los_path).unwrap(); + let los_path = pwd.join(&los_path); + let fs = File::options() .read(true) .open(los_path.join(".config")) .unwrap(); let fs = BufReader::new(fs); + println!("{}",manifest_path.join("src/liteos/config.rs").to_str().unwrap()); let mut fcfg = File::options() .write(true) .create(true) .truncate(true) - .open("./src/liteos/libc/config.rs") + .open(manifest_path.join("src/liteos/config.rs")) .unwrap(); let is_empty_line = Regex::new(r"^ *?#|^ *?$").unwrap(); let kv = Regex::new(r#"^ *?(\w+) *?= *?(.*)$"#).unwrap(); diff --git a/doc/code_info.md b/doc/code_info.md index 7edab6e..87e7a82 100644 --- a/doc/code_info.md +++ b/doc/code_info.md @@ -6,7 +6,7 @@ | ---------- | ----------------------- | --------------------- | -------------------------- | | .cargo | | | Cargo 编译配置文件 | |doc | | | 文档 | -|scr | | | 原码 | +|src | | | 源码 | | |common | |平台无关部分代码| | |liteos | |华为LiteOS_M 相关实现| | | |libc |编译时生成的 Lite_OS 配置信息| diff --git a/src/liteos/libc.rs b/src/liteos/libc.rs index c398d4b..935ba12 100644 --- a/src/liteos/libc.rs +++ b/src/liteos/libc.rs @@ -1,3 +1,4 @@ +#[path = "./config.rs"] mod config; pub type size_t = usize; pub mod heap { @@ -138,4 +139,4 @@ pub mod task { extern "C" { pub fn LOS_TaskDelay(tick: u32) -> u32; } -} \ No newline at end of file +} diff --git a/src/liteos/libc/config.rs b/src/liteos/libc/config.rs deleted file mode 100644 index 0e58341..0000000 --- a/src/liteos/libc/config.rs +++ /dev/null @@ -1,16 +0,0 @@ -//The following content is automatically generated by the compiler. -//please do not modify it. -pub const LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT: usize = 2usize; -pub const LOSCFG_BASE_CORE_TSK_LIMIT: usize = 12usize; -pub const LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE: usize = 400usize; -pub const LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE: usize = 800usize; -pub const LOSCFG_BASE_CORE_TSK_SWTMR_STACK_SIZE: usize = 800usize; -pub const LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE: usize = 400usize; -pub const LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO: usize = 10usize; -pub const LOSCFG_BASE_CORE_TICK_PER_SECOND: usize = 1000usize; -pub const LOSCFG_PLATFORM_HWI_LIMIT: usize = 256usize; -pub const LOSCFG_HWI_PRIO_LIMIT: usize = 32usize; -pub const LOSCFG_BASE_CORE_SWTMR_LIMIT: usize = 16usize; -pub const LOSCFG_BASE_IPC_QUEUE_LIMIT: usize = 10usize; -pub const LOSCFG_BASE_IPC_MUX_LIMIT: usize = 20usize; -pub const LOSCFG_BASE_IPC_SEM_LIMIT: usize = 20usize; -- Gitee From 5ee9a68baeba1757cf655409c34ec93badeeab00 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 11:27:32 +0000 Subject: [PATCH 09/27] buildrs --- build.rs | 86 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/build.rs b/build.rs index 7430808..422732a 100644 --- a/build.rs +++ b/build.rs @@ -11,53 +11,53 @@ fn main() { // Decode liteos configuration information and automatically generate configuration files. if target_os { let pwd = env::var("PWD").unwrap(); - let pwd = PathBuf::from_str(&pwd).unwrap(); - let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); - let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); + println!("{}", pwd); + // let pwd = PathBuf::from_str(&pwd).unwrap(); + // let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); + // let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); - let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); - let los_path = pwd.join(&los_path); + // let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); + // let los_path = pwd.join(&los_path); - let fs = File::options() - .read(true) - .open(los_path.join(".config")) - .unwrap(); - let fs = BufReader::new(fs); - println!("{}",manifest_path.join("src/liteos/config.rs").to_str().unwrap()); - let mut fcfg = File::options() - .write(true) - .create(true) - .truncate(true) - .open(manifest_path.join("src/liteos/config.rs")) - .unwrap(); - let is_empty_line = Regex::new(r"^ *?#|^ *?$").unwrap(); - let kv = Regex::new(r#"^ *?(\w+) *?= *?(.*)$"#).unwrap(); + // let fs = File::options() + // .read(true) + // .open(los_path.join(".config")) + // .unwrap(); + // let fs = BufReader::new(fs); + // let mut fcfg = File::options() + // .write(true) + // .create(true) + // .truncate(true) + // .open(manifest_path.join("src/liteos/config.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() - }; + // unsafe { + // write!(&mut fcfg,"//The following content is automatically generated by the compiler.\n//please do not modify it.\n").unwrap_unchecked() + // }; - for line in fs.lines() { - if let Ok(s) = line { - if is_empty_line.is_match(&s) { - continue; - } - let mc = kv.captures(&s).unwrap(); - let key = mc.get(1).unwrap().as_str(); - let value = mc.get(2).unwrap().as_str(); - if value.parse::().is_ok() { - write!(&mut fcfg, "pub const {}: usize = {}usize;\n", key, value).unwrap(); - } else if value == "y" { - println!("cargo:rustc-cfg={}", key); - } else if value.len() > 0 { - println!("cargo:rustc_cfg='{}={}'", key, value); - } - } - } - println!( - "cargo:rerun-if-changed={}", - los_path.join(".config").to_str().unwrap() - ); + // for line in fs.lines() { + // if let Ok(s) = line { + // if is_empty_line.is_match(&s) { + // continue; + // } + // let mc = kv.captures(&s).unwrap(); + // let key = mc.get(1).unwrap().as_str(); + // let value = mc.get(2).unwrap().as_str(); + // if value.parse::().is_ok() { + // write!(&mut fcfg, "pub const {}: usize = {}usize;\n", key, value).unwrap(); + // } else if value == "y" { + // println!("cargo:rustc-cfg={}", key); + // } else if value.len() > 0 { + // println!("cargo:rustc_cfg='{}={}'", key, value); + // } + // } + // } + // println!( + // "cargo:rerun-if-changed={}", + // los_path.join(".config").to_str().unwrap() + // ); } println!("cargo:rerun-if-changed=build.rs"); } -- Gitee From fb3507e225b3f329497d907e8c1dd02cd425fa4b Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 11:30:58 +0000 Subject: [PATCH 10/27] buildrs --- build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 422732a..6986050 100644 --- a/build.rs +++ b/build.rs @@ -11,8 +11,9 @@ fn main() { // Decode liteos configuration information and automatically generate configuration files. if target_os { let pwd = env::var("PWD").unwrap(); - println!("{}", pwd); - // let pwd = PathBuf::from_str(&pwd).unwrap(); + let pwd = PathBuf::from_str(&pwd).unwrap(); + println!("{}", pwd.to_str().unwrap()); + // let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); // let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); -- Gitee From b461f9b36b455cf3a398ed5e02338e93edd405ff Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 11:34:20 +0000 Subject: [PATCH 11/27] build rs --- build.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.rs b/build.rs index 6986050..d3b3893 100644 --- a/build.rs +++ b/build.rs @@ -12,14 +12,13 @@ fn main() { if target_os { let pwd = env::var("PWD").unwrap(); let pwd = PathBuf::from_str(&pwd).unwrap(); - println!("{}", pwd.to_str().unwrap()); - // let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); - // let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); - - // let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); - // let los_path = pwd.join(&los_path); + let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); + let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); + let los_path = pwd.join(&los_path); + println!("{}", los_path.to_str().unwrap()); // let fs = File::options() // .read(true) // .open(los_path.join(".config")) -- Gitee From 6cd204af64ad4acb9744422893750325132f03d2 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 11:37:47 +0000 Subject: [PATCH 12/27] buildrs --- build.rs | 76 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/build.rs b/build.rs index d3b3893..b2c86a4 100644 --- a/build.rs +++ b/build.rs @@ -18,46 +18,46 @@ fn main() { let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); let los_path = pwd.join(&los_path); - println!("{}", los_path.to_str().unwrap()); - // let fs = File::options() - // .read(true) - // .open(los_path.join(".config")) - // .unwrap(); - // let fs = BufReader::new(fs); - // let mut fcfg = File::options() - // .write(true) - // .create(true) - // .truncate(true) - // .open(manifest_path.join("src/liteos/config.rs")) - // .unwrap(); - // let is_empty_line = Regex::new(r"^ *?#|^ *?$").unwrap(); - // let kv = Regex::new(r#"^ *?(\w+) *?= *?(.*)$"#).unwrap(); + + let fs = File::options() + .read(true) + .open(los_path.join(".config")) + .unwrap(); + let fs = BufReader::new(fs); + let mut fcfg = File::options() + .write(true) + .create(true) + .truncate(true) + .open(manifest_path.join("src/liteos/config.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() - // }; + unsafe { + write!(&mut fcfg,"//The following content is automatically generated by the compiler.\n//please do not modify it.\n").unwrap_unchecked() + }; - // for line in fs.lines() { - // if let Ok(s) = line { - // if is_empty_line.is_match(&s) { - // continue; - // } - // let mc = kv.captures(&s).unwrap(); - // let key = mc.get(1).unwrap().as_str(); - // let value = mc.get(2).unwrap().as_str(); - // if value.parse::().is_ok() { - // write!(&mut fcfg, "pub const {}: usize = {}usize;\n", key, value).unwrap(); - // } else if value == "y" { - // println!("cargo:rustc-cfg={}", key); - // } else if value.len() > 0 { - // println!("cargo:rustc_cfg='{}={}'", key, value); - // } - // } - // } - // println!( - // "cargo:rerun-if-changed={}", - // los_path.join(".config").to_str().unwrap() - // ); + for line in fs.lines() { + if let Ok(s) = line { + if is_empty_line.is_match(&s) { + continue; + } + let mc = kv.captures(&s).unwrap(); + let key = mc.get(1).unwrap().as_str(); + let value = mc.get(2).unwrap().as_str(); + if value.parse::().is_ok() { + write!(&mut fcfg, "pub const {}: usize = {}usize;\n", key, value).unwrap(); + } else if value == "y" { + println!("cargo:rustc-cfg={}", key); + } else if value.len() > 0 { + println!("cargo:rustc_cfg='{}={}'", key, value); + } + } + } + println!( + "cargo:rerun-if-changed={}", + los_path.join(".config").to_str().unwrap() + ); } println!("cargo:rerun-if-changed=build.rs"); } -- Gitee From 467cafaeaca8fc05bbe5eb659767b85aedd1865d Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 11:44:15 +0000 Subject: [PATCH 13/27] buildrs --- build.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/build.rs b/build.rs index b2c86a4..6ac6cbe 100644 --- a/build.rs +++ b/build.rs @@ -18,11 +18,13 @@ fn main() { let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); let los_path = pwd.join(&los_path); - - let fs = File::options() - .read(true) - .open(los_path.join(".config")) - .unwrap(); + + let fs = File::options().read(true).open(los_path.join(".config")); + let fs = if fs.is_ok() { + fs.unwrap() + } else { + return; + }; let fs = BufReader::new(fs); let mut fcfg = File::options() .write(true) -- Gitee From 2a98862fc37ae49366bc031443202f93d33f5acc Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 11:45:01 +0000 Subject: [PATCH 14/27] build --- build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build.rs b/build.rs index 6ac6cbe..31f8978 100644 --- a/build.rs +++ b/build.rs @@ -23,6 +23,7 @@ fn main() { let fs = if fs.is_ok() { fs.unwrap() } else { + println!("{}", los_path.join(".config").to_str().unwrap()); return; }; let fs = BufReader::new(fs); -- Gitee From 2c9cc15b8265a8b8eb844bc6642b2116e4378f1d Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 11:55:26 +0000 Subject: [PATCH 15/27] build --- build.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 31f8978..9ab1d3f 100644 --- a/build.rs +++ b/build.rs @@ -23,7 +23,13 @@ fn main() { let fs = if fs.is_ok() { fs.unwrap() } else { - println!("{}", los_path.join(".config").to_str().unwrap()); + println!( + "{}\n-------------------------------------------", + los_path.join(".config").to_str().unwrap() + ); + for i in env::vars() { + println!("{}={}", i.0, i.1); + } return; }; let fs = BufReader::new(fs); -- Gitee From 6fc1a70b62c7be138d6d8869620e8dd8ad7bc263 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 12:20:17 +0000 Subject: [PATCH 16/27] build --- build.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/build.rs b/build.rs index 9ab1d3f..be932b3 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,7 @@ use regex::Regex; use std::{ env, + ffi::OsStr, fs::File, io::{BufRead, BufReader, Write}, path::PathBuf, @@ -10,28 +11,27 @@ fn main() { let target_os = env::var("CARGO_CFG_LITEOS").is_ok(); // Decode liteos configuration information and automatically generate configuration files. if target_os { - let pwd = env::var("PWD").unwrap(); - let pwd = PathBuf::from_str(&pwd).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); + } let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); - let los_path = pwd.join(&los_path); + let los_path = top_path.join(&los_path); + + let fs = File::options() + .read(true) + .open(los_path.join(".config")) + .unwrap(); - let fs = File::options().read(true).open(los_path.join(".config")); - let fs = if fs.is_ok() { - fs.unwrap() - } else { - println!( - "{}\n-------------------------------------------", - los_path.join(".config").to_str().unwrap() - ); - for i in env::vars() { - println!("{}={}", i.0, i.1); - } - return; - }; let fs = BufReader::new(fs); let mut fcfg = File::options() .write(true) -- Gitee From 170f580a00ad1ac01f9d7d7109b16ee0ad9de4c7 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 12:24:28 +0000 Subject: [PATCH 17/27] buildrs --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index be932b3..097a014 100644 --- a/build.rs +++ b/build.rs @@ -25,7 +25,7 @@ fn main() { let manifest_path = PathBuf::from_str(&manifest_path).unwrap(); let los_path = env::var("CARGO_CFG_LOS_PATH").unwrap(); - let los_path = top_path.join(&los_path); + let los_path = top_path.join(&los_path).canonicalize().unwrap(); let fs = File::options() .read(true) -- Gitee From c76a86ee4acdf53808c7f391301b47c2251c5697 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 6 Jul 2022 12:32:41 +0000 Subject: [PATCH 18/27] build --- build.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.rs b/build.rs index 097a014..7ffd1bc 100644 --- a/build.rs +++ b/build.rs @@ -67,6 +67,10 @@ fn main() { "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() + ) } println!("cargo:rerun-if-changed=build.rs"); } -- Gitee From 65c90aa388c7d09c3dd8d07ad414e4c9e5dcdc3c Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 13 Jul 2022 07:30:14 +0000 Subject: [PATCH 19/27] liteos_park_mutex --- .cargo/config.toml | 2 +- Cargo.toml | 3 ++- examples/led.rs | 4 +--- src/lib.rs | 2 +- src/liteos/libc.rs | 45 ++++++++++++++++++++++++++++++++++-- src/liteos/locks/mod.rs | 4 ++++ src/liteos/locks/mutex.rs | 43 ++++++++++++++++++++++++++++++++++ src/liteos/locks/parker.rs | 47 ++++++++++++++++++++++++++++++++++++++ src/liteos/mod.rs | 1 + src/unix/locks/parker.rs | 42 +++++++++++++++++----------------- src/unix/thread.rs | 2 +- src/unix/thread/tests.rs | 18 +++++++++++++++ 12 files changed, 183 insertions(+), 30 deletions(-) create mode 100644 src/liteos/locks/mod.rs create mode 100644 src/liteos/locks/mutex.rs create mode 100644 src/liteos/locks/parker.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 553cec2..4dafbd9 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -56,7 +56,7 @@ rustflags = [ 'target_os="liteos_m"', # Specify LiteOS location "--cfg", - 'LOS_PATH="../../stm32/LiteOS"', + 'LOS_PATH="../../../c/LiteOS/"', ] [build] diff --git a/Cargo.toml b/Cargo.toml index 7d7c1df..ae153d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,8 @@ crate-type = ["rlib"] [dependencies] utils = { git = "https://gitee.com/iot-ua/utils.git", branch = "develop" } - cfg-if = "1.0.0" + [target.'cfg(unix)'.dependencies] libc = { version = "0.2.126", default-features = false } @@ -35,6 +35,7 @@ regex = "1.5.6" name = "app" crate-type = ["staticlib"] + [[example]] name = "led" crate-type = ["staticlib"] diff --git a/examples/led.rs b/examples/led.rs index 43af96f..302b693 100644 --- a/examples/led.rs +++ b/examples/led.rs @@ -2,9 +2,7 @@ #![feature(default_alloc_error_handler)] extern crate alloc; use alloc::boxed::Box; -use arch::{ - thread::{self, Thread}, -}; +use arch::thread::{self, Thread}; extern "C" { fn led_toggle(); diff --git a/src/lib.rs b/src/lib.rs index 1a9b19f..6d393ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,6 @@ cfg_if! { mod liteos; pub use liteos::os; pub use liteos::thread; + pub use liteos::locks; } } - diff --git a/src/liteos/libc.rs b/src/liteos/libc.rs index 935ba12..7a7840e 100644 --- a/src/liteos/libc.rs +++ b/src/liteos/libc.rs @@ -90,7 +90,8 @@ 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; @@ -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::config::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; + + #[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 0000000..1b8740e --- /dev/null +++ b/src/liteos/locks/mod.rs @@ -0,0 +1,4 @@ +mod mutex; +pub use mutex::*; +mod parker; +pub use parker::*; diff --git a/src/liteos/locks/mutex.rs b/src/liteos/locks/mutex.rs new file mode 100644 index 0000000..41fd21e --- /dev/null +++ b/src/liteos/locks/mutex.rs @@ -0,0 +1,43 @@ +use core::mem::MaybeUninit; + +use crate::liteos::libc::{ + mutex::{LOS_MuxCreate, LOS_MuxDelete, LOS_MuxPend, LOS_MuxPost, LOS_ERRNO_MUX_TIMEOUT}, + sys::{LOS_OK, LOS_WAIT_FOREVER}, +}; +pub type MovableMutex = Mutex; +pub struct Mutex(u32); + +impl Mutex { + #[inline] + pub fn new() -> Self { + unsafe { + let mut handle = MaybeUninit::uninit().assume_init(); + let rtn = LOS_MuxCreate(&mut handle); + debug_assert!(rtn == LOS_OK); + Self(handle) + } + } + #[inline] + pub unsafe fn init(&mut self) {} + #[inline] + pub unsafe fn destroy(&self) { + LOS_MuxDelete(self.0); + } + #[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); + } +} diff --git a/src/liteos/locks/parker.rs b/src/liteos/locks/parker.rs new file mode 100644 index 0000000..d3d34e8 --- /dev/null +++ b/src/liteos/locks/parker.rs @@ -0,0 +1,47 @@ +use alloc::boxed::Box; + +use crate::liteos::libc::event::{ + LOS_EventDestroy, LOS_EventInit, LOS_EventRead, LOS_EventWrite, EVENT_CB_S, LOS_WAITMODE_AND, + LOS_WAITMODE_CLR, +}; +use crate::liteos::libc::sys::{LOS_OK, LOS_WAIT_FOREVER}; + +use core::mem::MaybeUninit; +use core::pin::Pin; + +pub struct Parker { + event: Pin>, +} + +impl Parker { + pub fn new() -> Self { + unsafe { + let event: Pin> = Box::pin(MaybeUninit::uninit().assume_init()); + let rtn = LOS_EventInit(&*event.as_ref()); + debug_assert!(rtn == LOS_OK); + Self { event } + } + } + pub fn park(&self) { + let rtn = unsafe { + LOS_EventRead( + &*self.event.as_ref(), + 1, + LOS_WAITMODE_AND | LOS_WAITMODE_CLR, + LOS_WAIT_FOREVER, + ) + }; + debug_assert!(rtn == 1); + } + #[inline] + pub fn unpark(&self) { + let rtn = unsafe { LOS_EventWrite(&*self.event.as_ref(), 1) }; + debug_assert!(rtn == LOS_OK); + } +} +impl Drop for Parker { + fn drop(&mut self) { + let rtn = unsafe { LOS_EventDestroy(&*self.event.as_ref()) }; + debug_assert!(rtn == LOS_OK); + } +} diff --git a/src/liteos/mod.rs b/src/liteos/mod.rs index 5bc3e59..fa4300c 100644 --- a/src/liteos/mod.rs +++ b/src/liteos/mod.rs @@ -1,5 +1,6 @@ #[allow(unused, non_camel_case_types, non_snake_case)] mod libc; +pub mod locks; mod malloc; pub mod os; pub mod thread; diff --git a/src/unix/locks/parker.rs b/src/unix/locks/parker.rs index c8591ba..1373f32 100644 --- a/src/unix/locks/parker.rs +++ b/src/unix/locks/parker.rs @@ -14,7 +14,7 @@ pub struct Parker { impl Parker { #[inline] - pub const fn new() -> Self { + pub fn new() -> Self { Parker { state: AtomicU32::new(EMPTY), } @@ -44,26 +44,26 @@ impl Parker { } } - // 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. - if self.state.fetch_sub(1, Acquire) == NOTIFIED { - return; - } - // 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(). - } else { - // Timeout or spurious wake up. - // We return either way, because we can't easily tell if it was the - // timeout or not. - } - } + // // 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. + // if self.state.fetch_sub(1, Acquire) == NOTIFIED { + // return; + // } + // // 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(). + // } else { + // // Timeout or spurious wake up. + // // We return either way, because we can't easily tell if it was the + // // timeout or not. + // } + // } #[inline] pub fn unpark(&self) { diff --git a/src/unix/thread.rs b/src/unix/thread.rs index ff3dd23..bb909b2 100644 --- a/src/unix/thread.rs +++ b/src/unix/thread.rs @@ -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 b79413f..a02e422 100644 --- a/src/unix/thread/tests.rs +++ b/src/unix/thread/tests.rs @@ -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"); + } +} -- Gitee From fc2a00a13e0bb9068db661fea162605350f4bc4a Mon Sep 17 00:00:00 2001 From: shuaihu Date: Thu, 14 Jul 2022 08:06:34 +0000 Subject: [PATCH 20/27] Number_cpus --- Cargo.toml | 3 +-- build.rs | 48 +++++++++++++++++++++++++------------- cfgfile | 1 + examples/led.rs | 18 ++++++++++---- src/liteos/libc.rs | 3 +-- src/liteos/locks/parker.rs | 38 +++++++++++++++++++----------- src/liteos/mod.rs | 2 ++ src/liteos/os.rs | 5 ++++ src/unix/config.rs | 1 + src/unix/locks/parker.rs | 2 +- src/unix/mod.rs | 1 + src/unix/os.rs | 1 + 12 files changed, 84 insertions(+), 39 deletions(-) create mode 100644 cfgfile create mode 100644 src/unix/config.rs diff --git a/Cargo.toml b/Cargo.toml index ae153d1..9c4916e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,13 +29,12 @@ windows-sys = { version = "0.36.1", features = [ [build-dependencies] regex = "1.5.6" - +num_cpus="1.13.1" [[example]] name = "app" crate-type = ["staticlib"] - [[example]] name = "led" crate-type = ["staticlib"] diff --git a/build.rs b/build.rs index 2f88dcd..681b2f5 100644 --- a/build.rs +++ b/build.rs @@ -8,24 +8,26 @@ use std::{ 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); + } 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(); - 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().unwrap() + }; let fs = File::options() .read(true) @@ -39,12 +41,12 @@ fn main() { .truncate(true) .open(manifest_path.join("src/liteos/config.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_unchecked() }; for line in fs.lines() { @@ -72,6 +74,20 @@ fn main() { "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/{}/config.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, "pub const CPU_CORE_NUMBERS: usize = {}usize;", cpus).unwrap(); + // for i in env::vars() { + // println!("{}={}", i.0, i.1); + // } } println!("cargo:rerun-if-changed=build.rs"); } diff --git a/cfgfile b/cfgfile new file mode 100644 index 0000000..8e528ca --- /dev/null +++ b/cfgfile @@ -0,0 +1 @@ +const CPU_CORE_NUMBERS:usize = 12usize \ No newline at end of file diff --git a/examples/led.rs b/examples/led.rs index 302b693..075fe13 100644 --- a/examples/led.rs +++ b/examples/led.rs @@ -1,23 +1,31 @@ #![no_std] #![feature(default_alloc_error_handler)] extern crate alloc; -use alloc::boxed::Box; -use arch::thread::{self, Thread}; + +use alloc::{boxed::Box, sync::Arc}; +use arch::{locks::Parker, os::printf, thread::Thread}; extern "C" { fn led_toggle(); } + #[no_mangle] extern "C" fn app_init() { + let parker = Arc::new(Parker::new()); + let unparker = parker.clone(); let _ = unsafe { Thread::new( - 800, - Box::new(|| loop { + 1600, + Box::new(move || { + parker.park(); led_toggle(); - thread::Thread::sleep(1000); + unsafe { printf("from thread!\n\0".as_ptr().cast()) }; }), ) }; + Thread::sleep(1000); + unparker.unpark(); + unsafe { printf("from init!\n\0".as_ptr().cast()) }; } #[cfg(not(test))] diff --git a/src/liteos/libc.rs b/src/liteos/libc.rs index 7a7840e..a5cf559 100644 --- a/src/liteos/libc.rs +++ b/src/liteos/libc.rs @@ -1,5 +1,4 @@ -#[path = "./config.rs"] -mod config; +use super:: config; pub type size_t = usize; pub mod heap { #[repr(C)] diff --git a/src/liteos/locks/parker.rs b/src/liteos/locks/parker.rs index d3d34e8..445f00d 100644 --- a/src/liteos/locks/parker.rs +++ b/src/liteos/locks/parker.rs @@ -1,31 +1,42 @@ -use alloc::boxed::Box; - use crate::liteos::libc::event::{ LOS_EventDestroy, LOS_EventInit, LOS_EventRead, LOS_EventWrite, EVENT_CB_S, LOS_WAITMODE_AND, LOS_WAITMODE_CLR, }; use crate::liteos::libc::sys::{LOS_OK, LOS_WAIT_FOREVER}; +use alloc::boxed::Box; +use utils::{ILazyObj, LazyObj}; +use core::intrinsics::transmute; use core::mem::MaybeUninit; -use core::pin::Pin; +pub type StaticParker = LazyObj; + +impl ILazyObj for Parker { + fn init() -> usize { + let pk = Parker::new(); + unsafe { transmute(pk) } + } + fn destory(v: usize) { + unsafe{crate::os::printf("d1\n\0".as_ptr().cast())}; + let _pk: Parker = unsafe { transmute(v) }; + } +} pub struct Parker { - event: Pin>, + event: Box, } - impl Parker { pub fn new() -> Self { unsafe { - let event: Pin> = Box::pin(MaybeUninit::uninit().assume_init()); - let rtn = LOS_EventInit(&*event.as_ref()); + let ev: Box = Box::new(MaybeUninit::uninit().assume_init()); + let rtn = LOS_EventInit(ev.as_ref()); debug_assert!(rtn == LOS_OK); - Self { event } + Self { event: ev } } } pub fn park(&self) { let rtn = unsafe { LOS_EventRead( - &*self.event.as_ref(), + &*self.event, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER, @@ -33,15 +44,16 @@ impl Parker { }; debug_assert!(rtn == 1); } - #[inline] pub fn unpark(&self) { - let rtn = unsafe { LOS_EventWrite(&*self.event.as_ref(), 1) }; + let rtn = unsafe { LOS_EventWrite(&*self.event, 1) }; debug_assert!(rtn == LOS_OK); } } impl Drop for Parker { fn drop(&mut self) { - let rtn = unsafe { LOS_EventDestroy(&*self.event.as_ref()) }; - debug_assert!(rtn == LOS_OK); + unsafe { + let rtn = LOS_EventDestroy(self.event.as_ref()); + debug_assert!(rtn == LOS_OK); + } } } diff --git a/src/liteos/mod.rs b/src/liteos/mod.rs index fa4300c..b19f34b 100644 --- a/src/liteos/mod.rs +++ b/src/liteos/mod.rs @@ -4,3 +4,5 @@ pub mod locks; mod malloc; pub mod os; pub mod thread; +#[allow(unused)] +mod config; \ No newline at end of file diff --git a/src/liteos/os.rs b/src/liteos/os.rs index 51b1f87..67255f7 100644 --- a/src/liteos/os.rs +++ b/src/liteos/os.rs @@ -26,6 +26,11 @@ pub(crate) fn page_size() -> usize { pub(crate) fn get_tick_count() -> u32 { 222 } +#[cfg(LOSCFG_KERNEL_SMP)] +pub const CPU_CORE_NUMBERS: usize = super::config::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/config.rs b/src/unix/config.rs new file mode 100644 index 0000000..0e5c2ba --- /dev/null +++ b/src/unix/config.rs @@ -0,0 +1 @@ +pub const CPU_CORE_NUMBERS: usize = 12usize; \ No newline at end of file diff --git a/src/unix/locks/parker.rs b/src/unix/locks/parker.rs index 1373f32..195cb85 100644 --- a/src/unix/locks/parker.rs +++ b/src/unix/locks/parker.rs @@ -14,7 +14,7 @@ pub struct Parker { impl Parker { #[inline] - pub fn new() -> Self { + pub const fn new() -> Self { Parker { state: AtomicU32::new(EMPTY), } diff --git a/src/unix/mod.rs b/src/unix/mod.rs index 94115de..601aa73 100644 --- a/src/unix/mod.rs +++ b/src/unix/mod.rs @@ -3,3 +3,4 @@ mod malloc; pub mod os; pub mod thread; mod utils; +mod config; \ No newline at end of file diff --git a/src/unix/os.rs b/src/unix/os.rs index df5e650..287e733 100644 --- a/src/unix/os.rs +++ b/src/unix/os.rs @@ -1,5 +1,6 @@ #[cfg(test)] mod tests; +pub use super::config::CPU_CORE_NUMBERS; use super::utils::dlsym; use super::utils::TimeSpec; use alloc::string::String; -- Gitee From de95d577d8a53f4d27713fc2f85a63ce02620b03 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Fri, 15 Jul 2022 03:48:34 +0000 Subject: [PATCH 21/27] static parker --- .vscode/settings.json | 4 +++- Cargo.toml | 2 +- examples/led.rs | 14 ++++++-------- src/common/instant.rs | 2 +- src/liteos/locks/mutex.rs | 4 +++- src/liteos/locks/parker.rs | 3 ++- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 513cbeb..a71b1f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "rust-analyzer.checkOnSave.allTargets": false + "lldb.displayFormat": "auto", + "lldb.dereferencePointers": true, + "lldb.consoleMode": "commands", } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 9c4916e..229e8f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ name = "led" crate-type = ["staticlib"] [profile.release] -opt-level = 3 +opt-level = 2 debug = true debug-assertions = false overflow-checks = false diff --git a/examples/led.rs b/examples/led.rs index 075fe13..0779b27 100644 --- a/examples/led.rs +++ b/examples/led.rs @@ -2,29 +2,27 @@ #![feature(default_alloc_error_handler)] extern crate alloc; -use alloc::{boxed::Box, sync::Arc}; -use arch::{locks::Parker, os::printf, thread::Thread}; +use alloc::boxed::Box; +use arch::{locks::StaticParker, os::printf, thread::Thread}; extern "C" { fn led_toggle(); } - +static mut PARKER: StaticParker = StaticParker::new(); #[no_mangle] extern "C" fn app_init() { - let parker = Arc::new(Parker::new()); - let unparker = parker.clone(); let _ = unsafe { Thread::new( 1600, Box::new(move || { - parker.park(); + PARKER.park(); led_toggle(); - unsafe { printf("from thread!\n\0".as_ptr().cast()) }; + printf("from thread!\n\0".as_ptr().cast()); }), ) }; Thread::sleep(1000); - unparker.unpark(); + unsafe{PARKER.unpark()}; unsafe { printf("from init!\n\0".as_ptr().cast()) }; } diff --git a/src/common/instant.rs b/src/common/instant.rs index 35a4a7d..ec27c54 100644 --- a/src/common/instant.rs +++ b/src/common/instant.rs @@ -1,4 +1,4 @@ -#[cfg(test)] +#[cfg(all(test, not(liteos)))] mod tests; use core::ops::{Deref, DerefMut}; diff --git a/src/liteos/locks/mutex.rs b/src/liteos/locks/mutex.rs index 41fd21e..d668395 100644 --- a/src/liteos/locks/mutex.rs +++ b/src/liteos/locks/mutex.rs @@ -1,10 +1,12 @@ use core::mem::MaybeUninit; +use utils::LazyObj; + use crate::liteos::libc::{ mutex::{LOS_MuxCreate, LOS_MuxDelete, LOS_MuxPend, LOS_MuxPost, LOS_ERRNO_MUX_TIMEOUT}, sys::{LOS_OK, LOS_WAIT_FOREVER}, }; -pub type MovableMutex = Mutex; +pub type MovableMutex = LazyObj; pub struct Mutex(u32); impl Mutex { diff --git a/src/liteos/locks/parker.rs b/src/liteos/locks/parker.rs index 445f00d..920393d 100644 --- a/src/liteos/locks/parker.rs +++ b/src/liteos/locks/parker.rs @@ -12,12 +12,13 @@ use core::mem::MaybeUninit; pub type StaticParker = LazyObj; impl ILazyObj for Parker { + #[inline] fn init() -> usize { let pk = Parker::new(); unsafe { transmute(pk) } } + #[inline] fn destory(v: usize) { - unsafe{crate::os::printf("d1\n\0".as_ptr().cast())}; let _pk: Parker = unsafe { transmute(v) }; } } -- Gitee From 41f24c7bdc8ecc3167f36beb5fac6d5abe874090 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Fri, 22 Jul 2022 09:09:27 +0000 Subject: [PATCH 22/27] parking LazyObj --- .cargo/config.toml | 16 +--- .gitignore | 3 +- .vscode/settings.json | 3 + Cargo.toml | 30 +++--- build.rs | 42 +++++--- cfgfile | 1 - examples/app.rs | 26 ----- examples/led.rs | 33 ------- examples/liteos/lazyobj_test.rs | 141 +++++++++++++++++++++++++++ examples/liteos/mod.rs | 2 + examples/test_liteos.rs | 47 +++++++++ src/common/instant.rs | 4 +- src/common/lazyobj.rs | 149 +++++++++++++++++++++++++++++ src/common/lazyobj/tests.rs | 27 ++++++ src/common/mod.rs | 4 + src/lib.rs | 16 +++- src/liteos/libc.rs | 11 ++- src/liteos/locks/mod.rs | 3 +- src/liteos/locks/mutex.rs | 36 +++---- src/liteos/locks/parker.rs | 164 +++++++++++++++++++++++++------- src/liteos/mod.rs | 5 +- src/liteos/os.rs | 15 ++- src/unix/config.rs | 1 - src/unix/locks/mod.rs | 3 +- src/unix/locks/parker.rs | 157 +++++++++++++++++++----------- src/unix/locks/parker/tests.rs | 8 +- src/unix/mod.rs | 2 +- src/unix/os.rs | 8 +- src/unix/thread.rs | 2 +- src/unix/thread/tests.rs | 8 +- 30 files changed, 726 insertions(+), 241 deletions(-) delete mode 100644 cfgfile delete mode 100644 examples/app.rs delete mode 100644 examples/led.rs create mode 100644 examples/liteos/lazyobj_test.rs create mode 100644 examples/liteos/mod.rs create mode 100644 examples/test_liteos.rs create mode 100644 src/common/lazyobj.rs create mode 100644 src/common/lazyobj/tests.rs delete mode 100644 src/unix/config.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 4dafbd9..b973bcd 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 @@ -59,6 +51,6 @@ rustflags = [ '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 502d4f0..d1a77b6 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 a71b1f5..9939e92 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,8 @@ { + "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 229e8f4..f436996 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" -num_cpus="1.13.1" - -[[example]] -name = "app" -crate-type = ["staticlib"] - [[example]] -name = "led" +name = "test_liteos" crate-type = ["staticlib"] +required-features = ["liteos"] [profile.release] -opt-level = 2 +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 681b2f5..a8f773b 100644 --- a/build.rs +++ b/build.rs @@ -3,13 +3,15 @@ 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(); @@ -19,14 +21,26 @@ fn main() { } 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 { + //获取LiteOS所在位置,详细参见编译配置文件 ".cargo/config.toml" 中的编译选项: "--cfg", 'LOS_PATH="../../../c/LiteOS/"'。 let los_path = env::var("CARGO_CFG_LOS_PATH").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().unwrap() + 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() @@ -39,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!(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 { @@ -66,17 +78,15 @@ 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/{}/config.rs", system); + let cfgfile = format!("src/{}/sysinfo.rs", system); let mut fcfg = File::options() .write(true) .create(true) @@ -84,10 +94,14 @@ fn main() { .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(); - // for i in env::vars() { - // println!("{}={}", i.0, i.1); - // } } println!("cargo:rerun-if-changed=build.rs"); + println!( + "cargo:rerun-if-changed={}", + top_path.join(".cargo/config.toml").to_str().unwrap() + ); } diff --git a/cfgfile b/cfgfile deleted file mode 100644 index 8e528ca..0000000 --- a/cfgfile +++ /dev/null @@ -1 +0,0 @@ -const CPU_CORE_NUMBERS:usize = 12usize \ No newline at end of file diff --git a/examples/app.rs b/examples/app.rs deleted file mode 100644 index 695e210..0000000 --- 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 0779b27..0000000 --- a/examples/led.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![no_std] -#![feature(default_alloc_error_handler)] -extern crate alloc; - -use alloc::boxed::Box; -use arch::{locks::StaticParker, os::printf, thread::Thread}; - -extern "C" { - fn led_toggle(); -} -static mut PARKER: StaticParker = StaticParker::new(); -#[no_mangle] -extern "C" fn app_init() { - let _ = unsafe { - Thread::new( - 1600, - Box::new(move || { - PARKER.park(); - led_toggle(); - printf("from thread!\n\0".as_ptr().cast()); - }), - ) - }; - Thread::sleep(1000); - unsafe{PARKER.unpark()}; - unsafe { printf("from init!\n\0".as_ptr().cast()) }; -} - -#[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 0000000..73087c7 --- /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 0000000..21c9e9d --- /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 0000000..8d51fc9 --- /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 ec27c54..057dbbd 100644 --- a/src/common/instant.rs +++ b/src/common/instant.rs @@ -3,14 +3,14 @@ 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 0000000..23e6a56 --- /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 0000000..64eedfa --- /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 ea7508d..59dfc2b 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 6d393ae..3cc5f3b 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::thread; pub use liteos::locks; + pub use liteos::thread; } } diff --git a/src/liteos/libc.rs b/src/liteos/libc.rs index a5cf559..db52e60 100644 --- a/src/liteos/libc.rs +++ b/src/liteos/libc.rs @@ -1,4 +1,4 @@ -use super:: config; +use super::sysinfo::*; pub type size_t = usize; pub mod heap { #[repr(C)] @@ -96,6 +96,7 @@ pub mod sys { 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], @@ -135,7 +136,7 @@ pub mod timer { } } pub mod task { - use super::config::LOSCFG_BASE_CORE_TSK_LIMIT; + 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; @@ -162,7 +163,7 @@ 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, diff --git a/src/liteos/locks/mod.rs b/src/liteos/locks/mod.rs index 1b8740e..aad438c 100644 --- a/src/liteos/locks/mod.rs +++ b/src/liteos/locks/mod.rs @@ -1,4 +1,3 @@ mod mutex; pub use mutex::*; -mod parker; -pub use parker::*; +pub mod parker; diff --git a/src/liteos/locks/mutex.rs b/src/liteos/locks/mutex.rs index d668395..e9fc1eb 100644 --- a/src/liteos/locks/mutex.rs +++ b/src/liteos/locks/mutex.rs @@ -1,29 +1,27 @@ -use core::mem::MaybeUninit; - -use utils::LazyObj; - +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}, }; -pub type MovableMutex = LazyObj; +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 fn new() -> Self { - unsafe { - let mut handle = MaybeUninit::uninit().assume_init(); - let rtn = LOS_MuxCreate(&mut handle); - debug_assert!(rtn == LOS_OK); - Self(handle) - } + pub const fn new() -> Self { + Mutex(u32::MAX) } #[inline] - pub unsafe fn init(&mut self) {} - #[inline] - pub unsafe fn destroy(&self) { - LOS_MuxDelete(self.0); + 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 { @@ -43,3 +41,9 @@ impl Mutex { 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 index 920393d..c5c933c 100644 --- a/src/liteos/locks/parker.rs +++ b/src/liteos/locks/parker.rs @@ -1,60 +1,156 @@ use crate::liteos::libc::event::{ - LOS_EventDestroy, LOS_EventInit, LOS_EventRead, LOS_EventWrite, EVENT_CB_S, LOS_WAITMODE_AND, - LOS_WAITMODE_CLR, + 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 utils::{ILazyObj, LazyObj}; -use core::intrinsics::transmute; 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; -pub type StaticParker = LazyObj; - -impl ILazyObj for Parker { +struct Inner { + cnt: AtomicU32, + flag: AtomicU32, + evb: EVENT_CB_S, +} +impl Inner { #[inline] - fn init() -> usize { - let pk = Parker::new(); - unsafe { transmute(pk) } + const unsafe fn new() -> Self { + Self { + cnt: AtomicU32::new(1), + flag: AtomicU32::new(EMPTY), + evb: MaybeUninit::uninit().assume_init(), + } } #[inline] - fn destory(v: usize) { - let _pk: Parker = unsafe { transmute(v) }; + 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 { - event: Box, + unparker: Unparker, } +unsafe impl Send for Parker {} +unsafe impl Sync for Parker {} impl Parker { pub fn new() -> Self { - unsafe { - let ev: Box = Box::new(MaybeUninit::uninit().assume_init()); - let rtn = LOS_EventInit(ev.as_ref()); - debug_assert!(rtn == LOS_OK); - Self { event: ev } + Parker { + unparker: Unparker::new(), } } pub fn park(&self) { - let rtn = unsafe { - LOS_EventRead( - &*self.event, - 1, - LOS_WAITMODE_AND | LOS_WAITMODE_CLR, - LOS_WAIT_FOREVER, - ) - }; - debug_assert!(rtn == 1); + self.unparker.park() } - pub fn unpark(&self) { - let rtn = unsafe { LOS_EventWrite(&*self.event, 1) }; - debug_assert!(rtn == LOS_OK); + 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() } } -impl Drop for Parker { +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) { - unsafe { - let rtn = LOS_EventDestroy(self.event.as_ref()); - debug_assert!(rtn == LOS_OK); + 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 b19f34b..1f76668 100644 --- a/src/liteos/mod.rs +++ b/src/liteos/mod.rs @@ -3,6 +3,7 @@ mod libc; pub mod locks; mod malloc; pub mod os; +#[allow(unused, non_camel_case_types, non_snake_case)] +mod sysinfo; + pub mod thread; -#[allow(unused)] -mod config; \ No newline at end of file diff --git a/src/liteos/os.rs b/src/liteos/os.rs index 67255f7..8da1742 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,17 +20,19 @@ 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::config::LOSCFG_KERNEL_SMP_CORE_NUM; +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; diff --git a/src/unix/config.rs b/src/unix/config.rs deleted file mode 100644 index 0e5c2ba..0000000 --- a/src/unix/config.rs +++ /dev/null @@ -1 +0,0 @@ -pub const CPU_CORE_NUMBERS: usize = 12usize; \ No newline at end of file diff --git a/src/unix/locks/mod.rs b/src/unix/locks/mod.rs index 858918a..8c4a021 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 195cb85..6110f4f 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 { +pub 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), } } + fn park(&self) { + if self.state.fetch_sub(1, Acquire) != NOTIFIED { + futex_wait(&self.state, PARKED, u32::MAX); + 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(&self) { - // 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; } - loop { - // Wait for something to happen, assuming it's still set to PARKED. - 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. - } + futex_wait(&self.state, PARKED, timeout); + if self.state.swap(EMPTY, Acquire) == NOTIFIED { + true + } else { + false } } - // // 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. - // if self.state.fetch_sub(1, Acquire) == NOTIFIED { - // return; - // } - // // 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(). - // } else { - // // Timeout or spurious wake up. - // // We return either way, because we can't easily tell if it was the - // // timeout or not. - // } - // } + #[inline] + 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 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); + 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 156dcbc..24e6057 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 601aa73..9660822 100644 --- a/src/unix/mod.rs +++ b/src/unix/mod.rs @@ -1,6 +1,6 @@ pub mod locks; mod malloc; pub mod os; +mod sysinfo; pub mod thread; mod utils; -mod config; \ No newline at end of file diff --git a/src/unix/os.rs b/src/unix/os.rs index 287e733..eb6592c 100644 --- a/src/unix/os.rs +++ b/src/unix/os.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests; -pub use super::config::CPU_CORE_NUMBERS; +pub use super::sysinfo::CPU_CORE_NUMBERS; use super::utils::dlsym; use super::utils::TimeSpec; use alloc::string::String; @@ -30,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 bb909b2..1d28d42 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}, diff --git a/src/unix/thread/tests.rs b/src/unix/thread/tests.rs index a02e422..2601567 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; @@ -53,17 +53,17 @@ fn test_sleep() { fn test_thread_name() { use super::Thread; unsafe { - static mut test: [u8; 16] = [0u8; 16]; + 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; + TEST = name; assert_eq!(1, 1); }) .unwrap(); abc.join(); - assert_eq!(&test, b"0123456789abcde\0"); + assert_eq!(&TEST, b"0123456789abcde\0"); } } -- Gitee From 36031c87e52d7f2d6a22e47e53c2a35731d55947 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Fri, 22 Jul 2022 10:02:30 +0000 Subject: [PATCH 23/27] Parker inner pub bug fix --- src/unix/locks/parker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/locks/parker.rs b/src/unix/locks/parker.rs index 6110f4f..a6a63cb 100644 --- a/src/unix/locks/parker.rs +++ b/src/unix/locks/parker.rs @@ -11,7 +11,7 @@ const PARKED: u32 = u32::MAX; const EMPTY: u32 = 0; const NOTIFIED: u32 = 1; -pub struct Inner { +struct Inner { cnt: AtomicU32, state: AtomicU32, } -- Gitee From 12cb89c35d49db045aa7fa6b5325338d7934b560 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Thu, 28 Jul 2022 02:48:56 +0000 Subject: [PATCH 24/27] =?UTF-8?q?=E5=8E=BB=E9=99=A4mem-copy=E7=89=B9?= =?UTF-8?q?=E5=BE=81=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 14 ++- examples/liteos/lazyobj_test.rs | 10 +-- examples/liteos/mod.rs | 6 ++ examples/liteos/os.rs | 9 ++ examples/liteos/parker.rs | 29 +++++++ examples/liteos/rwlock_test.rs | 10 +++ examples/test_liteos.rs | 18 +++- src/common/lazyobj.rs | 17 ++-- src/lib.rs | 1 - src/liteos/locks/mod.rs | 2 + src/liteos/locks/parker.rs | 2 +- src/liteos/locks/rwlock.rs | 149 ++++++++++++++++++++++++++++++++ src/liteos/os.rs | 59 ++++++++++++- src/unix/locks/futex_rwlock.rs | 12 ++- 14 files changed, 307 insertions(+), 31 deletions(-) create mode 100644 examples/liteos/os.rs create mode 100644 examples/liteos/parker.rs create mode 100644 examples/liteos/rwlock_test.rs create mode 100644 src/liteos/locks/rwlock.rs diff --git a/Cargo.toml b/Cargo.toml index f436996..a0f01d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ liteos = [] [dependencies] utils = { git = "https://gitee.com/iot-ua/utils.git", branch = "develop" } +# utils = { path = "../utils" } cfg-if = "1.0.0" [build-dependencies] @@ -42,10 +43,21 @@ required-features = ["liteos"] [profile.release] opt-level = 3 +debug = false +rpath = false +lto = false +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = false + +[profile.dev] +opt-level = "z" debug = true rpath = false lto = true -debug-assertions = false +debug-assertions = true codegen-units = 1 panic = 'abort' incremental = false diff --git a/examples/liteos/lazyobj_test.rs b/examples/liteos/lazyobj_test.rs index 73087c7..bace800 100644 --- a/examples/liteos/lazyobj_test.rs +++ b/examples/liteos/lazyobj_test.rs @@ -1,6 +1,5 @@ -use arch::instant::Instant; +use arch::lazy::*; use arch::os::printf; -use arch::{lazy::*, thread}; use core::mem::MaybeUninit; struct TestStruct { @@ -132,10 +131,3 @@ pub fn lazyobj_test6() { 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 index 21c9e9d..d7a169a 100644 --- a/examples/liteos/mod.rs +++ b/examples/liteos/mod.rs @@ -1,2 +1,8 @@ mod lazyobj_test; pub use lazyobj_test::*; +mod rwlock_test; +pub use rwlock_test::*; +mod os; +pub use os::*; +mod parker; +pub use parker::*; diff --git a/examples/liteos/os.rs b/examples/liteos/os.rs new file mode 100644 index 0000000..ba5bef2 --- /dev/null +++ b/examples/liteos/os.rs @@ -0,0 +1,9 @@ +use arch::instant::Instant; +use arch::os::printf; +use arch::thread; +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/parker.rs b/examples/liteos/parker.rs new file mode 100644 index 0000000..f7f7901 --- /dev/null +++ b/examples/liteos/parker.rs @@ -0,0 +1,29 @@ +use alloc::boxed::Box; +use arch::{locks::parker::*, thread}; + +use crate::led_toggle; + +pub fn parker_led() { + let (p, u) = pair(); + unsafe { + thread::Thread::new( + 400, + Box::new(move || { + for _ in 0..2 { + p.park(); + led_toggle(); + } + }), + ) + .unwrap_unchecked(); + }; + + for _ in 0..2 { + thread::Thread::sleep(1000); + u.unpark(); + } +} + +pub fn los_event_check() { + unsafe { arch::os::los_event_check() }; +} diff --git a/examples/liteos/rwlock_test.rs b/examples/liteos/rwlock_test.rs new file mode 100644 index 0000000..f387d7f --- /dev/null +++ b/examples/liteos/rwlock_test.rs @@ -0,0 +1,10 @@ +use arch::locks::MovableRwLock; +pub fn rwlock_smoke() { + let l = MovableRwLock::new(); + l.read(); + l.read(); + // drop(l.read().unwrap()); + // drop(l.write().unwrap()); + // drop((l.read().unwrap(), l.read().unwrap())); + // drop(l.write().unwrap()); +} diff --git a/examples/test_liteos.rs b/examples/test_liteos.rs index 8d51fc9..cd7bf83 100644 --- a/examples/test_liteos.rs +++ b/examples/test_liteos.rs @@ -3,7 +3,12 @@ #![feature(panic_info_message)] #![feature(bench_black_box)] -use alloc::string::ToString; +use core::alloc::Layout; + +use alloc::{ + alloc::{alloc, dealloc}, + string::ToString, +}; use arch::os::printf; #[allow(unused_imports)] @@ -11,8 +16,8 @@ use arch::os::printf; extern crate alloc; #[allow(unused)] extern "C" { - fn led_toggle(); - fn DemoEntry(); + pub fn led_toggle(); + pub fn DemoEntry(); } // #[cfg(not(test))] @@ -31,7 +36,6 @@ unsafe extern "C" fn app_init() { 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()); @@ -44,4 +48,10 @@ unsafe extern "C" fn app_init() { lazyobj_test6(); printf("getTickCount Test\n\0".as_ptr()); get_tickcount_test(); + printf("RWLock smolk Test\n\0".as_ptr()); + rwlock_smoke(); + printf("parker led Test\n\0".as_ptr()); + parker_led(); + printf("LOS Event Check\n\0".as_ptr()); + los_event_check() } diff --git a/src/common/lazyobj.rs b/src/common/lazyobj.rs index 23e6a56..086803c 100644 --- a/src/common/lazyobj.rs +++ b/src/common/lazyobj.rs @@ -37,15 +37,14 @@ impl LazyObj { } #[inline] fn get_pointer(&self) -> *mut T { - let mut state = self.value.load(Acquire); + let mut state = self.value.load(Relaxed); 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) }); + initialize_nobox(&self.value, state, unsafe { transmute(T::init as *mut u8) }); } } if ISBOX { @@ -87,7 +86,7 @@ fn initialize_box(ptr: &AtomicUsize, mut state: usize, ly: Layout, init: fn(*mut } #[cold] //放置到全局的目的是禁止泛化,造成的代码膨胀。 -fn initialize_nobox(ptr: &AtomicUsize, mut status: usize, init: fn(*mut ())) -> usize { +fn initialize_nobox(ptr: &AtomicUsize, mut status: usize, init: fn(*mut ())) { loop { match status { EMPTY => { @@ -98,16 +97,15 @@ fn initialize_nobox(ptr: &AtomicUsize, mut status: usize, init: fn(*mut ())) -> } unsafe { init(transmute(&status)) }; ptr.swap(status, Release); - return ptr.as_mut_ptr().addr(); } - s if s < RUNING => return status, + s if s < RUNING => return, _ => { + debug_assert!(status == RUNING); if CPU_CORE_NUMBERS > 1 { core::hint::spin_loop(); } else { thread::Thread::yield_now(); } - debug_assert!(status == RUNING); status = ptr.load(Acquire); continue; } @@ -137,9 +135,8 @@ impl Drop for LazyObj { if t < RUNING { if ISBOX { let t: *mut T = transmute(t); - t.read(); - let ly = Layout::new::(); - dealloc(t.cast(), ly); + t.drop_in_place(); + dealloc(t.cast(), Self::LY); } else { drop::(transmute_copy(&t)); } diff --git a/src/lib.rs b/src/lib.rs index 3cc5f3b..62a814d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ #![feature(atomic_mut_ptr)] #![feature(negative_impls)] #![feature(const_mut_refs)] -#![feature(mem_copy_fn)] #![feature(bench_black_box)] #[allow(unused_imports)] diff --git a/src/liteos/locks/mod.rs b/src/liteos/locks/mod.rs index aad438c..34a4ef2 100644 --- a/src/liteos/locks/mod.rs +++ b/src/liteos/locks/mod.rs @@ -1,3 +1,5 @@ mod mutex; pub use mutex::*; pub mod parker; +mod rwlock; +pub use rwlock::*; diff --git a/src/liteos/locks/parker.rs b/src/liteos/locks/parker.rs index c5c933c..fac29e0 100644 --- a/src/liteos/locks/parker.rs +++ b/src/liteos/locks/parker.rs @@ -45,7 +45,7 @@ impl Inner { LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER, ); - debug_assert!(rtn == 1 || rtn == LOS_ERRNO_EVENT_READ_TIMEOUT); + debug_assert!(rtn == 1); self.flag.swap(EMPTY, Relaxed); } unsafe fn park_timeout(&self, timeout: u32) -> bool { diff --git a/src/liteos/locks/rwlock.rs b/src/liteos/locks/rwlock.rs new file mode 100644 index 0000000..80a4d8d --- /dev/null +++ b/src/liteos/locks/rwlock.rs @@ -0,0 +1,149 @@ +use core::{ + mem::MaybeUninit, + sync::atomic::AtomicU32, + sync::atomic::Ordering::{Acquire, Relaxed, Release}, +}; + +use crate::{ + lazy::{LazyObj, LazyObjInit}, + liteos::libc::{ + event::{LOS_EventDestroy, LOS_EventInit, LOS_EventRead, EVENT_CB_S, LOS_WAITMODE_AND}, + sys::{LOS_OK, LOS_WAIT_FOREVER}, + }, + os::CPU_CORE_NUMBERS, + thread::Thread, +}; + +const READ_LOCKED: u32 = 1; +const MASK: u32 = (1 << 30) - 1; +const WRITE_LOCKED: u32 = MASK; +const MAX_READERS: u32 = MASK - 1; +const READERS_WAITING: u32 = 1 << 30; +const WRITERS_WAITING: u32 = 1 << 31; + +fn is_unlocked(state: u32) -> bool { + state & MASK == 0 +} + +fn is_write_locked(state: u32) -> bool { + state & MASK == WRITE_LOCKED +} + +fn has_readers_waiting(state: u32) -> bool { + state & READERS_WAITING != 0 +} + +fn has_writers_waiting(state: u32) -> bool { + state & WRITERS_WAITING != 0 +} +fn is_read_lockable(state: u32) -> bool { + state & !MASK == 0 && state & MASK < MAX_READERS +} +fn has_reached_max_readers(state: u32) -> bool { + state & MASK == MAX_READERS +} +pub struct RwLock { + state: AtomicU32, + event: EVENT_CB_S, +} +pub type MovableRwLock = LazyObj; +impl LazyObjInit for RwLock { + fn init(v: &mut MaybeUninit) { + let v = v.write(RwLock::new()); + v.init(); + } +} +impl RwLock { + #[inline] + pub const fn new() -> Self { + Self { + state: AtomicU32::new(0), + event: unsafe { MaybeUninit::uninit().assume_init() }, + } + } + fn init(&self) { + let rtn = unsafe { LOS_EventInit(&self.event) }; + debug_assert!(rtn == LOS_OK); + } + pub fn try_read(&self) -> bool { + self.state + .fetch_update(Acquire, Relaxed, |s| { + is_read_lockable(s).then(|| s + READ_LOCKED) + }) + .is_ok() + } + #[cold] + pub fn read(&self) { + let state = self.state.load(Relaxed); + if !is_read_lockable(state) + || self + .state + .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) + .is_err() + { + self.read_contended(); + } + } + #[cold] + fn read_contended(&self) { + let mut state = self.spin_read(); + loop { + if is_read_lockable(state) { + match self + .state + .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) + { + Ok(_) => return, + Err(s) => { + state = s; + continue; + } + } + } + + // Check for overflow. + if has_reached_max_readers(state) { + panic!("too many active read locks on RwLock"); + } + if !has_readers_waiting(state) { + if let Err(s) = + self.state + .compare_exchange(state, state | READERS_WAITING, Relaxed, Relaxed) + { + state = s; + continue; + } + } + let rtn = unsafe { LOS_EventRead(&self.event, 1, LOS_WAITMODE_AND, LOS_WAIT_FOREVER) }; + debug_assert!(rtn == 1); + state = self.spin_read(); + } + } + fn spin_until(&self, f: impl Fn(u32) -> bool) -> u32 { + let mut spin = 100; // Chosen by fair dice roll. + loop { + let state = self.state.load(Relaxed); + if f(state) || spin == 0 { + return state; + } + if CPU_CORE_NUMBERS > 1 { + core::hint::spin_loop(); + } else { + Thread::yield_now(); + } + spin -= 1; + } + } + fn spin_read(&self) -> u32 { + // Stop spinning when it's unlocked or read locked, or when there's waiting threads. + self.spin_until(|state| { + !is_write_locked(state) || has_readers_waiting(state) || has_writers_waiting(state) + }) + } +} +impl Drop for RwLock { + fn drop(&mut self) { + let rtn = unsafe { LOS_EventDestroy(&self.event) }; + debug_assert!(rtn == LOS_OK); + } +} diff --git a/src/liteos/os.rs b/src/liteos/os.rs index 8da1742..19cd340 100644 --- a/src/liteos/os.rs +++ b/src/liteos/os.rs @@ -1,10 +1,22 @@ -use core::str::from_utf8_unchecked; +use core::{alloc::Layout, mem::MaybeUninit, str::from_utf8_unchecked}; + +use crate::thread::Thread; use super::{ - libc::sys::{self, *}, + libc::{ + event::{ + LOS_EventInit, LOS_EventRead, LOS_EventWrite, EVENT_CB_S, LOS_WAITMODE_AND, + LOS_WAITMODE_CLR, LOS_WAITMODE_OR, + }, + sys::{self, *}, + }, sysinfo::LOSCFG_BASE_CORE_TICK_PER_SECOND, }; -use alloc::string::{String, ToString}; +use alloc::{ + alloc::alloc, + boxed::Box, + string::{String, ToString}, +}; #[inline(always)] pub fn errno() -> i32 { unsafe { *__errno_location() as i32 } @@ -41,3 +53,44 @@ pub const CPU_CORE_NUMBERS: usize = 1; pub fn abort() -> ! { unsafe { sys::abort() }; } + +pub unsafe fn los_event_check() { + let ly = Layout::new::(); + let p = alloc(ly).cast(); + LOS_EventInit(p); + let th1 = Thread::new(1024, box move || { + for _ in 0..2 { + let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); + let tick = get_tickcount(); + printf("Task0:tick:%u;:%d\r\n\0".as_ptr(), tick, rtn); + } + }) + .unwrap_unchecked(); + + let th2 = Thread::new(1024, box move || { + for _ in 0..2 { + let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); + let tick = get_tickcount(); + printf("Task1:tick:%u;:%u\r\n\0".as_ptr(), tick, rtn); + } + }) + .unwrap_unchecked(); + + let th3 = Thread::new(1024, box move || { + for _ in 0..2 { + let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); + let tick = get_tickcount(); + printf("Task2:tick:%u;:%u\r\n\0".as_ptr(), tick, rtn); + } + }) + .unwrap_unchecked(); + + for _ in 0..2 { + Thread::sleep(1000); + printf("send------\r\n\0".as_ptr()); + LOS_EventWrite(p, 1); + } + th1.join(); + th2.join(); + th3.join(); +} diff --git a/src/unix/locks/futex_rwlock.rs b/src/unix/locks/futex_rwlock.rs index 36e0c3b..3f7718f 100644 --- a/src/unix/locks/futex_rwlock.rs +++ b/src/unix/locks/futex_rwlock.rs @@ -1,6 +1,10 @@ #[cfg(test)] mod tests; -use crate::unix::utils::{futex_wait, futex_wake, futex_wake_all}; +use crate::{ + os::CPU_CORE_NUMBERS, + thread::Thread, + unix::utils::{futex_wait, futex_wake, futex_wake_all}, +}; use core::sync::atomic::{ AtomicU32, Ordering::{Acquire, Relaxed, Release}, @@ -322,7 +326,11 @@ impl RwLock { if f(state) || spin == 0 { return state; } - core::hint::spin_loop(); + if CPU_CORE_NUMBERS > 1 { + core::hint::spin_loop(); + } else { + Thread::yield_now(); + } spin -= 1; } } -- Gitee From c49393ea4e38c889ac9417da856061a86be86943 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 10 Aug 2022 06:14:13 +0000 Subject: [PATCH 25/27] RwLock --- .cargo/config.toml | 6 +- .vscode/c_cpp_properties.json | 28 ++++ .vscode/configurationCache.log | 1 + .vscode/dryrun.log | 6 + .vscode/targets.log | 216 +++++++++++++++++++++++++ Cargo.toml | 9 +- build.rs | 47 +++++- examples/liteos/lazyobj_test.rs | 6 +- examples/liteos/os.rs | 56 ++++++- examples/liteos/parker.rs | 6 +- examples/liteos/rwlock_test.rs | 80 ++++++++-- examples/test_liteos.rs | 18 +-- src/common/lazyobj.rs | 32 ++-- src/lib.rs | 2 + src/liteos/libc.rs | 257 +++++++++++++++++++++++++++++- src/liteos/locks/parker.rs | 12 +- src/liteos/locks/rwlock.rs | 268 ++++++++++++++++++++++++++------ src/liteos/malloc.rs | 12 +- src/liteos/os.rs | 62 ++------ src/liteos/rust.c | 109 +++++++++++++ src/liteos/thread.rs | 3 +- 21 files changed, 1066 insertions(+), 170 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/configurationCache.log create mode 100644 .vscode/dryrun.log create mode 100644 .vscode/targets.log create mode 100644 src/liteos/rust.c diff --git a/.cargo/config.toml b/.cargo/config.toml index b973bcd..295be3e 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -51,6 +51,6 @@ rustflags = [ '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/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..77d74a0 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,28 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "/home/shuaihu/project/c/LiteOS/**", + "/home/shuaihu/project/c/LiteOS/kernel/include", + "/home/shuaihu/project/c/LiteOS/kernel/base/include", + "/home/shuaihu/project/c/LiteOS/targets/STM32F103_FIRE_Arbitrary/Inc", + "/home/shuaihu/project/c/LiteOS/targets/STM32F103_FIRE_Arbitrary/include", + "/home/shuaihu/project/c/LiteOS/arch/arm/cortex_m/include", + "/home/shuaihu/project/c/LiteOS/arch/arm/cortex_m/cmsis", + "/home/shuaihu/project/c/LiteOS/drivers/timer/include", + "/home/shuaihu/project/c/LiteOS/drivers/base/include", + "/home/shuaihu/project/c/LiteOS/drivers/interrupt/include", + "/home/shuaihu/project/c/LiteOS/drivers/uart/include", + "/home/shuaihu/project/c/LiteOS/lib/libsec/include" + ], + "defines": [], + "compilerPath": "/home/shuaihu/.local/bin/arm-none-eabi-gcc", + "cStandard": "gnu17", + "cppStandard": "gnu++17", + "intelliSenseMode": "linux-gcc-arm", + "configurationProvider": "ms-vscode.makefile-tools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/configurationCache.log b/.vscode/configurationCache.log new file mode 100644 index 0000000..bab9054 --- /dev/null +++ b/.vscode/configurationCache.log @@ -0,0 +1 @@ +{"buildTargets":[],"launchTargets":[],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":[],"compilerArgs":[]},"fileIndex":[]}} \ No newline at end of file diff --git a/.vscode/dryrun.log b/.vscode/dryrun.log new file mode 100644 index 0000000..2293bef --- /dev/null +++ b/.vscode/dryrun.log @@ -0,0 +1,6 @@ +make --dry-run --always-make --keep-going --print-directory +make: Entering directory '/home/shuaihu/project/rust/opcua/arch' +make: Leaving directory '/home/shuaihu/project/rust/opcua/arch' + +make: *** No targets specified and no makefile found. Stop. + diff --git a/.vscode/targets.log b/.vscode/targets.log new file mode 100644 index 0000000..c097b01 --- /dev/null +++ b/.vscode/targets.log @@ -0,0 +1,216 @@ +make all --print-data-base --no-builtin-variables --no-builtin-rules --question +make: *** No rule to make target 'all'. Stop. + +# GNU Make 4.2.1 +# Built for x86_64-pc-linux-gnu +# Copyright (C) 1988-2016 Free Software Foundation, Inc. +# License GPLv3+: GNU GPL version 3 or later +# This is free software: you are free to change and redistribute it. +# There is NO WARRANTY, to the extent permitted by law. + +# Make data base, printed on Fri Aug 5 09:34:04 2022 + +# Variables + +# automatic + 0 { println!("cargo:rustc_cfg='{}={}'", key, value); + if key == "LOSCFG_PLATFORM" { + liteos_add_padding(&los_path, &manifest_path, value.trim_matches('\"')); + } } } } @@ -105,3 +107,44 @@ fn main() { top_path.join(".cargo/config.toml").to_str().unwrap() ); } + +fn liteos_add_padding(los_path: &PathBuf, manifest_path: &PathBuf, platform: &str) { + let target = los_path.join("targets").join(platform); + copy( + manifest_path.join("src/liteos/rust.c"), + target.join("Src/rust.c"), + ) + .unwrap(); + println!( + "cargo:rerun-if-changed={}", + manifest_path.join("src/liteos/rust.c").to_str().unwrap() + ); + if !target.join("Makefile.org").exists() { + rename(target.join("Makefile"), target.join("Makefile.org")).unwrap(); + } + let fmake = File::options() + .read(true) + .open(target.join("Makefile.org")) + .unwrap(); + let mut _fmake = File::options() + .write(true) + .create(true) + .open(target.join("Makefile")) + .unwrap(); + let fmake = BufReader::new(fmake); + for line in fmake.lines() { + if let Ok(line) = line { + write!(&mut _fmake, "{}\n", line).unwrap(); + if line.trim().starts_with("C_SOURCES") { + write!( + &mut _fmake, + "{}\n{}\n", + "RUST_SRC = $(LITEOSTOPDIR)/targets/$(LITEOS_PLATFORM)/Src/rust.c", + "C_SOURCES += $(RUST_SRC)" + ) + .unwrap(); + } + } + } + drop(_fmake); +} diff --git a/examples/liteos/lazyobj_test.rs b/examples/liteos/lazyobj_test.rs index bace800..8b98987 100644 --- a/examples/liteos/lazyobj_test.rs +++ b/examples/liteos/lazyobj_test.rs @@ -7,6 +7,7 @@ struct TestStruct { q: u64, } impl Drop for TestStruct { + #[inline(never)] fn drop(&mut self) { unsafe { printf("Droped1\n\0".as_ptr()) }; } @@ -25,10 +26,11 @@ pub fn lazyobj_test() { } struct TestStruct2 { - a: u32, - q: u128, + a: u8, + q: u64, } impl Drop for TestStruct2 { + #[inline(never)] fn drop(&mut self) { unsafe { printf("Droped2\n\0".as_ptr()) }; } diff --git a/examples/liteos/os.rs b/examples/liteos/os.rs index ba5bef2..5fa12f4 100644 --- a/examples/liteos/os.rs +++ b/examples/liteos/os.rs @@ -1,9 +1,63 @@ +use alloc::alloc::{alloc, dealloc, Layout}; use arch::instant::Instant; +use arch::locks::MovableMutex; use arch::os::printf; use arch::thread; +use arch::thread::Thread; 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) }; + unsafe { printf("elapsed time:%d\n\r\0".as_ptr(), t) }; } + +// static MUTEX: MovableMutex = MovableMutex::new(); +// pub unsafe fn los_event_check() { +// let ly = Layout::new::(); +// let p = alloc(ly).cast(); + +// LOS_EventInit(p); +// let th1 = Thread::new(1536, box move || { +// for _ in 0..10 { +// let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); +// let tick = Instant::now(); +// MUTEX.lock(); +// printf("Task0:tick:%u;:%d\r\n\0".as_ptr(), tick, rtn); +// MUTEX.unlock(); +// } +// }) +// .unwrap(); + +// let th2 = Thread::new(1536, box move || { +// for _ in 0..10 { +// let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); +// let tick = Instant::now(); +// MUTEX.lock(); +// printf("Task1:tick:%u;:%u\r\n\0".as_ptr(), tick, rtn); +// MUTEX.unlock(); +// } +// }) +// .unwrap(); + +// let th3 = Thread::new(1536, box move || { +// for _ in 0..10 { +// let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); +// let tick = Instant::now(); +// MUTEX.lock(); +// printf("Task2:tick:%u;:%u\r\n\0".as_ptr(), tick, rtn); +// MUTEX.unlock(); +// } +// }) +// .unwrap(); + +// for _ in 0..10 { +// Thread::sleep(1000); +// printf("send------\r\n\0".as_ptr()); +// LOS_EventWrite(p, 1); +// } +// th2.join(); +// th1.join(); +// th3.join(); +// LOS_EventDestroy(p); +// dealloc(p.cast(), ly); +// } diff --git a/examples/liteos/parker.rs b/examples/liteos/parker.rs index f7f7901..ba37dbe 100644 --- a/examples/liteos/parker.rs +++ b/examples/liteos/parker.rs @@ -7,7 +7,7 @@ pub fn parker_led() { let (p, u) = pair(); unsafe { thread::Thread::new( - 400, + 800, Box::new(move || { for _ in 0..2 { p.park(); @@ -23,7 +23,3 @@ pub fn parker_led() { u.unpark(); } } - -pub fn los_event_check() { - unsafe { arch::os::los_event_check() }; -} diff --git a/examples/liteos/rwlock_test.rs b/examples/liteos/rwlock_test.rs index f387d7f..651f423 100644 --- a/examples/liteos/rwlock_test.rs +++ b/examples/liteos/rwlock_test.rs @@ -1,10 +1,72 @@ -use arch::locks::MovableRwLock; -pub fn rwlock_smoke() { - let l = MovableRwLock::new(); - l.read(); - l.read(); - // drop(l.read().unwrap()); - // drop(l.write().unwrap()); - // drop((l.read().unwrap(), l.read().unwrap())); - // drop(l.write().unwrap()); +use core::hint::spin_loop; + +use alloc::vec::Vec; +use arch::{ + instant::Instant, + locks::MovableRwLock, + os::{printf, rand}, + thread::Thread, +}; +pub unsafe fn rwlock_smoke() { + static L: MovableRwLock = MovableRwLock::new(); + if L.try_read() { + printf("true\r\n\0".as_ptr()); + } else { + printf("false\r\n\0".as_ptr()); + } + L.read(); + L.read(); + if L.try_write() { + printf("true\r\n\0".as_ptr()); + } else { + printf("false\r\n\0".as_ptr()); + } + Thread::new(4096, box || { + L.write(); + printf("Locked Write\r\n\0".as_ptr()); + }) + .unwrap_unchecked(); + L.read_unlock(); + L.read_unlock(); + Thread::yield_now(); + L.read_unlock(); + printf("UnLock Ok\r\n\0".as_ptr()); +} +#[no_mangle] +pub static RWLOCK: MovableRwLock = MovableRwLock::new(); +pub unsafe fn frob() { + const N: u32 = 4; + const M: usize = 100000; + RWLOCK.read(); + RWLOCK.read_unlock(); + let mut t = Vec::::new(); + for _ in 0..N { + let th = Thread::new(2048, box move || { + for _s in 0..M { + let i = rand(); + if i % 2 == 0 { + RWLOCK.write(); + for _ in 0..10000 { + spin_loop(); + } + RWLOCK.write_unlock(); + } else { + RWLOCK.read(); + for _ in 0..5000 { + spin_loop(); + } + RWLOCK.read_unlock(); + } + } + }) + .unwrap_unchecked(); + t.push(th); + } + let a = Instant::now(); + for t in t.drain(..) { + t.join(); + } + let p = a.elapsed(); + printf("elapsed time:%d\r\n\0".as_ptr(), p); + assert_eq!(1, 1); } diff --git a/examples/test_liteos.rs b/examples/test_liteos.rs index cd7bf83..46f051a 100644 --- a/examples/test_liteos.rs +++ b/examples/test_liteos.rs @@ -2,13 +2,9 @@ #![feature(default_alloc_error_handler)] #![feature(panic_info_message)] #![feature(bench_black_box)] +#![feature(box_syntax)] -use core::alloc::Layout; - -use alloc::{ - alloc::{alloc, dealloc}, - string::ToString, -}; +use alloc::string::ToString; use arch::os::printf; #[allow(unused_imports)] @@ -27,7 +23,7 @@ pub unsafe fn painc_handler(info: &core::panic::PanicInfo<'_>) -> ! { printf("%s\n\0".as_ptr().cast(), s.as_ptr()); loop {} } - +#[allow(unused, unused_imports)] mod liteos; use liteos::*; #[no_mangle] @@ -48,10 +44,10 @@ unsafe extern "C" fn app_init() { lazyobj_test6(); printf("getTickCount Test\n\0".as_ptr()); get_tickcount_test(); - printf("RWLock smolk Test\n\0".as_ptr()); - rwlock_smoke(); printf("parker led Test\n\0".as_ptr()); parker_led(); - printf("LOS Event Check\n\0".as_ptr()); - los_event_check() + printf("RWLock smolk Test\n\0".as_ptr()); + rwlock_smoke(); + printf("RWLock frob Test\n\0".as_ptr()); + frob(); } diff --git a/src/common/lazyobj.rs b/src/common/lazyobj.rs index 086803c..ecce8c2 100644 --- a/src/common/lazyobj.rs +++ b/src/common/lazyobj.rs @@ -10,7 +10,7 @@ use core::{ ops::{Deref, DerefMut}, sync::atomic::{ AtomicUsize, - Ordering::{Acquire, Relaxed, Release}, + Ordering::{Relaxed, Release}, }, }; const EMPTY: usize = usize::MAX; @@ -40,11 +40,11 @@ impl LazyObj { let mut state = self.value.load(Relaxed); if state > COMPLETE { if ISBOX { - state = initialize_box(&self.value, state, Self::LY, unsafe { + state = initialize_box(&self.value, Self::LY, unsafe { transmute(T::init as *mut u8) }); } else { - initialize_nobox(&self.value, state, unsafe { transmute(T::init as *mut u8) }); + initialize_nobox(&self.value, unsafe { transmute(T::init as *mut u8) }); } } if ISBOX { @@ -56,11 +56,13 @@ impl LazyObj { } //放置到全局的目的是禁止泛化,造成的代码膨胀。 #[cold] -fn initialize_box(ptr: &AtomicUsize, mut state: usize, ly: Layout, init: fn(*mut ())) -> usize { +fn initialize_box(ptr: &AtomicUsize, ly: Layout, init: fn(*mut ())) -> usize { + let mut state = ptr.load(Relaxed); loop { match state { + s if s < RUNING => return state, EMPTY => { - let result = ptr.compare_exchange_weak(state, RUNING, Acquire, Acquire); + let result = ptr.compare_exchange_weak(state, RUNING, Relaxed, Relaxed); if let Err(old) = result { state = old; continue; @@ -70,7 +72,6 @@ fn initialize_box(ptr: &AtomicUsize, mut state: usize, ly: Layout, init: fn(*mut ptr.swap(t.addr(), Release); return t.addr(); } - s if s < RUNING => return state, _ => { if CPU_CORE_NUMBERS > 1 { core::hint::spin_loop(); @@ -78,7 +79,7 @@ fn initialize_box(ptr: &AtomicUsize, mut state: usize, ly: Layout, init: fn(*mut thread::Thread::yield_now(); } debug_assert!(state == RUNING); - state = ptr.load(Acquire); + state = ptr.load(Relaxed); continue; } } @@ -86,27 +87,28 @@ fn initialize_box(ptr: &AtomicUsize, mut state: usize, ly: Layout, init: fn(*mut } #[cold] //放置到全局的目的是禁止泛化,造成的代码膨胀。 -fn initialize_nobox(ptr: &AtomicUsize, mut status: usize, init: fn(*mut ())) { +fn initialize_nobox(ptr: &AtomicUsize, init: fn(*mut ())) { + let mut state = ptr.load(Relaxed); loop { - match status { + match state { EMPTY => { - let result = ptr.compare_exchange_weak(status, RUNING, Acquire, Acquire); + let result = ptr.compare_exchange_weak(state, RUNING, Relaxed, Relaxed); if let Err(old) = result { - status = old; + state = old; continue; } - unsafe { init(transmute(&status)) }; - ptr.swap(status, Release); + unsafe { init(transmute(&state)) }; + ptr.swap(state, Release); } s if s < RUNING => return, _ => { - debug_assert!(status == RUNING); + debug_assert!(state == RUNING); if CPU_CORE_NUMBERS > 1 { core::hint::spin_loop(); } else { thread::Thread::yield_now(); } - status = ptr.load(Acquire); + state = ptr.load(Relaxed); continue; } } diff --git a/src/lib.rs b/src/lib.rs index 62a814d..a089082 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,8 @@ #![feature(negative_impls)] #![feature(const_mut_refs)] #![feature(bench_black_box)] +#![feature(let_chains)] +#![feature(const_ptr_offset_from)] #[allow(unused_imports)] #[macro_use] diff --git a/src/liteos/libc.rs b/src/liteos/libc.rs index db52e60..99bf61b 100644 --- a/src/liteos/libc.rs +++ b/src/liteos/libc.rs @@ -12,6 +12,8 @@ pub mod heap { uwUsageWaterLine: u32, } extern "C" { + #[link_name = "__los_heap_addr_start__"] + pub static mut GLOBAL_POOL: u8; // 初始化和删除内存池 // LOS_MemInit 初始化一块指定的动态内存池,大小为size pub fn LOS_MemInit(poll: *mut u8, size: u32) -> u32; @@ -95,8 +97,6 @@ pub mod sys { 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 { @@ -133,18 +133,128 @@ pub mod pthread { pub mod timer { extern "C" { pub fn LOS_MS2Tick(millisec: u32) -> u32; + pub fn LOS_TickCountGet() -> u64; } } pub mod task { + use super::super::sysinfo::*; + use super::event::EVENT_CB_S; + use super::list::{SortLinkList, LOS_DL_LIST}; + use super::spinlock::SPIN_LOCK_S; use super::LOSCFG_BASE_CORE_TSK_LIMIT; + use crate::os::CPU_CORE_NUMBERS; + use core::ffi::c_void; pub const KERNEL_TSK_LIMIT: u32 = LOSCFG_BASE_CORE_TSK_LIMIT as u32; pub const LOS_ERRNO_TSK_ID_INVALID: u32 = 0x02000207; + + pub const OS_TASK_STATUS_READY: u16 = 0x0004; + pub const OS_TASK_STATUS_PEND: u16 = 0x0008; + + #[cfg(LOSCFG_KERNEL_SMP_LOCKDEP)] + #[repr(C)] + pub struct HeldLocks { + lockPtr: *const c_void, + lockAddr: *const c_void, + waitTime: u64, + holdTime: u64, + } + #[cfg(LOSCFG_KERNEL_SMP_LOCKDEP)] + const MAX_LOCK_DEPTH: usize = 16; + #[cfg(LOSCFG_KERNEL_SMP_LOCKDEP)] + #[repr(C)] + pub struct LockDep { + waitLock: *const c_void, + lockDepth: i32, + heldLocks: [HeldLocks; MAX_LOCK_DEPTH], + } + #[cfg(LOSCFG_DEBUG_SCHED_STATISTICS)] + #[repr(C)] + pub struct SchedPercpu { + runtime: u64, + contexSwitch: u32, + } + #[cfg(LOSCFG_DEBUG_SCHED_STATISTICS)] + #[repr(C)] + pub struct SchedStat { + startRuntime: u64, + allRuntime: u64, + allContextSwitch: u32, + schedPercpu: [SchedPercpu; CPU_CORE_NUMBERS], + } + #[repr(C)] + pub struct LosTaskCB { + pub stackPointer: *const core::ffi::c_void, /* Task stack pointer */ + pub taskStatus: u16, /* Task status */ + pub priority: u16, /* Task priority */ + pub taskFlags: u32, /* Task extend flags: taskFlags uses 8 bits now. 23 bits left */ + pub stackSize: u32, /* Task stack size */ + pub topOfStack: *const u32, /* Task stack top */ + pub taskId: u32, /* Task ID */ + pub taskEntry: *const c_void, /* Task entrance function */ + pub taskSem: *const core::ffi::c_void, /* Task-held semaphore */ + #[cfg(LOSCFG_COMPAT_POSIX)] + pub threadJoin: *const core::ffi::c_void, /* pthread adaption */ + #[cfg(LOSCFG_COMPAT_POSIX)] + pub threadJoinRetval: *const core::ffi::c_void, /* pthread adaption */ + + pub taskMux: *const core::ffi::c_void, /* Task-held mutex */ + #[cfg(LOSCFG_OBSOLETE_API)] + pub args: [*const u32; 4], /* Parameter, of which the maximum number is 4 */ + #[cfg(not(LOSCFG_OBSOLETE_API))] + pub args: *const core::ffi::c_void, /* Parameter, of which the type is void * */ + + pub taskName: *const u8, /* Task name */ + pub pendList: LOS_DL_LIST, /* Task pend node */ + pub sortList: SortLinkList, /* Task sortlink node */ + #[cfg(LOSCFG_BASE_IPC_EVENT)] + pub event: EVENT_CB_S, + #[cfg(LOSCFG_BASE_IPC_EVENT)] + pub eventMask: u32, /* Event mask */ + #[cfg(LOSCFG_BASE_IPC_EVENT)] + pub eventMode: u32, /* Event mode */ + + pub msg: *const core::ffi::c_void, /* Memory allocated to queues */ + pub priBitMap: u32, /* BitMap for recording the change of task priority, + the priority can not be greater than 31 */ + pub signal: u32, /* Task signal */ + #[cfg(LOSCFG_BASE_CORE_TIMESLICE)] + pub timeSlice: u16, /* Remaining time slice */ + + #[cfg(LOSCFG_KERNEL_SMP)] + pub currCpu: u16, /* CPU core number of this task is running on */ + #[cfg(LOSCFG_KERNEL_SMP)] + pub lastCpu: u16, /* CPU core number of this task is running on last time */ + #[cfg(LOSCFG_KERNEL_SMP)] + pub timerCpu: u32, /* CPU core number of this task is delayed or pended */ + #[cfg(LOSCFG_KERNEL_SMP)] + pub cpuAffiMask: u16, /* CPU affinity mask, support up to 16 cores */ + #[cfg(all(LOSCFG_KERNEL_SMP, LOSCFG_KERNEL_SMP_TASK_SYNC))] + pub syncSignal: u32, /* Synchronization for signal handling */ + #[cfg(all(LOSCFG_KERNEL_SMP, LOSCFG_KERNEL_SMP_LOCKDEP))] + pub lockDep: LockDep, + + #[cfg(LOSCFG_DEBUG_SCHED_STATISTICS)] + pub schedStat: SchedStat, /* Schedule statistics */ + + #[cfg(LOSCFG_KERNEL_PERF)] + pub pc: *const u32, + #[cfg(LOSCFG_KERNEL_PERF)] + pub fp: *const u32, + } + extern "C" { + pub static g_taskSpin: SPIN_LOCK_S; 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 fn LOS_TaskLock(); + pub fn LOS_TaskUnlock(); + pub fn OsSchedResched(); + #[inline(always)] + #[link_name = "_OsCurrTaskGet"] + pub fn OsCurrTaskGet() -> *mut LosTaskCB; } } pub mod mutex { @@ -159,7 +269,6 @@ pub mod mutex { } } pub mod event { - pub const LOS_WAITMODE_AND: u32 = 4u32; pub const LOS_WAITMODE_CLR: u32 = 1u32; pub const LOS_WAITMODE_OR: u32 = 2u32; @@ -179,5 +288,147 @@ pub mod event { ) -> u32; pub fn LOS_EventWrite(eventCB: *const EVENT_CB_S, events: u32) -> u32; pub fn LOS_EventDestroy(eventCB: *const EVENT_CB_S) -> u32; + pub fn OsEventWriteOnce(eventCB: *const EVENT_CB_S, events: u32) -> u32; + pub fn LOS_EventClear(eventCB: *const EVENT_CB_S, events: u32) -> u32; + } +} +pub mod c { + use super::size_t; + + extern "C" { + pub fn rand() -> i32; + pub fn strnlen(cs: *const u8, maxlen: size_t) -> size_t; + } +} +pub mod spinlock { + use cfg_if::cfg_if; + cfg_if! { + if #[cfg(LOSCFG_KERNEL_SMP_LOCKDEP)]{ + #[repr(C)] + pub struct SPIN_LOCK_S { + rawLock: usize, + cpuid: u32, + owner: *const core::ffi::c_void, + name: *const u8, + } + impl SPIN_LOCK_S{ + pub const fn default() -> Self { + Self{ + rawLock:0, + cpuid:u32::MAX, + owner:core::ptr::null(), + name:b"".as_ptr(), + } + } + } + }else{ + #[repr(C)] + pub struct SPIN_LOCK_S { + rawLock: usize, + } + impl SPIN_LOCK_S{ + pub const fn default() -> Self { + Self { rawLock: 0 } + } + } + } + } + + extern "C" { + #[inline(always)] + #[link_name = "_LOS_SpinHeld"] + pub fn LOS_SpinHeld(lock: *const SPIN_LOCK_S) -> bool; + + #[inline(always)] + #[link_name = "_LOS_SpinInit"] + pub fn LOS_SpinInit(lock: *const SPIN_LOCK_S); + + #[inline(always)] + #[link_name = "_LOS_SpinLock"] + pub fn LOS_SpinLock(lock: *const SPIN_LOCK_S); + + #[inline(always)] + #[link_name = "_LOS_SpinLockSave"] + pub fn LOS_SpinLockSave(lock: *const SPIN_LOCK_S, intsave: &mut u32); + + #[inline(always)] + #[link_name = "_LOS_SpinTrylock"] + pub fn LOS_SpinTrylock(lock: *const SPIN_LOCK_S) -> u32; + + #[inline(always)] + #[link_name = "_LOS_SpinUnlock"] + pub fn LOS_SpinUnlock(lock: *const SPIN_LOCK_S); + + #[inline(always)] + #[link_name = "_LOS_SpinUnlockRestore"] + pub fn LOS_SpinUnlockRestore(lock: *const SPIN_LOCK_S, intsave: u32); + } +} +pub mod interrupt { + extern "C" { + #[inline(always)] + #[link_name = "_LOS_IntLock"] + pub fn LOS_IntLock() -> u32; + + #[inline(always)] + #[link_name = "_LOS_IntUnLock"] + pub fn LOS_IntUnLock() -> u32; + + #[inline(always)] + #[link_name = "_LOS_IntRestore"] + pub fn LOS_IntRestore(intsave: u32); + } +} +pub mod list { + use core::{mem::transmute, num::NonZeroUsize, ptr::NonNull}; + + #[repr(C)] + pub struct LOS_DL_LIST { + //**< Current node's pointer to the previous node + pstPrev: NonNull, + //**< Current node's pointer to the next node + pstNext: NonNull, + } + unsafe impl Sync for LOS_DL_LIST {} + #[repr(C)] + pub struct SortLinkList { + sortLinkNode: LOS_DL_LIST, + idxRollNum: u32, + } + + pub fn LOS_ListAdd(list: &mut LOS_DL_LIST, node: &mut LOS_DL_LIST) { + unsafe { + node.pstNext = list.pstNext; + node.pstPrev = list.into(); + list.pstNext.as_mut().pstPrev = node.into(); + list.pstNext = node.into(); + } + } + pub fn LOS_ListTailInsert(list: &mut LOS_DL_LIST, node: &mut LOS_DL_LIST) { + LOS_ListAdd(list, node); + } + pub fn LOS_ListEmpty(list: &LOS_DL_LIST) -> bool { + return list.pstNext == list.into(); + } + pub const fn LOS_ListInit(list: &mut LOS_DL_LIST) { + unsafe { + list.pstPrev = NonNull::new_unchecked(list); + list.pstNext = NonNull::new_unchecked(list); + } + } +} +pub mod futex { + use core::sync::atomic::AtomicU32; + + use super::list::LOS_DL_LIST; + extern "C" { + pub fn Futex_Wake(list: *const LOS_DL_LIST, once: bool) -> bool; + pub fn Futex_Wait( + futex: &AtomicU32, + expected: u32, + list: *const LOS_DL_LIST, + timeout: u32, + ) -> bool; + } } diff --git a/src/liteos/locks/parker.rs b/src/liteos/locks/parker.rs index fac29e0..e343e7b 100644 --- a/src/liteos/locks/parker.rs +++ b/src/liteos/locks/parker.rs @@ -9,7 +9,7 @@ use core::mem::MaybeUninit; use core::ptr::NonNull; use core::sync::atomic::{ AtomicU32, - Ordering::{Acquire, Relaxed}, + Ordering::{Acquire, Relaxed, Release}, }; #[allow(unused)] const PARKED: u32 = 0x00000000; @@ -36,7 +36,7 @@ impl Inner { debug_assert!(rtn == LOS_OK); } unsafe fn park(&self) { - if self.flag.fetch_sub(EMPTY, Acquire) == NOTIFIED { + if self.flag.fetch_sub(EMPTY, Release) == NOTIFIED { return; } let rtn = LOS_EventRead( @@ -45,15 +45,17 @@ impl Inner { LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER, ); - debug_assert!(rtn == 1); + //If multiple threads use the same Parker, only one thread will return 1 and other threads will return zero. + debug_assert!(rtn == 1 || rtn == 0); self.flag.swap(EMPTY, Relaxed); } unsafe fn park_timeout(&self, timeout: u32) -> bool { - if self.flag.fetch_sub(EMPTY, Acquire) == NOTIFIED { + if self.flag.fetch_sub(EMPTY, Release) == 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 multiple threads use the same Parker, only one thread will return 1 and other threads will return zero. + debug_assert!(rtn == 1 || rtn == 0 || rtn == LOS_ERRNO_EVENT_READ_TIMEOUT); if self.flag.swap(EMPTY, Acquire) == NOTIFIED { true } else { diff --git a/src/liteos/locks/rwlock.rs b/src/liteos/locks/rwlock.rs index 80a4d8d..89adf33 100644 --- a/src/liteos/locks/rwlock.rs +++ b/src/liteos/locks/rwlock.rs @@ -4,16 +4,17 @@ use core::{ sync::atomic::Ordering::{Acquire, Relaxed, Release}, }; +use crate::liteos::libc::{ + futex::{Futex_Wait, Futex_Wake}, + list::{LOS_ListInit, LOS_DL_LIST}, +}; +#[allow(unused_imports)] +use crate::os::printf; use crate::{ lazy::{LazyObj, LazyObjInit}, - liteos::libc::{ - event::{LOS_EventDestroy, LOS_EventInit, LOS_EventRead, EVENT_CB_S, LOS_WAITMODE_AND}, - sys::{LOS_OK, LOS_WAIT_FOREVER}, - }, + liteos::libc::sys::LOS_WAIT_FOREVER, os::CPU_CORE_NUMBERS, - thread::Thread, }; - const READ_LOCKED: u32 = 1; const MASK: u32 = (1 << 30) - 1; const WRITE_LOCKED: u32 = MASK; @@ -21,79 +22,106 @@ const MAX_READERS: u32 = MASK - 1; const READERS_WAITING: u32 = 1 << 30; const WRITERS_WAITING: u32 = 1 << 31; +#[inline] fn is_unlocked(state: u32) -> bool { state & MASK == 0 } +#[inline] fn is_write_locked(state: u32) -> bool { state & MASK == WRITE_LOCKED } +#[inline] fn has_readers_waiting(state: u32) -> bool { state & READERS_WAITING != 0 } +#[inline] fn has_writers_waiting(state: u32) -> bool { state & WRITERS_WAITING != 0 } +#[inline] fn is_read_lockable(state: u32) -> bool { - state & !MASK == 0 && state & MASK < MAX_READERS + (state & MASK < MAX_READERS) && (state & (!MASK) == 0) } +#[inline] fn has_reached_max_readers(state: u32) -> bool { state & MASK == MAX_READERS } pub struct RwLock { state: AtomicU32, - event: EVENT_CB_S, + wrcnt: AtomicU32, + readers: LOS_DL_LIST, + writers: LOS_DL_LIST, } pub type MovableRwLock = LazyObj; impl LazyObjInit for RwLock { fn init(v: &mut MaybeUninit) { - let v = v.write(RwLock::new()); + let v = unsafe { v.assume_init_mut() }; v.init(); } } +/// NB that during the initialization of liteos event, +/// The head and tail of the double linked list point to itself as an empty tag. +/// Therefore, events must be placed on the heap and cannot be moved. impl RwLock { - #[inline] - pub const fn new() -> Self { - Self { - state: AtomicU32::new(0), - event: unsafe { MaybeUninit::uninit().assume_init() }, - } + fn init(&mut self) { + self.state = AtomicU32::new(0); + self.wrcnt = AtomicU32::new(0); + LOS_ListInit(&mut self.readers); + LOS_ListInit(&mut self.writers); } - fn init(&self) { - let rtn = unsafe { LOS_EventInit(&self.event) }; - debug_assert!(rtn == LOS_OK); - } - pub fn try_read(&self) -> bool { + // Here only need to test and lock it once, and the successful locking returns true + pub unsafe fn try_read(&self) -> bool { self.state .fetch_update(Acquire, Relaxed, |s| { is_read_lockable(s).then(|| s + READ_LOCKED) }) .is_ok() } - #[cold] - pub fn read(&self) { - let state = self.state.load(Relaxed); - if !is_read_lockable(state) - || self - .state - .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) - .is_err() - { - self.read_contended(); + pub unsafe fn read(&self) { + let mut state = self.state.load(Relaxed); + while is_read_lockable(state) { + if let Err(s) = + self.state + .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) + { + state = s; + continue; + } + // Successfully locked, Return; + return; + } + // Resolve lock contention + self.read_contended(); + } + pub fn read_unlock(&self) { + let state = self.state.fetch_sub(READ_LOCKED, Release) - READ_LOCKED; + + // There can be no task waiting to be read, unless there is a task waiting to be written. + debug_assert!(!has_readers_waiting(state) || has_writers_waiting(state)); + + // If we are the last reader,and there are tasks waiting to be written, wake up the task which waiting to be written. + if is_unlocked(state) && has_writers_waiting(state) { + unsafe { self.wake_writer_or_readers(state) }; } } #[cold] fn read_contended(&self) { - let mut state = self.spin_read(); + // For a single core processor, spin only causes the problem of priority inversion. + let mut state = if CPU_CORE_NUMBERS > 1 { + self.spin_read() + } else { + self.state.load(Acquire) + }; loop { if is_read_lockable(state) { match self .state .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) { - Ok(_) => return, + Ok(_) => return, // Locked! Err(s) => { state = s; continue; @@ -105,6 +133,7 @@ impl RwLock { if has_reached_max_readers(state) { panic!("too many active read locks on RwLock"); } + // If there are no readers waiting for lock, we set it up. if !has_readers_waiting(state) { if let Err(s) = self.state @@ -114,11 +143,158 @@ impl RwLock { continue; } } - let rtn = unsafe { LOS_EventRead(&self.event, 1, LOS_WAITMODE_AND, LOS_WAIT_FOREVER) }; - debug_assert!(rtn == 1); - state = self.spin_read(); + // blocking current thread , and wait for notify. + unsafe { + Futex_Wait( + &self.state, + state | READERS_WAITING, + &self.readers, + LOS_WAIT_FOREVER, + ) + }; + state = if CPU_CORE_NUMBERS > 1 { + self.spin_read() + } else { + self.state.load(Acquire) + }; } } + // Test and locked it; + pub unsafe fn try_write(&self) -> bool { + self.state + .fetch_update(Acquire, Relaxed, |s| { + is_unlocked(s).then(|| s + WRITE_LOCKED) + }) + .is_ok() + } + pub unsafe fn write(&self) { + // In most cases, entering the write-lock is in the lock idle state. + if self + .state + .compare_exchange_weak(0, WRITE_LOCKED, Acquire, Relaxed) + .is_err() + { + self.write_contended(); + } + } + + pub unsafe fn write_unlock(&self) { + let state = self.state.fetch_sub(WRITE_LOCKED, Release) - WRITE_LOCKED; + // After unlocked the write-lock, it is only possible to enter the unlocked state + debug_assert!(is_unlocked(state)); + + if has_writers_waiting(state) || has_readers_waiting(state) { + self.wake_writer_or_readers(state); + } + } + + #[cold] + unsafe fn write_contended(&self) { + // For a single core processor, spin only causes the problem of priority inversion. + let mut state = if CPU_CORE_NUMBERS > 1 { + self.spin_write() + } else { + self.state.load(Acquire) + }; + let mut other_writers_waiting = 0; + loop { + // If it's unlocked, we try to lock it. + if is_unlocked(state) { + match self.state.compare_exchange_weak( + state, + state | WRITE_LOCKED | other_writers_waiting, + Acquire, + Relaxed, + ) { + Ok(_) => return, // Locked! + Err(s) => { + state = s; + continue; + } + } + } + + if !has_writers_waiting(state) { + if let Err(s) = + self.state + .compare_exchange(state, state | WRITERS_WAITING, Relaxed, Relaxed) + { + state = s; + continue; + } + } + // Because there may be other tasks waiting to write the lock, + // so,we need to keep this state in the next retry. + other_writers_waiting = WRITERS_WAITING; + let seq = self.wrcnt.load(Acquire); + // Confirm again whether to wait. + state = self.state.load(Relaxed); + if is_unlocked(state) || !has_writers_waiting(state) { + continue; + } + Futex_Wait(&self.wrcnt, seq, &self.writers, LOS_WAIT_FOREVER); + // Retry lock + state = if CPU_CORE_NUMBERS > 1 { + self.spin_write() + } else { + self.state.load(Acquire) + }; + } + } + + /// Wake up waiting tasks after unlocking + /// + /// If there are tasks waiting to be written, wake up one of them first。 + /// Otherwise, wake up all tasks waiting for reading。 + + #[cold] + unsafe fn wake_writer_or_readers(&self, mut state: u32) { + debug_assert!(is_unlocked(state)); + // If there are only tasks which waiting to write locks,We just need to wake one of them. + // NB. There is no need to judge whether the task is really awakened. + // If no task is awakened, it means that the current task is the last one. The lock state is restored to the initial state + if state == WRITERS_WAITING { + match self.state.compare_exchange(state, 0, Relaxed, Relaxed) { + Ok(_) => { + self.wrcnt.fetch_add(1, Release); + Futex_Wake(&self.writers, true); + return; + } + Err(s) => { + // Maybe some readers are now waiting too. So, continue to the next `if`. + state = s; + } + } + } + if state == READERS_WAITING + WRITERS_WAITING { + if self + .state + .compare_exchange(state, READERS_WAITING, Relaxed, Relaxed) + .is_err() + { + // Only other tasks have acquired the write lock, so no processing is required. + return; + } + // Wake up the task which waiting for writing. + // If no task were actually blocking on Futex,We continue wake up the task which waiting for reading. + self.wrcnt.fetch_add(1, Relaxed); + if Futex_Wake(&self.writers, true) { + return; + } + state = READERS_WAITING; + } + // Wake up tasks which waiting to be read + if state == READERS_WAITING { + if self + .state + .compare_exchange(state, 0, Relaxed, Relaxed) + .is_ok() + { + Futex_Wake(&self.readers, false); + } + } + } + fn spin_until(&self, f: impl Fn(u32) -> bool) -> u32 { let mut spin = 100; // Chosen by fair dice roll. loop { @@ -126,24 +302,22 @@ impl RwLock { if f(state) || spin == 0 { return state; } - if CPU_CORE_NUMBERS > 1 { - core::hint::spin_loop(); - } else { - Thread::yield_now(); - } + core::hint::spin_loop(); spin -= 1; } } + + fn spin_write(&self) -> u32 { + // Stop spinning when it's unlocked or when there's waiting writers. + self.spin_until(|state| is_unlocked(state) || has_writers_waiting(state)) + } + fn spin_read(&self) -> u32 { - // Stop spinning when it's unlocked or read locked, or when there's waiting threads. + // 1:Is no writer locked it; At this time, we need to try to lock it again + // 2:There is a reader waiting for lock; At this time, we should also directly block the current thread and wait for wakeup + // 3:There is a writer waiting for lock; At this time, we should also directly block the current thread and wait for wakeup self.spin_until(|state| { !is_write_locked(state) || has_readers_waiting(state) || has_writers_waiting(state) }) } } -impl Drop for RwLock { - fn drop(&mut self) { - let rtn = unsafe { LOS_EventDestroy(&self.event) }; - debug_assert!(rtn == LOS_OK); - } -} diff --git a/src/liteos/malloc.rs b/src/liteos/malloc.rs index 19c78cc..cf32d8e 100644 --- a/src/liteos/malloc.rs +++ b/src/liteos/malloc.rs @@ -2,10 +2,6 @@ use super::libc::heap::*; use crate::common::malloc::{realloc_fallback, System, MIN_ALIGN}; use core::alloc::{GlobalAlloc, Layout}; -extern "C" { - #[link_name = "__los_heap_addr_start__"] - static mut POOL: u8; -} unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { @@ -13,15 +9,15 @@ unsafe impl GlobalAlloc for System { let size = layout.size() as u32; let size = (size + (4 - 1)) & (-4i32 as u32); let ptr = if layout.align() <= MIN_ALIGN { - LOS_MemAlloc(&mut POOL, size) + LOS_MemAlloc(&mut GLOBAL_POOL, size) } else { - LOS_MemAllocAlign(&mut POOL, size, layout.align() as u32) + LOS_MemAllocAlign(&mut GLOBAL_POOL, size, layout.align() as u32) }; ptr } #[inline] unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - LOS_MemFree(&mut POOL, ptr); + LOS_MemFree(&mut GLOBAL_POOL, ptr); } #[inline] @@ -29,7 +25,7 @@ unsafe impl GlobalAlloc for System { let size = new_size as u32; let size = (size + (4 - 1)) & (-4i32 as u32); if layout.align() <= MIN_ALIGN { - LOS_MemRealloc(&mut POOL, ptr, size) + LOS_MemRealloc(&mut GLOBAL_POOL, ptr, size) } else { realloc_fallback(self, ptr, layout, new_size) } diff --git a/src/liteos/os.rs b/src/liteos/os.rs index 19cd340..a430b1a 100644 --- a/src/liteos/os.rs +++ b/src/liteos/os.rs @@ -1,22 +1,14 @@ -use core::{alloc::Layout, mem::MaybeUninit, str::from_utf8_unchecked}; +use core::str::from_utf8_unchecked; -use crate::thread::Thread; +use super::libc; +use super::libc::timer::LOS_TickCountGet; use super::{ - libc::{ - event::{ - LOS_EventInit, LOS_EventRead, LOS_EventWrite, EVENT_CB_S, LOS_WAITMODE_AND, - LOS_WAITMODE_CLR, LOS_WAITMODE_OR, - }, - sys::{self, *}, - }, + libc::c::strnlen, + libc::sys::{self, __errno_location, strerror_r}, sysinfo::LOSCFG_BASE_CORE_TICK_PER_SECOND, }; -use alloc::{ - alloc::alloc, - boxed::Box, - string::{String, ToString}, -}; +use alloc::string::{String, ToString}; #[inline(always)] pub fn errno() -> i32 { unsafe { *__errno_location() as i32 } @@ -54,43 +46,7 @@ pub fn abort() -> ! { unsafe { sys::abort() }; } -pub unsafe fn los_event_check() { - let ly = Layout::new::(); - let p = alloc(ly).cast(); - LOS_EventInit(p); - let th1 = Thread::new(1024, box move || { - for _ in 0..2 { - let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); - let tick = get_tickcount(); - printf("Task0:tick:%u;:%d\r\n\0".as_ptr(), tick, rtn); - } - }) - .unwrap_unchecked(); - - let th2 = Thread::new(1024, box move || { - for _ in 0..2 { - let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); - let tick = get_tickcount(); - printf("Task1:tick:%u;:%u\r\n\0".as_ptr(), tick, rtn); - } - }) - .unwrap_unchecked(); - - let th3 = Thread::new(1024, box move || { - for _ in 0..2 { - let rtn = LOS_EventRead(p, 1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); - let tick = get_tickcount(); - printf("Task2:tick:%u;:%u\r\n\0".as_ptr(), tick, rtn); - } - }) - .unwrap_unchecked(); - - for _ in 0..2 { - Thread::sleep(1000); - printf("send------\r\n\0".as_ptr()); - LOS_EventWrite(p, 1); - } - th1.join(); - th2.join(); - th3.join(); +#[inline(always)] +pub fn rand() -> i32 { + unsafe { libc::c::rand() } } diff --git a/src/liteos/rust.c b/src/liteos/rust.c new file mode 100644 index 0000000..29587b9 --- /dev/null +++ b/src/liteos/rust.c @@ -0,0 +1,109 @@ +#include "los_spinlock.h" +#include "los_task_pri.h" +#include "los_atomic.h" +#include "los_list.h" +#include "los_mp_pri.h" +LITE_OS_SEC_TEXT BOOL _LOS_SpinHeld(const SPIN_LOCK_S *lock) +{ + return LOS_SpinHeld(lock); +} + +LITE_OS_SEC_TEXT VOID _LOS_SpinInit(SPIN_LOCK_S *lock) +{ + LOS_SpinInit(lock); +} + +LITE_OS_SEC_TEXT VOID _LOS_SpinLock(SPIN_LOCK_S *lock) +{ + LOS_SpinLock(lock); +} + +LITE_OS_SEC_TEXT VOID _LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave) +{ + LOS_SpinLockSave(lock, intSave); +} + +LITE_OS_SEC_TEXT INT32 _LOS_SpinTrylock(SPIN_LOCK_S *lock) +{ + return LOS_SpinTrylock(lock); +} + +LITE_OS_SEC_TEXT VOID _LOS_SpinUnlock(SPIN_LOCK_S *lock) +{ + LOS_SpinUnlock(lock); +} + +LITE_OS_SEC_TEXT VOID _LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, + UINT32 intSave) +{ + LOS_SpinUnlockRestore(lock, intSave); +} + +LITE_OS_SEC_TEXT UINT32 _LOS_IntLock(VOID) +{ + return LOS_IntLock(); +} + +LITE_OS_SEC_TEXT UINT32 _LOS_IntUnLock(VOID) +{ + return LOS_IntUnLock(); +} + +LITE_OS_SEC_TEXT VOID _LOS_IntRestore(UINT32 intSave) +{ + LOS_IntRestore(intSave); +} + +LITE_OS_SEC_TEXT BOOL Futex_Wait(Atomic *futex, INT32 expected, LOS_DL_LIST *list, UINT32 timeout) +{ + UINT32 intSave; + LosTaskCB *runTask = OsCurrTaskGet(); + SCHEDULER_LOCK(intSave); + if (LOS_AtomicRead(futex) == expected) + { + OsTaskWait(list, OS_TASK_STATUS_PEND, timeout); + OsSchedResched(); + SCHEDULER_UNLOCK(intSave); + SCHEDULER_LOCK(intSave); + if (runTask->taskStatus & OS_TASK_STATUS_TIMEOUT) + { + runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT; + SCHEDULER_UNLOCK(intSave); + return false; + } + } + SCHEDULER_UNLOCK(intSave); + return true; +} + +LITE_OS_SEC_TEXT BOOL Futex_Wake(LOS_DL_LIST *list, BOOL once) +{ + LosTaskCB *resumedTask = NULL; + LosTaskCB *nextTask = NULL; + UINT8 exitFlag = 0; + UINT32 intSave; + SCHEDULER_LOCK(intSave); + if (!LOS_ListEmpty(list)) + { + for (resumedTask = LOS_DL_LIST_ENTRY(list->pstNext, LosTaskCB, pendList); + &resumedTask->pendList != list;) + { + nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList); + exitFlag++; + OsTaskWake(resumedTask, OS_TASK_STATUS_PEND); + if (once) + { + break; + } + resumedTask = nextTask; + } + } + SCHEDULER_UNLOCK(intSave); + if (exitFlag > 0) + { + LOS_MpSchedule(OS_MP_CPU_ALL); + LOS_Schedule(); + return true; + } + return false; +} diff --git a/src/liteos/thread.rs b/src/liteos/thread.rs index 4c3d8d0..1f149cc 100644 --- a/src/liteos/thread.rs +++ b/src/liteos/thread.rs @@ -52,8 +52,7 @@ impl Thread { } #[inline] pub fn yield_now() { - let ret = unsafe { sched_yield() }; - debug_assert_eq!(ret, 0); + unsafe { sched_yield() }; } #[inline] pub fn set_name(_name: &str) {} -- Gitee From 206470ea771a7f42026ace5f25a2b7fd82437304 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 10 Aug 2022 06:46:59 +0000 Subject: [PATCH 26/27] =?UTF-8?q?rust.c+=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/liteos/rust.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/liteos/rust.c b/src/liteos/rust.c index 29587b9..111c0a9 100644 --- a/src/liteos/rust.c +++ b/src/liteos/rust.c @@ -1,3 +1,5 @@ +// Copyright (C) 2022-2022 Agilor Co.,Ltd. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 #include "los_spinlock.h" #include "los_task_pri.h" #include "los_atomic.h" -- Gitee From c35293cd2e0de47159cf3c59d7bcf6dccacd6878 Mon Sep 17 00:00:00 2001 From: shuaihu Date: Wed, 10 Aug 2022 07:00:26 +0000 Subject: [PATCH 27/27] =?UTF-8?q?=E8=AD=A6=E5=91=8A=E6=B6=88=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cargo/config.toml | 6 +++--- Cargo.toml | 2 +- examples/test_liteos.rs | 8 +------- src/liteos/os.rs | 23 ++++++++--------------- 4 files changed, 13 insertions(+), 26 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 295be3e..b973bcd 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -51,6 +51,6 @@ rustflags = [ '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/Cargo.toml b/Cargo.toml index 120671f..3ee2f02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ version = "0.1.0" crate-type = ["rlib"] [features] -default = ["liteos"] +default = [] liteos = [] [dependencies] diff --git a/examples/test_liteos.rs b/examples/test_liteos.rs index 05effce..80daa20 100644 --- a/examples/test_liteos.rs +++ b/examples/test_liteos.rs @@ -6,12 +6,7 @@ #![feature(bench_black_box)] #![feature(box_syntax)] -use core::alloc::Layout; - -use alloc::{ - alloc::{alloc, dealloc}, - string::ToString, -}; +use alloc::string::ToString; use arch::os::printf; #[allow(unused_imports)] @@ -58,4 +53,3 @@ unsafe extern "C" fn app_init() { printf("RWLock frob Test\n\0".as_ptr()); frob(); } - diff --git a/src/liteos/os.rs b/src/liteos/os.rs index d84a2e4..71a7342 100644 --- a/src/liteos/os.rs +++ b/src/liteos/os.rs @@ -1,22 +1,15 @@ // Copyright (C) 2022-2022 Agilor Co.,Ltd. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -use core::{alloc::Layout, mem::MaybeUninit, str::from_utf8_unchecked}; +use core::str::from_utf8_unchecked; -use crate::thread::Thread; - -use super::libc; -use super::libc::timer::LOS_TickCountGet; - -use super::{ - libc::c::strnlen, - libc::sys::{self, __errno_location, strerror_r}, - sysinfo::LOSCFG_BASE_CORE_TICK_PER_SECOND, -}; -use alloc::{ - alloc::alloc, - boxed::Box, - string::{String, ToString}, +use super::libc::{ + self, + c::strnlen, + sys::{self, __errno_location, strerror_r}, + timer::LOS_TickCountGet, }; +use super::sysinfo::LOSCFG_BASE_CORE_TICK_PER_SECOND; +use alloc::string::{String, ToString}; #[inline(always)] pub fn errno() -> i32 { unsafe { *__errno_location() as i32 } -- Gitee