zephyr/
sys.rs

1// Copyright (c) 2024 Linaro LTD
2// SPDX-License-Identifier: Apache-2.0
3
4//! Zephyr 'sys' module.
5//!
6//! The `zephyr-sys` crate contains the direct C bindings to the Zephyr API.  All of these are
7//! unsafe.
8//!
9//! This module `zephyr::sys` contains thin wrappers to these C bindings, that can be used without
10//! unsafe, but as unchanged as possible.
11
12use zephyr_sys::k_timeout_t;
13
14pub mod queue;
15pub mod sync;
16pub mod thread;
17
18// These two constants are not able to be captured by bindgen.  It is unlikely that these values
19// would change in the Zephyr headers, but there will be an explicit test to make sure they are
20// correct.
21
22/// Represents a timeout with an infinite delay.
23///
24/// Low-level Zephyr constant.  Calls using this value will wait as long as necessary to perform
25/// the requested operation.
26pub const K_FOREVER: k_timeout_t = k_timeout_t { ticks: -1 };
27
28/// Represents a null timeout delay.
29///
30/// Low-level Zephyr Constant.  Calls using this value will not wait if the operation cannot be
31/// performed immediately.
32pub const K_NO_WAIT: k_timeout_t = k_timeout_t { ticks: 0 };
33
34/// Return the current uptime of the system in ms.
35///
36/// Direct Zephyr call.  Precision is limited by the system tick timer.
37#[inline]
38pub fn uptime_get() -> i64 {
39    unsafe { crate::raw::k_uptime_get() }
40}
41
42// The below implementation, based on interrupt locking has only been tested on single CPU.  The
43// implementation suggests it should work on SMP, and can be tested.  The docs for irq_lock()
44// explicitly state that it cannot be used from userspace. Unfortunately, spinlocks have
45// incompatible semantics with critical sections, so to work with userspace we'd need probably a
46// syscall.
47#[cfg(CONFIG_USERSPACE)]
48compile_error!("Critical-section implementation does not work with CONFIG_USERSPACE");
49
50pub mod critical {
51    //! Zephyr implementation of critical sections.
52    //!
53    //! The critical-section crate explicitly states that critical sections can be nested.
54    //! Unfortunately, Zephyr spinlocks cannot be nested.  It is possible to nest different ones,
55    //! but the critical-section implementation API doesn't give access to the stack.
56
57    use core::{
58        ffi::c_int,
59        sync::atomic::{fence, Ordering},
60    };
61
62    use critical_section::RawRestoreState;
63    use zephyr_sys::{zr_irq_lock, zr_irq_unlock};
64
65    struct ZephyrCriticalSection;
66    critical_section::set_impl!(ZephyrCriticalSection);
67
68    unsafe impl critical_section::Impl for ZephyrCriticalSection {
69        unsafe fn acquire() -> RawRestoreState {
70            let res = zr_irq_lock();
71            fence(Ordering::Acquire);
72            res as RawRestoreState
73        }
74
75        unsafe fn release(token: RawRestoreState) {
76            fence(Ordering::Release);
77            zr_irq_unlock(token as c_int);
78        }
79    }
80}