summaryrefslogtreecommitdiff
path: root/components/rust/core/src/api
diff options
context:
space:
mode:
authorzhang san <[email protected]>2025-12-08 18:34:25 +0800
committerGitHub <[email protected]>2025-12-08 18:34:25 +0800
commit69980f8b9d29b38dbd4ddf6373b4b45f3a138409 (patch)
tree21dd9a8ce80e3d30192e9ffa56ea39a199bae309 /components/rust/core/src/api
parentcd1d47b87c5d47e131730e5506eb3ad77d357653 (diff)
Adding Rust Language Support for RT-Thread #10910
Diffstat (limited to 'components/rust/core/src/api')
-rw-r--r--components/rust/core/src/api/base.rs78
-rw-r--r--components/rust/core/src/api/interrupt.rs69
-rw-r--r--components/rust/core/src/api/libloading.rs238
-rw-r--r--components/rust/core/src/api/mem.rs79
-rw-r--r--components/rust/core/src/api/mod.rs27
-rw-r--r--components/rust/core/src/api/mutex.rs48
-rw-r--r--components/rust/core/src/api/queue.rs56
-rw-r--r--components/rust/core/src/api/sem.rs51
-rw-r--r--components/rust/core/src/api/thread.rs97
9 files changed, 743 insertions, 0 deletions
diff --git a/components/rust/core/src/api/base.rs b/components/rust/core/src/api/base.rs
new file mode 100644
index 0000000000..fabb00d5ba
--- /dev/null
+++ b/components/rust/core/src/api/base.rs
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author notes
+ * 2025-10-10 foxglove latest version
+ */
+use crate::bindings::*;
+
+/* Error type from rt-thread C code */
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub enum RttCResult {
+ Ok = RT_EOK as isize,
+ Error = -(RT_ERROR as isize),
+ TimeOut = -(RT_ETIMEOUT as isize),
+ Full = -(RT_EFULL as isize),
+ Empty = -(RT_EEMPTY as isize),
+ NoMem = -(RT_ENOMEM as isize),
+ NoSys = -(RT_ENOSYS as isize),
+ Busy = -(RT_EBUSY as isize),
+ IO = -(RT_EIO as isize),
+ INTR = -(RT_EINTR as isize),
+ INVAL = -(RT_EINVAL as isize),
+
+ NotValidCode = -100,
+}
+/* NOTE Match to `enum Error` */
+impl From<i32> for RttCResult {
+ fn from(a: i32) -> Self {
+ let ret = match a {
+ 0 => RttCResult::Ok,
+ -1 => RttCResult::Error,
+ -2 => RttCResult::TimeOut,
+ -3 => RttCResult::Full,
+ -4 => RttCResult::Empty,
+ -5 => RttCResult::NoMem,
+ -6 => RttCResult::NoSys,
+ -7 => RttCResult::Busy,
+ -8 => RttCResult::IO,
+ -9 => RttCResult::INTR,
+ -10 => RttCResult::INVAL,
+ _ => RttCResult::NotValidCode,
+ };
+ ret
+ }
+}
+
+impl From<i64> for RttCResult {
+ fn from(a: i64) -> Self {
+ if a >= 0 {
+ RttCResult::Ok
+ } else {
+ match a {
+ -1 => RttCResult::Error,
+ -2 => RttCResult::TimeOut,
+ -3 => RttCResult::Full,
+ -4 => RttCResult::Empty,
+ -5 => RttCResult::NoMem,
+ -6 => RttCResult::NoSys,
+ -7 => RttCResult::Busy,
+ -8 => RttCResult::IO,
+ -9 => RttCResult::INTR,
+ -10 => RttCResult::INVAL,
+ _ => RttCResult::NotValidCode,
+ }
+ }
+ }
+}
+
+pub fn is_eok(val: RttCResult) -> bool {
+ if let RttCResult::Ok = val {
+ true
+ } else {
+ false
+ }
+}
diff --git a/components/rust/core/src/api/interrupt.rs b/components/rust/core/src/api/interrupt.rs
new file mode 100644
index 0000000000..9a62442cb9
--- /dev/null
+++ b/components/rust/core/src/api/interrupt.rs
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author notes
+ * 2025-10-10 foxglove latest version
+ */
+use crate::bindings::*;
+
+#[cfg(not(feature = "smp"))]
+unsafe fn irq_close() -> rt_base_t {
+ rt_hw_interrupt_disable()
+}
+#[cfg(feature = "smp")]
+unsafe fn irq_close() -> rt_base_t {
+ rt_cpus_lock()
+}
+
+#[cfg(not(feature = "smp"))]
+unsafe fn irq_open(f: rt_base_t) {
+ rt_hw_interrupt_enable(f)
+}
+#[cfg(feature = "smp")]
+unsafe fn irq_open(f: rt_base_t) {
+ rt_cpus_unlock(f)
+}
+
+pub fn no_irq<F, T>(f: F) -> T
+where
+ F: FnOnce() -> T,
+{
+ let level;
+ let out;
+ unsafe { level = irq_close() }
+ out = f();
+ unsafe { irq_open(level) }
+ out
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct InterruptFlag(rt_base_t);
+
+pub const INTERRUPT_FLAG_INIT: InterruptFlag = InterruptFlag { 0: 0 as _ };
+
+pub fn interrupt_disable() -> InterruptFlag {
+ unsafe { InterruptFlag(irq_close()) }
+}
+
+pub fn interrupt_enable(f: InterruptFlag) {
+ unsafe { irq_open(f.0) }
+}
+
+pub fn interrupt_enter() {
+ unsafe {
+ rt_interrupt_enter();
+ }
+}
+
+pub fn interrupt_leave() {
+ unsafe {
+ rt_interrupt_leave();
+ }
+}
+
+pub fn is_irq_context() -> bool {
+ unsafe { rt_interrupt_get_nest() != 0 }
+} \ No newline at end of file
diff --git a/components/rust/core/src/api/libloading.rs b/components/rust/core/src/api/libloading.rs
new file mode 100644
index 0000000000..438f1fb40b
--- /dev/null
+++ b/components/rust/core/src/api/libloading.rs
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2025-10-14 foxglove libdl safe wrapper (libloading-like)
+ */
+
+/*! Minimal `libloading`-style safe wrapper around RT-Thread libdl.
+Provides RAII `Library` and typed `Symbol<T>` for dlsym.
+*/
+
+extern crate alloc;
+
+use core::ffi::{c_char, c_int, c_void};
+use core::ffi::CStr;
+use core::marker::PhantomData;
+use core::mem::forget;
+use core::ops::Deref;
+
+use alloc::ffi::CString;
+use alloc::vec::Vec;
+
+use crate::bindings::libc;
+
+pub use crate::bindings::libc::{RTLD_GLOBAL, RTLD_LAZY, RTLD_LOCAL, RTLD_NOW};
+
+/* Error type for dynamic loading operations */
+pub enum DlError {
+ /* dlopen failed; contains last error C-string pointer */
+ Open(*const c_char),
+ /* dlsym failed; contains last error C-string pointer */
+ Symbol(*const c_char),
+ /* dlclose returned non-zero; contains return code */
+ Close(c_int),
+}
+
+impl core::fmt::Debug for DlError {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::Display::fmt(self, f)
+ }
+}
+
+impl core::fmt::Display for DlError {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ match self {
+ &DlError::Open(ptr) | &DlError::Symbol(ptr) => {
+ if ptr.is_null() {
+ write!(f, "[libdl open/sym error: none]")
+ } else {
+ unsafe {
+ // `ptr` is a raw C string pointer
+ let cstr = CStr::from_ptr(ptr);
+ match cstr.to_str() {
+ Ok(s) => write!(f, "{}", s),
+ Err(_) => write!(f, "[libdl error: invalid UTF-8]")
+ }
+ }
+ }
+ }
+ DlError::Close(rc) => write!(f, "dlclose rc={}", rc),
+ }
+ }
+}
+
+/* RAII wrapper for a `dlopen` handle */
+pub struct Library {
+ handle: *mut c_void,
+}
+
+impl Library {
+ /* Create a new library using default flags (`RTLD_NOW | RTLD_GLOBAL`).
+ * Accepts a Rust string path and converts internally to a C string.
+ */
+ pub fn new(path: &str) -> Result<Self, DlError> {
+ let cstr = match CString::new(path) {
+ Ok(s) => s,
+ Err(_) => {
+ return Err(DlError::Open(core::ptr::null()));
+ }
+ };
+ unsafe { Self::open_global(cstr.as_ptr()) }
+ }
+ /* Open a dynamic module with given flags
+ * Safety: `path` must be a valid, NUL-terminated C string pointer
+ */
+ pub unsafe fn open(path: *const c_char, flags: c_int) -> Result<Self, DlError> {
+ let h = libc::dlopen(path, flags);
+ if h.is_null() {
+ Err(DlError::Open(libc::last_error_ptr()))
+ } else {
+ Ok(Library { handle: h })
+ }
+ }
+
+ /* Convenience open using `RTLD_NOW | RTLD_GLOBAL` */
+ pub unsafe fn open_global(path: *const c_char) -> Result<Self, DlError> {
+ Self::open(path, RTLD_NOW | RTLD_GLOBAL)
+ }
+
+ /* Resolve a typed symbol from the library using a C string pointer.
+ * Safety: Caller must ensure `T` matches the actual symbol type and `symbol` is NUL-terminated.
+ */
+ pub unsafe fn get_ptr<T>(&self, symbol: *const c_char) -> Result<Symbol<'_, T>, DlError> {
+ let sym = libc::dlsym(self.handle, symbol);
+ if sym.is_null() {
+ Err(DlError::Symbol(libc::last_error_ptr()))
+ } else {
+ Ok(Symbol {
+ raw: sym,
+ _lib: PhantomData,
+ _ty: PhantomData,
+ })
+ }
+ }
+
+ /* Resolve a typed symbol from the library using a byte slice name.
+ * If the slice is not NUL-terminated, a temporary buffer is allocated.
+ */
+ pub fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<'_, T>, DlError> {
+ let (ptr, _guard_buf): (*const c_char, Option<Vec<u8>>) = if symbol.last().copied() == Some(0) {
+ (symbol.as_ptr() as *const c_char, None)
+ } else {
+ let mut buf = Vec::with_capacity(symbol.len() + 1);
+ buf.extend_from_slice(symbol);
+ buf.push(0);
+ (buf.as_ptr() as *const c_char, Some(buf))
+ };
+ let sym = unsafe { libc::dlsym(self.handle, ptr) };
+ if sym.is_null() {
+ Err(DlError::Symbol(libc::last_error_ptr()))
+ } else {
+ Ok(Symbol {
+ raw: sym,
+ _lib: PhantomData,
+ _ty: PhantomData,
+ })
+ }
+ }
+
+ /* Check if handle is null */
+ pub fn is_null(&self) -> bool {
+ self.handle.is_null()
+ }
+
+ /* Consume and close the library explicitly */
+ pub unsafe fn close(self) -> Result<(), DlError> {
+ let h = self.handle;
+ forget(self);
+ let rc = libc::dlclose(h);
+ if rc == 1 {
+ Ok(())
+ } else {
+ Err(DlError::Close(rc))
+ }
+ }
+
+ /* Leak the handle out (caller manages lifetime) */
+ pub unsafe fn into_raw(self) -> *mut c_void {
+ let h = self.handle;
+ forget(self);
+ h
+ }
+}
+
+impl Drop for Library {
+ fn drop(&mut self) {
+ unsafe {
+ if !self.handle.is_null() {
+ let _ = libc::dlclose(self.handle);
+ self.handle = core::ptr::null_mut();
+ }
+ }
+ }
+}
+
+/* RAII wrapper for a symbol tied to a `Library` lifetime.
+ * Stores the raw pointer and performs typed conversion at the use site.
+ */
+pub struct Symbol<'lib, T> {
+ raw: *mut c_void,
+ _lib: PhantomData<&'lib Library>,
+ _ty: PhantomData<T>,
+}
+
+impl<'lib, T> Symbol<'lib, T> {
+ /* Check if the underlying pointer is null */
+ pub fn is_null(&self) -> bool {
+ self.raw.is_null()
+ }
+
+ /* Get the raw pointer as `*mut c_void` */
+ pub fn as_raw(&self) -> *mut c_void {
+ self.raw
+ }
+
+ /* Cast the raw pointer to a different pointer type
+ * Safety: Caller must ensure `U` is the correct target type.
+ */
+ pub unsafe fn as_ptr<U>(&self) -> *mut U {
+ self.raw as *mut U
+ }
+
+ /* Convert to the typed value (e.g., function pointer) at use site
+ Safety: `T` must be the correct type for the symbol.
+ */
+ pub unsafe fn to_value(&self) -> T
+ where
+ T: Sized + Copy,
+ {
+ // Bitwise-copy the pointer value into a `T` without using `transmute`.
+ // This relies on `T` (e.g., extern "C" fn ...) having the same representation size.
+ let src: *const T = (&self.raw as *const *mut c_void) as *const T;
+ core::ptr::read(src)
+ }
+
+ pub fn into_raw(self) -> *mut c_void {
+ let p = self.raw;
+ forget(self);
+ p
+ }
+}
+
+impl<'lib, T> Deref for Symbol<'lib, T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ /* Reinterpret the `raw` pointer storage as a value of type `T`. */
+ /* Safety: This is safe if `T` is a pointer-sized function pointer or compatible pointer type. */
+ unsafe { &*((&self.raw as *const *mut c_void) as *const T) }
+ }
+}
+
+#[inline]
+pub fn last_error() -> *const c_char {
+ libc::last_error_ptr()
+}
diff --git a/components/rust/core/src/api/mem.rs b/components/rust/core/src/api/mem.rs
new file mode 100644
index 0000000000..8b998f77c3
--- /dev/null
+++ b/components/rust/core/src/api/mem.rs
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2025-10-10 foxglove memory management API
+ */
+
+use crate::bindings::*;
+use core::ffi::c_void;
+
+pub fn mem_alloc(bytes: usize) -> Option<*mut c_void> {
+ if bytes == 0 {
+ return None;
+ }
+
+ let ptr = unsafe { rt_malloc(bytes as rt_size_t) };
+ if ptr.is_null() {
+ None
+ } else {
+ Some(ptr)
+ }
+}
+
+pub fn mem_calloc(count: usize, size: usize) -> Option<*mut c_void> {
+ if count == 0 || size == 0 {
+ return None;
+ }
+
+ let ptr = unsafe { rt_calloc(count as rt_size_t, size as rt_size_t) };
+ if ptr.is_null() {
+ None
+ } else {
+ Some(ptr)
+ }
+}
+
+pub fn mem_alloc_aligned(bytes: usize, align: usize) -> Option<*mut c_void> {
+ if bytes == 0 || align == 0 || !align.is_power_of_two() {
+ return None;
+ }
+
+ let ptr = unsafe { rt_malloc_align(bytes as rt_size_t, align as rt_size_t) };
+ if ptr.is_null() {
+ None
+ } else {
+ Some(ptr)
+ }
+}
+
+pub fn mem_realloc(ptr: *mut c_void, new_size: usize) -> Option<*mut c_void> {
+ if new_size == 0 {
+ if !ptr.is_null() {
+ mem_free(ptr);
+ }
+ return None;
+ }
+
+ let new_ptr = unsafe { rt_realloc(ptr, new_size as rt_size_t) };
+ if new_ptr.is_null() {
+ None
+ } else {
+ Some(new_ptr)
+ }
+}
+
+pub fn mem_free(ptr: *mut c_void) {
+ if !ptr.is_null() {
+ unsafe { rt_free(ptr) };
+ }
+}
+
+pub fn mem_free_aligned(ptr: *mut c_void) {
+ if !ptr.is_null() {
+ unsafe { rt_free_align(ptr) };
+ }
+}
diff --git a/components/rust/core/src/api/mod.rs b/components/rust/core/src/api/mod.rs
new file mode 100644
index 0000000000..8fc2ba2301
--- /dev/null
+++ b/components/rust/core/src/api/mod.rs
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author notes
+ * 2025-10-10 foxglove API module
+ */
+pub mod base;
+pub mod interrupt;
+pub mod mem;
+pub mod thread;
+pub mod mutex;
+pub mod sem;
+pub mod queue;
+pub mod libloading;
+
+
+pub use base::*;
+pub use interrupt::*;
+pub use mem::*;
+pub use thread::*;
+pub use mutex::*;
+pub use sem::*;
+pub use queue::*;
+pub use libloading::*;
diff --git a/components/rust/core/src/api/mutex.rs b/components/rust/core/src/api/mutex.rs
new file mode 100644
index 0000000000..176e02e2e7
--- /dev/null
+++ b/components/rust/core/src/api/mutex.rs
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author notes
+ * 2025-10-10 foxglove Mutex API
+ */
+use crate::api::RttCResult;
+use crate::bindings::*;
+use core::ptr;
+use alloc::ffi::CString;
+
+pub type APIRawMutex = rt_mutex_t;
+
+#[inline]
+pub fn mutex_create(name: &str) -> Option<APIRawMutex> {
+ let s = CString::new(name).unwrap();
+ let raw;
+ unsafe {
+ raw = rt_mutex_create(s.as_ptr(), 1);
+ }
+ if raw == ptr::null_mut() {
+ None
+ } else {
+ Some(raw)
+ }
+}
+
+#[inline]
+pub fn mutex_delete(handle: APIRawMutex) {
+ unsafe {
+ rt_mutex_delete(handle);
+ }
+}
+
+#[inline]
+pub fn mutex_take(handle: APIRawMutex, tick: isize) -> RttCResult {
+ unsafe { rt_mutex_take(handle, tick as _).into() }
+}
+
+#[inline]
+pub fn mutex_release(handle: APIRawMutex) {
+ unsafe {
+ rt_mutex_release(handle);
+ }
+}
diff --git a/components/rust/core/src/api/queue.rs b/components/rust/core/src/api/queue.rs
new file mode 100644
index 0000000000..96665e47f2
--- /dev/null
+++ b/components/rust/core/src/api/queue.rs
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author notes
+ * 2025-10-10 foxglove Queue API
+ */
+
+use crate::api::RttCResult;
+use core::ffi::c_void;
+use crate::bindings::*;
+use core::ptr;
+use alloc::ffi::CString;
+
+pub type APIRawQueue = rt_mq_t;
+
+#[inline]
+pub(crate) fn queue_create(name: &str, len: u64, message_size: u64) -> Option<APIRawQueue> {
+ let s = CString::new(name).unwrap();
+ let raw;
+ unsafe { raw = rt_mq_create(s.as_ptr(), message_size, len, 0) }
+ if raw == ptr::null_mut() {
+ None
+ } else {
+ Some(raw)
+ }
+}
+
+#[inline]
+pub(crate) fn queue_send_wait(
+ handle: APIRawQueue,
+ msg: *const c_void,
+ msg_size: u64,
+ tick: i32,
+) -> RttCResult {
+ unsafe { rt_mq_send_wait(handle, msg, msg_size, tick).into() }
+}
+
+#[inline]
+pub(crate) fn queue_receive_wait(
+ handle: APIRawQueue,
+ msg: *mut c_void,
+ msg_size: u64,
+ tick: i32,
+) -> RttCResult {
+ unsafe { rt_mq_recv(handle, msg, msg_size, tick).into() }
+}
+
+#[inline]
+pub(crate) fn queue_delete(handle: APIRawQueue) {
+ unsafe {
+ rt_mq_delete(handle);
+ }
+}
diff --git a/components/rust/core/src/api/sem.rs b/components/rust/core/src/api/sem.rs
new file mode 100644
index 0000000000..43c21978d2
--- /dev/null
+++ b/components/rust/core/src/api/sem.rs
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author notes
+ * 2025-10-10 foxglove Semaphore API
+ */
+use crate::api::RttCResult;
+use crate::bindings::*;
+use core::ptr;
+use alloc::ffi::CString;
+
+pub type APIRawSem = rt_sem_t;
+
+ #[inline]
+pub(crate) fn semaphore_create(name: &str) -> Option<APIRawSem> {
+ let s = CString::new(name).unwrap();
+ let raw;
+ unsafe {
+ raw = rt_sem_create(s.as_ptr(), 0, 0);
+ }
+ return if raw == ptr::null_mut() {
+ None
+ } else {
+ Some(raw)
+ };
+}
+
+ #[inline]
+pub(crate) fn semaphore_try_take(handle: APIRawSem) -> RttCResult {
+ unsafe { rt_sem_trytake(handle).into() }
+}
+
+ #[inline]
+pub(crate) fn semaphore_take(handle: APIRawSem, tick: u32) -> RttCResult {
+ unsafe { rt_sem_take(handle, tick).into() }
+}
+
+ #[inline]
+pub(crate) fn semaphore_release(handle: APIRawSem) -> RttCResult {
+ unsafe { rt_sem_release(handle).into() }
+}
+
+ #[inline]
+pub(crate) fn semaphore_delete(handle: APIRawSem) {
+ unsafe {
+ let _ = rt_sem_delete(handle);
+ }
+}
diff --git a/components/rust/core/src/api/thread.rs b/components/rust/core/src/api/thread.rs
new file mode 100644
index 0000000000..d8b1ed295b
--- /dev/null
+++ b/components/rust/core/src/api/thread.rs
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author notes
+ * 2025-10-10 foxglove Thread API
+ */
+use super::base::*;
+use crate::bindings::*;
+use core::ptr;
+use core::ffi::c_void;
+use alloc::ffi::CString;
+
+/* Thread handle, defined by RT-Thread C code */
+pub type APIRawThread = rt_thread_t;
+/* Thread entry function, defined by RT-Thread C code */
+pub type ThreadEntry = extern "C" fn(parameter: *mut c_void);
+
+#[inline]
+pub fn thread_create(
+ name: &str,
+ entry: ThreadEntry,
+ param: *mut c_void,
+ stack_size: u32,
+ priority: u8,
+ tick: u32,
+) -> Option<APIRawThread> {
+ let name = CString::new(name).unwrap();
+ let raw;
+ unsafe {
+ raw = rt_thread_create(
+ name.as_ptr(),
+ entry,
+ param,
+ stack_size as crate::bindings::librt::rt_size_t,
+ priority,
+ tick,
+ );
+ }
+ if raw == ptr::null_mut() {
+ None
+ } else {
+ Some(raw)
+ }
+}
+
+#[inline]
+pub fn thread_delete(th: APIRawThread) -> RttCResult {
+ unsafe { rt_thread_delete(th).into() }
+}
+
+#[inline]
+pub fn thread_self() -> Option<APIRawThread> {
+ let ret;
+ unsafe {
+ ret = rt_thread_self();
+ }
+ if ret == ptr::null_mut() {
+ None
+ } else {
+ Some(ret)
+ }
+}
+
+#[inline]
+pub fn thread_startup(th: APIRawThread) -> RttCResult {
+ unsafe { rt_thread_startup(th).into() }
+}
+
+#[inline]
+pub fn thread_delay(ticks: usize) -> RttCResult {
+ unsafe { rt_thread_delay(ticks as _).into() }
+}
+
+#[inline]
+pub fn thread_m_delay(ms: i32) -> RttCResult {
+ unsafe { rt_thread_mdelay(ms as _).into() }
+}
+
+#[inline]
+pub fn thread_yield() {
+ unsafe {
+ rt_thread_yield();
+ }
+}
+
+#[inline]
+pub fn thread_suspend(th: APIRawThread) -> RttCResult {
+ unsafe { rt_thread_suspend(th).into() }
+}
+
+#[inline]
+pub fn thread_resume(th: APIRawThread) -> RttCResult {
+ unsafe { rt_thread_resume(th).into() }
+}