mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
Rust changes for v6.15
Toolchain and infrastructure: - Extract the 'pin-init' API from the 'kernel' crate and make it into a standalone crate. In order to do this, the contents are rearranged so that they can easily be kept in sync with the version maintained out-of-tree that other projects have started to use too (or plan to, like QEMU). This will reduce the maintenance burden for Benno, who will now have his own sub-tree, and will simplify future expected changes like the move to use 'syn' to simplify the implementation. - Add '#[test]'-like support based on KUnit. We already had doctests support based on KUnit, which takes the examples in our Rust documentation and runs them under KUnit. Now, we are adding the beginning of the support for "normal" tests, similar to those the '#[test]' tests in userspace Rust. For instance: #[kunit_tests(my_suite)] mod tests { #[test] fn my_test() { assert_eq!(1 + 1, 2); } } Unlike with doctests, the 'assert*!'s do not map to the KUnit assertion APIs yet. - Check Rust signatures at compile time for functions called from C by name. In particular, introduce a new '#[export]' macro that can be placed in the Rust function definition. It will ensure that the function declaration on the C side matches the signature on the Rust function: #[export] pub unsafe extern "C" fn my_function(a: u8, b: i32) -> usize { // ... } The macro essentially forces the compiler to compare the types of the actual Rust function and the 'bindgen'-processed C signature. These cases are rare so far. In the future, we may consider introducing another tool, 'cbindgen', to generate C headers automatically. Even then, having these functions explicitly marked may be a good idea anyway. - Enable the 'raw_ref_op' Rust feature: it is already stable, and allows us to use the new '&raw' syntax, avoiding a couple macros. After everyone has migrated, we will disallow the macros. - Pass the correct target to 'bindgen' on Usermode Linux. - Fix 'rusttest' build in macOS. 'kernel' crate: - New 'hrtimer' module: add support for setting up intrusive timers without allocating when starting the timer. Add support for 'Pin<Box<_>>', 'Arc<_>', 'Pin<&_>' and 'Pin<&mut _>' as pointer types for use with timer callbacks. Add support for setting clock source and timer mode. - New 'dma' module: add a simple DMA coherent allocator abstraction and a test sample driver. - 'list' module: make the linked list 'Cursor' point between elements, rather than at an element, which is more convenient to us and allows for cursors to empty lists; and document it with examples of how to perform common operations with the provided methods. - 'str' module: implement a few traits for 'BStr' as well as the 'strip_prefix()' method. - 'sync' module: add 'Arc::as_ptr'. - 'alloc' module: add 'Box::into_pin'. - 'error' module: extend the 'Result' documentation, including a few examples on different ways of handling errors, a warning about using methods that may panic, and links to external documentation. 'macros' crate: - 'module' macro: add the 'authors' key to support multiple authors. The original key will be kept until everyone has migrated. Documentation: - Add error handling sections. MAINTAINERS: - Add Danilo Krummrich as reviewer of the Rust "subsystem". - Add 'RUST [PIN-INIT]' entry with Benno Lossin as maintainer. It has its own sub-tree. - Add sub-tree for 'RUST [ALLOC]'. - Add 'DMA MAPPING HELPERS DEVICE DRIVER API [RUST]' entry with Abdiel Janulgue as primary maintainer. It will go through the sub-tree of the 'RUST [ALLOC]' entry. - Add 'HIGH-RESOLUTION TIMERS [RUST]' entry with Andreas Hindborg as maintainer. It has its own sub-tree. And a few other cleanups and improvements. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPjU5OPd5QIZ9jqqOGXyLc2htIW0FAmfpQgAACgkQGXyLc2ht IW35CQ//VOIFKtG6qgHVMIxrmpT7YFsrAU41h+cHT2lzy5KiTqSYlCgd18SJ+Iyy vi1ylfdyqOpH5EoO+opPN2H4E+VUlRJg7BkZrT4p1lgGDEKg1mtR/825TxquLNFM A653f3FvK/scMb6X43kWNKGK/jnxlfxBGmUwIY4/p7+adIuZzXnNbPkV9XYGLx3r 8KIBKJ9gM52eXoCoF8XJpg6Vg/0rYWIet32OzYF0PvzSAOqUlH4keu15jeUo+59V tgCzAkc2yV3oSo721KYlpPeCPKI5iVCzIcwT0n8fqraXtgGnaFPe5XF16U9Qvrjv vRp5/dePAHwsOcj5ErzOgLMqGa1sqY76lxDI05PNcBJ8fBAhNEV/rpCTXs/wRagQ xUZOdsQyEn0V/BOtV+dnwu410dElEeJdOAeojSYFm1gUay43a0e6yIboxn3Ylnfx 8jONSokZ/UFHX3wOFNqHeXsY+REB8Qq8OZXjNBZVFpKHNsICWA0G3BcCRnB1815k 0v7seSdrST78EJ/A5nM0a9gghuLzYgAN04SDx0FzKjb2mHs3PiVfXDvrNMCJ0pBW zbF9RlvszKZStY5tpxdZ5Zh+f7rfYcnJHYhNpoP7DJr136iWP+NnHbk1lK6+o4WY lPVdMMgUSUlEXIHgK2ebcb/I1KBrDYiPktmvKAFLrH3qVzhkLAU= =PCxf -----END PGP SIGNATURE----- Merge tag 'rust-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux Pull Rust updates from Miguel Ojeda: "Toolchain and infrastructure: - Extract the 'pin-init' API from the 'kernel' crate and make it into a standalone crate. In order to do this, the contents are rearranged so that they can easily be kept in sync with the version maintained out-of-tree that other projects have started to use too (or plan to, like QEMU). This will reduce the maintenance burden for Benno, who will now have his own sub-tree, and will simplify future expected changes like the move to use 'syn' to simplify the implementation. - Add '#[test]'-like support based on KUnit. We already had doctests support based on KUnit, which takes the examples in our Rust documentation and runs them under KUnit. Now, we are adding the beginning of the support for "normal" tests, similar to those the '#[test]' tests in userspace Rust. For instance: #[kunit_tests(my_suite)] mod tests { #[test] fn my_test() { assert_eq!(1 + 1, 2); } } Unlike with doctests, the 'assert*!'s do not map to the KUnit assertion APIs yet. - Check Rust signatures at compile time for functions called from C by name. In particular, introduce a new '#[export]' macro that can be placed in the Rust function definition. It will ensure that the function declaration on the C side matches the signature on the Rust function: #[export] pub unsafe extern "C" fn my_function(a: u8, b: i32) -> usize { // ... } The macro essentially forces the compiler to compare the types of the actual Rust function and the 'bindgen'-processed C signature. These cases are rare so far. In the future, we may consider introducing another tool, 'cbindgen', to generate C headers automatically. Even then, having these functions explicitly marked may be a good idea anyway. - Enable the 'raw_ref_op' Rust feature: it is already stable, and allows us to use the new '&raw' syntax, avoiding a couple macros. After everyone has migrated, we will disallow the macros. - Pass the correct target to 'bindgen' on Usermode Linux. - Fix 'rusttest' build in macOS. 'kernel' crate: - New 'hrtimer' module: add support for setting up intrusive timers without allocating when starting the timer. Add support for 'Pin<Box<_>>', 'Arc<_>', 'Pin<&_>' and 'Pin<&mut _>' as pointer types for use with timer callbacks. Add support for setting clock source and timer mode. - New 'dma' module: add a simple DMA coherent allocator abstraction and a test sample driver. - 'list' module: make the linked list 'Cursor' point between elements, rather than at an element, which is more convenient to us and allows for cursors to empty lists; and document it with examples of how to perform common operations with the provided methods. - 'str' module: implement a few traits for 'BStr' as well as the 'strip_prefix()' method. - 'sync' module: add 'Arc::as_ptr'. - 'alloc' module: add 'Box::into_pin'. - 'error' module: extend the 'Result' documentation, including a few examples on different ways of handling errors, a warning about using methods that may panic, and links to external documentation. 'macros' crate: - 'module' macro: add the 'authors' key to support multiple authors. The original key will be kept until everyone has migrated. Documentation: - Add error handling sections. MAINTAINERS: - Add Danilo Krummrich as reviewer of the Rust "subsystem". - Add 'RUST [PIN-INIT]' entry with Benno Lossin as maintainer. It has its own sub-tree. - Add sub-tree for 'RUST [ALLOC]'. - Add 'DMA MAPPING HELPERS DEVICE DRIVER API [RUST]' entry with Abdiel Janulgue as primary maintainer. It will go through the sub-tree of the 'RUST [ALLOC]' entry. - Add 'HIGH-RESOLUTION TIMERS [RUST]' entry with Andreas Hindborg as maintainer. It has its own sub-tree. And a few other cleanups and improvements" * tag 'rust-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (71 commits) rust: dma: add `Send` implementation for `CoherentAllocation` rust: macros: fix `make rusttest` build on macOS rust: block: refactor to use `&raw mut` rust: enable `raw_ref_op` feature rust: uaccess: name the correct function rust: rbtree: fix comments referring to Box instead of KBox rust: hrtimer: add maintainer entry rust: hrtimer: add clocksource selection through `ClockId` rust: hrtimer: add `HrTimerMode` rust: hrtimer: implement `HrTimerPointer` for `Pin<Box<T>>` rust: alloc: add `Box::into_pin` rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&mut T>` rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&T>` rust: hrtimer: add `hrtimer::ScopedHrTimerPointer` rust: hrtimer: add `UnsafeHrTimerPointer` rust: hrtimer: allow timer restart from timer handler rust: str: implement `strip_prefix` for `BStr` rust: str: implement `AsRef<BStr>` for `[u8]` and `BStr` rust: str: implement `Index` for `BStr` rust: str: implement `PartialEq` for `BStr` ...
This commit is contained in:
commit
4e82c87058
@ -373,3 +373,11 @@ triggered due to non-local changes (such as ``dead_code``).
|
||||
For more information about diagnostics in Rust, please see:
|
||||
|
||||
https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html
|
||||
|
||||
Error handling
|
||||
--------------
|
||||
|
||||
For some background and guidelines about Rust for Linux specific error handling,
|
||||
please see:
|
||||
|
||||
https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust
|
||||
|
@ -123,6 +123,13 @@ A current limitation is that KUnit does not support assertions in other tasks.
|
||||
Thus, we presently simply print an error to the kernel log if an assertion
|
||||
actually failed. Additionally, doctests are not run for nonpublic functions.
|
||||
|
||||
Since these tests are examples, i.e. they are part of the documentation, they
|
||||
should generally be written like "real code". Thus, for example, instead of
|
||||
using ``unwrap()`` or ``expect()``, use the ``?`` operator. For more background,
|
||||
please see:
|
||||
|
||||
https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust
|
||||
|
||||
The ``#[test]`` tests
|
||||
---------------------
|
||||
|
||||
|
44
MAINTAINERS
44
MAINTAINERS
@ -6981,6 +6981,19 @@ F: include/linux/dma-mapping.h
|
||||
F: include/linux/swiotlb.h
|
||||
F: kernel/dma/
|
||||
|
||||
DMA MAPPING HELPERS DEVICE DRIVER API [RUST]
|
||||
M: Abdiel Janulgue <abdiel.janulgue@gmail.com>
|
||||
M: Danilo Krummrich <dakr@kernel.org>
|
||||
R: Daniel Almeida <daniel.almeida@collabora.com>
|
||||
R: Robin Murphy <robin.murphy@arm.com>
|
||||
R: Andreas Hindborg <a.hindborg@kernel.org>
|
||||
L: rust-for-linux@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://rust-for-linux.com
|
||||
T: git https://github.com/Rust-for-Linux/linux.git alloc-next
|
||||
F: rust/kernel/dma.rs
|
||||
F: samples/rust/rust_dma.rs
|
||||
|
||||
DMA-BUF HEAPS FRAMEWORK
|
||||
M: Sumit Semwal <sumit.semwal@linaro.org>
|
||||
R: Benjamin Gaignard <benjamin.gaignard@collabora.com>
|
||||
@ -10539,6 +10552,21 @@ F: kernel/time/timer_list.c
|
||||
F: kernel/time/timer_migration.*
|
||||
F: tools/testing/selftests/timers/
|
||||
|
||||
HIGH-RESOLUTION TIMERS [RUST]
|
||||
M: Andreas Hindborg <a.hindborg@kernel.org>
|
||||
R: Boqun Feng <boqun.feng@gmail.com>
|
||||
R: Frederic Weisbecker <frederic@kernel.org>
|
||||
R: Lyude Paul <lyude@redhat.com>
|
||||
R: Thomas Gleixner <tglx@linutronix.de>
|
||||
R: Anna-Maria Behnsen <anna-maria@linutronix.de>
|
||||
L: rust-for-linux@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://rust-for-linux.com
|
||||
B: https://github.com/Rust-for-Linux/linux/issues
|
||||
T: git https://github.com/Rust-for-Linux/linux.git hrtimer-next
|
||||
F: rust/kernel/time/hrtimer.rs
|
||||
F: rust/kernel/time/hrtimer/
|
||||
|
||||
HIGH-SPEED SCC DRIVER FOR AX.25
|
||||
L: linux-hams@vger.kernel.org
|
||||
S: Orphan
|
||||
@ -12902,6 +12930,7 @@ F: Documentation/dev-tools/kunit/
|
||||
F: include/kunit/
|
||||
F: lib/kunit/
|
||||
F: rust/kernel/kunit.rs
|
||||
F: rust/macros/kunit.rs
|
||||
F: scripts/rustdoc_test_*
|
||||
F: tools/testing/kunit/
|
||||
|
||||
@ -20993,6 +21022,7 @@ R: Benno Lossin <benno.lossin@proton.me>
|
||||
R: Andreas Hindborg <a.hindborg@kernel.org>
|
||||
R: Alice Ryhl <aliceryhl@google.com>
|
||||
R: Trevor Gross <tmgross@umich.edu>
|
||||
R: Danilo Krummrich <dakr@kernel.org>
|
||||
L: rust-for-linux@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://rust-for-linux.com
|
||||
@ -21013,9 +21043,23 @@ RUST [ALLOC]
|
||||
M: Danilo Krummrich <dakr@kernel.org>
|
||||
L: rust-for-linux@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git https://github.com/Rust-for-Linux/linux.git alloc-next
|
||||
F: rust/kernel/alloc.rs
|
||||
F: rust/kernel/alloc/
|
||||
|
||||
RUST [PIN-INIT]
|
||||
M: Benno Lossin <benno.lossin@proton.me>
|
||||
L: rust-for-linux@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://rust-for-linux.com/pin-init
|
||||
B: https://github.com/Rust-for-Linux/pin-init/issues
|
||||
C: zulip://rust-for-linux.zulipchat.com
|
||||
P: rust/pin-init/CONTRIBUTING.md
|
||||
T: git https://github.com/Rust-for-Linux/linux.git pin-init-next
|
||||
F: rust/kernel/init.rs
|
||||
F: rust/pin-init/
|
||||
K: \bpin-init\b|pin_init\b|PinInit
|
||||
|
||||
RXRPC SOCKETS (AF_RXRPC)
|
||||
M: David Howells <dhowells@redhat.com>
|
||||
M: Marc Dionne <marc.dionne@auristor.com>
|
||||
|
@ -27,7 +27,7 @@ use kernel::{
|
||||
module! {
|
||||
type: NullBlkModule,
|
||||
name: "rnull_mod",
|
||||
author: "Andreas Hindborg",
|
||||
authors: ["Andreas Hindborg"],
|
||||
description: "Rust implementation of the C null block driver",
|
||||
license: "GPL v2",
|
||||
}
|
||||
|
@ -486,11 +486,6 @@ static void drm_panic_qr_exit(void)
|
||||
stream.workspace = NULL;
|
||||
}
|
||||
|
||||
extern size_t drm_panic_qr_max_data_size(u8 version, size_t url_len);
|
||||
|
||||
extern u8 drm_panic_qr_generate(const char *url, u8 *data, size_t data_len, size_t data_size,
|
||||
u8 *tmp, size_t tmp_size);
|
||||
|
||||
static int drm_panic_get_qr_code_url(u8 **qr_image)
|
||||
{
|
||||
struct kmsg_dump_iter iter;
|
||||
|
@ -27,7 +27,7 @@
|
||||
//! * <https://github.com/erwanvivien/fast_qr>
|
||||
//! * <https://github.com/bjguillot/qr>
|
||||
|
||||
use kernel::str::CStr;
|
||||
use kernel::{prelude::*, str::CStr};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||
struct Version(usize);
|
||||
@ -891,7 +891,7 @@ impl QrImage<'_> {
|
||||
/// * `tmp` must be valid for reading and writing for `tmp_size` bytes.
|
||||
///
|
||||
/// They must remain valid for the duration of the function call.
|
||||
#[no_mangle]
|
||||
#[export]
|
||||
pub unsafe extern "C" fn drm_panic_qr_generate(
|
||||
url: *const kernel::ffi::c_char,
|
||||
data: *mut u8,
|
||||
@ -942,8 +942,13 @@ pub unsafe extern "C" fn drm_panic_qr_generate(
|
||||
/// * If `url_len` > 0, remove the 2 segments header/length and also count the
|
||||
/// conversion to numeric segments.
|
||||
/// * If `url_len` = 0, only removes 3 bytes for 1 binary segment.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Always safe to call.
|
||||
// Required to be unsafe due to the `#[export]` annotation.
|
||||
#[export]
|
||||
pub unsafe extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
|
||||
#[expect(clippy::manual_range_contains)]
|
||||
if version < 1 || version > 40 {
|
||||
return 0;
|
||||
|
@ -19,7 +19,7 @@ kernel::module_phy_driver! {
|
||||
DeviceId::new_with_driver::<PhyAX88796B>()
|
||||
],
|
||||
name: "rust_asix_phy",
|
||||
author: "FUJITA Tomonori <fujita.tomonori@gmail.com>",
|
||||
authors: ["FUJITA Tomonori <fujita.tomonori@gmail.com>"],
|
||||
description: "Rust Asix PHYs driver",
|
||||
license: "GPL",
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ kernel::module_phy_driver! {
|
||||
phy::DeviceId::new_with_driver::<PhyQT2025>(),
|
||||
],
|
||||
name: "qt2025_phy",
|
||||
author: "FUJITA Tomonori <fujita.tomonori@gmail.com>",
|
||||
authors: ["FUJITA Tomonori <fujita.tomonori@gmail.com>"],
|
||||
description: "AMCC QT2025 PHY driver",
|
||||
license: "GPL",
|
||||
firmware: ["qt2025-2.0.3.3.fw"],
|
||||
|
@ -163,4 +163,11 @@ static inline void drm_panic_unlock(struct drm_device *dev, unsigned long flags)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
|
||||
size_t drm_panic_qr_max_data_size(u8 version, size_t url_len);
|
||||
|
||||
u8 drm_panic_qr_generate(const char *url, u8 *data, size_t data_len, size_t data_size,
|
||||
u8 *tmp, size_t tmp_size);
|
||||
#endif
|
||||
|
||||
#endif /* __DRM_PANIC_H__ */
|
||||
|
@ -24,4 +24,7 @@ __scanf(2, 0) int vsscanf(const char *, const char *, va_list);
|
||||
extern bool no_hash_pointers;
|
||||
int no_hash_pointers_enable(char *str);
|
||||
|
||||
/* Used for Rust formatting ('%pA') */
|
||||
char *rust_fmt_argument(char *buf, char *end, const void *ptr);
|
||||
|
||||
#endif /* _LINUX_KERNEL_SPRINTF_H */
|
||||
|
@ -2291,9 +2291,6 @@ int __init no_hash_pointers_enable(char *str)
|
||||
}
|
||||
early_param("no_hash_pointers", no_hash_pointers_enable);
|
||||
|
||||
/* Used for Rust formatting ('%pA'). */
|
||||
char *rust_fmt_argument(char *buf, char *end, void *ptr);
|
||||
|
||||
/*
|
||||
* Show a '%p' thing. A kernel extension is that the '%p' is followed
|
||||
* by an extra set of alphanumeric characters that are extended format
|
||||
|
3
rust/.kunitconfig
Normal file
3
rust/.kunitconfig
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_RUST=y
|
||||
CONFIG_RUST_KERNEL_DOCTESTS=y
|
@ -12,7 +12,7 @@ obj-$(CONFIG_RUST) += helpers/helpers.o
|
||||
CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations
|
||||
|
||||
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
|
||||
obj-$(CONFIG_RUST) += bindings.o kernel.o
|
||||
obj-$(CONFIG_RUST) += bindings.o pin_init.o kernel.o
|
||||
always-$(CONFIG_RUST) += exports_helpers_generated.h \
|
||||
exports_bindings_generated.h exports_kernel_generated.h
|
||||
|
||||
@ -41,7 +41,10 @@ ifdef CONFIG_RUST
|
||||
libmacros_name := $(shell MAKEFLAGS= $(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - </dev/null)
|
||||
libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name))
|
||||
|
||||
always-$(CONFIG_RUST) += $(libmacros_name)
|
||||
libpin_init_internal_name := $(shell MAKEFLAGS= $(RUSTC) --print file-names --crate-name pin_init_internal --crate-type proc-macro - </dev/null)
|
||||
libpin_init_internal_extension := $(patsubst libpin_init_internal.%,%,$(libpin_init_internal_name))
|
||||
|
||||
always-$(CONFIG_RUST) += $(libmacros_name) $(libpin_init_internal_name)
|
||||
|
||||
# `$(rust_flags)` is passed in case the user added `--sysroot`.
|
||||
rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot)
|
||||
@ -80,7 +83,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
|
||||
# command-like flags to solve the issue. Meanwhile, we use the non-custom case
|
||||
# and then retouch the generated files.
|
||||
rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
|
||||
rustdoc-kernel
|
||||
rustdoc-kernel rustdoc-pin_init
|
||||
$(Q)cp $(srctree)/Documentation/images/logo.svg $(rustdoc_output)/static.files/
|
||||
$(Q)cp $(srctree)/Documentation/images/COPYING-logo $(rustdoc_output)/static.files/
|
||||
$(Q)find $(rustdoc_output) -name '*.html' -type f -print0 | xargs -0 sed -Ei \
|
||||
@ -110,11 +113,24 @@ rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE
|
||||
rustdoc-ffi: $(src)/ffi.rs rustdoc-core FORCE
|
||||
+$(call if_changed,rustdoc)
|
||||
|
||||
rustdoc-kernel: private rustc_target_flags = --extern ffi \
|
||||
rustdoc-pin_init_internal: private rustdoc_host = yes
|
||||
rustdoc-pin_init_internal: private rustc_target_flags = --cfg kernel \
|
||||
--extern proc_macro --crate-type proc-macro
|
||||
rustdoc-pin_init_internal: $(src)/pin-init/internal/src/lib.rs FORCE
|
||||
+$(call if_changed,rustdoc)
|
||||
|
||||
rustdoc-pin_init: private rustdoc_host = yes
|
||||
rustdoc-pin_init: private rustc_target_flags = --extern pin_init_internal \
|
||||
--extern macros --extern alloc --cfg kernel --cfg feature=\"alloc\"
|
||||
rustdoc-pin_init: $(src)/pin-init/src/lib.rs rustdoc-pin_init_internal \
|
||||
rustdoc-macros FORCE
|
||||
+$(call if_changed,rustdoc)
|
||||
|
||||
rustdoc-kernel: private rustc_target_flags = --extern ffi --extern pin_init \
|
||||
--extern build_error --extern macros \
|
||||
--extern bindings --extern uapi
|
||||
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-ffi rustdoc-macros \
|
||||
rustdoc-compiler_builtins $(obj)/$(libmacros_name) \
|
||||
rustdoc-pin_init rustdoc-compiler_builtins $(obj)/$(libmacros_name) \
|
||||
$(obj)/bindings.o FORCE
|
||||
+$(call if_changed,rustdoc)
|
||||
|
||||
@ -139,12 +155,24 @@ rusttestlib-macros: private rustc_test_library_proc = yes
|
||||
rusttestlib-macros: $(src)/macros/lib.rs FORCE
|
||||
+$(call if_changed,rustc_test_library)
|
||||
|
||||
rusttestlib-pin_init_internal: private rustc_target_flags = --cfg kernel \
|
||||
--extern proc_macro
|
||||
rusttestlib-pin_init_internal: private rustc_test_library_proc = yes
|
||||
rusttestlib-pin_init_internal: $(src)/pin-init/internal/src/lib.rs FORCE
|
||||
+$(call if_changed,rustc_test_library)
|
||||
|
||||
rusttestlib-pin_init: private rustc_target_flags = --extern pin_init_internal \
|
||||
--extern macros --cfg kernel
|
||||
rusttestlib-pin_init: $(src)/pin-init/src/lib.rs rusttestlib-macros \
|
||||
rusttestlib-pin_init_internal $(obj)/$(libpin_init_internal_name) FORCE
|
||||
+$(call if_changed,rustc_test_library)
|
||||
|
||||
rusttestlib-kernel: private rustc_target_flags = --extern ffi \
|
||||
--extern build_error --extern macros \
|
||||
--extern build_error --extern macros --extern pin_init \
|
||||
--extern bindings --extern uapi
|
||||
rusttestlib-kernel: $(src)/kernel/lib.rs \
|
||||
rusttestlib-bindings rusttestlib-uapi rusttestlib-build_error \
|
||||
$(obj)/$(libmacros_name) $(obj)/bindings.o FORCE
|
||||
rusttestlib-kernel: $(src)/kernel/lib.rs rusttestlib-bindings rusttestlib-uapi \
|
||||
rusttestlib-build_error rusttestlib-pin_init $(obj)/$(libmacros_name) \
|
||||
$(obj)/bindings.o FORCE
|
||||
+$(call if_changed,rustc_test_library)
|
||||
|
||||
rusttestlib-bindings: private rustc_target_flags = --extern ffi
|
||||
@ -172,8 +200,8 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
|
||||
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
|
||||
OBJTREE=$(abspath $(objtree)) \
|
||||
$(RUSTDOC) --test $(rust_flags) \
|
||||
-L$(objtree)/$(obj) --extern ffi --extern kernel \
|
||||
--extern build_error --extern macros \
|
||||
-L$(objtree)/$(obj) --extern ffi --extern pin_init \
|
||||
--extern kernel --extern build_error --extern macros \
|
||||
--extern bindings --extern uapi \
|
||||
--no-run --crate-name kernel -Zunstable-options \
|
||||
--sysroot=/dev/null \
|
||||
@ -203,18 +231,18 @@ quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T $<
|
||||
rusttest: rusttest-macros rusttest-kernel
|
||||
|
||||
rusttest-macros: private rustc_target_flags = --extern proc_macro \
|
||||
--extern macros --extern kernel
|
||||
--extern macros --extern kernel --extern pin_init
|
||||
rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro
|
||||
rusttest-macros: $(src)/macros/lib.rs \
|
||||
rusttestlib-macros rusttestlib-kernel FORCE
|
||||
rusttestlib-macros rusttestlib-kernel rusttestlib-pin_init FORCE
|
||||
+$(call if_changed,rustc_test)
|
||||
+$(call if_changed,rustdoc_test)
|
||||
|
||||
rusttest-kernel: private rustc_target_flags = --extern ffi \
|
||||
rusttest-kernel: private rustc_target_flags = --extern ffi --extern pin_init \
|
||||
--extern build_error --extern macros --extern bindings --extern uapi
|
||||
rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-ffi rusttestlib-kernel \
|
||||
rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \
|
||||
rusttestlib-uapi FORCE
|
||||
rusttestlib-uapi rusttestlib-pin_init FORCE
|
||||
+$(call if_changed,rustc_test)
|
||||
|
||||
ifdef CONFIG_CC_IS_CLANG
|
||||
@ -246,6 +274,7 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
|
||||
# Derived from `scripts/Makefile.clang`.
|
||||
BINDGEN_TARGET_x86 := x86_64-linux-gnu
|
||||
BINDGEN_TARGET_arm64 := aarch64-linux-gnu
|
||||
BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH))
|
||||
BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH))
|
||||
|
||||
# All warnings are inhibited since GCC builds are very experimental,
|
||||
@ -361,7 +390,7 @@ $(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE
|
||||
|
||||
quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
|
||||
cmd_rustc_procmacro = \
|
||||
$(RUSTC_OR_CLIPPY) $(rust_common_flags) \
|
||||
$(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
|
||||
-Clinker-flavor=gcc -Clinker=$(HOSTCC) \
|
||||
-Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \
|
||||
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
|
||||
@ -372,6 +401,10 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
|
||||
$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE
|
||||
+$(call if_changed_dep,rustc_procmacro)
|
||||
|
||||
$(obj)/$(libpin_init_internal_name): private rustc_target_flags = --cfg kernel
|
||||
$(obj)/$(libpin_init_internal_name): $(src)/pin-init/internal/src/lib.rs FORCE
|
||||
+$(call if_changed_dep,rustc_procmacro)
|
||||
|
||||
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
|
||||
cmd_rustc_library = \
|
||||
OBJTREE=$(abspath $(objtree)) \
|
||||
@ -451,6 +484,13 @@ $(obj)/compiler_builtins.o: private rustc_objcopy = -w -W '__*'
|
||||
$(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE
|
||||
+$(call if_changed_rule,rustc_library)
|
||||
|
||||
$(obj)/pin_init.o: private skip_gendwarfksyms = 1
|
||||
$(obj)/pin_init.o: private rustc_target_flags = --extern pin_init_internal \
|
||||
--extern macros --cfg kernel
|
||||
$(obj)/pin_init.o: $(src)/pin-init/src/lib.rs $(obj)/compiler_builtins.o \
|
||||
$(obj)/$(libpin_init_internal_name) $(obj)/$(libmacros_name) FORCE
|
||||
+$(call if_changed_rule,rustc_library)
|
||||
|
||||
$(obj)/build_error.o: private skip_gendwarfksyms = 1
|
||||
$(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE
|
||||
+$(call if_changed_rule,rustc_library)
|
||||
@ -473,9 +513,9 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
|
||||
$(obj)/uapi/uapi_generated.rs FORCE
|
||||
+$(call if_changed_rule,rustc_library)
|
||||
|
||||
$(obj)/kernel.o: private rustc_target_flags = --extern ffi \
|
||||
$(obj)/kernel.o: private rustc_target_flags = --extern ffi --extern pin_init \
|
||||
--extern build_error --extern macros --extern bindings --extern uapi
|
||||
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \
|
||||
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o $(obj)/pin_init.o \
|
||||
$(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE
|
||||
+$(call if_changed_rule,rustc_library)
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/device/faux.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/errname.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/file.h>
|
||||
@ -38,6 +39,11 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <trace/events/rust_sample.h>
|
||||
|
||||
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
|
||||
// Used by `#[export]` in `drivers/gpu/drm/drm_panic_qr.rs`.
|
||||
#include <drm/drm_panic.h>
|
||||
#endif
|
||||
|
||||
/* `bindgen` gets confused at certain things. */
|
||||
const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
|
||||
const size_t RUST_CONST_HELPER_PAGE_SIZE = PAGE_SIZE;
|
||||
|
@ -80,6 +80,7 @@ impl ReallocFunc {
|
||||
/// This method has the same guarantees as `Allocator::realloc`. Additionally
|
||||
/// - it accepts any pointer to a valid memory allocation allocated by this function.
|
||||
/// - memory allocated by this function remains valid until it is passed to this function.
|
||||
#[inline]
|
||||
unsafe fn call(
|
||||
&self,
|
||||
ptr: Option<NonNull<u8>>,
|
||||
|
@ -15,8 +15,9 @@ use core::pin::Pin;
|
||||
use core::ptr::NonNull;
|
||||
use core::result::Result;
|
||||
|
||||
use crate::init::{InPlaceInit, InPlaceWrite, Init, PinInit};
|
||||
use crate::init::InPlaceInit;
|
||||
use crate::types::ForeignOwnable;
|
||||
use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
|
||||
|
||||
/// The kernel's [`Box`] type -- a heap allocation for a single value of type `T`.
|
||||
///
|
||||
@ -99,6 +100,10 @@ pub type VBox<T> = Box<T, super::allocator::Vmalloc>;
|
||||
/// ```
|
||||
pub type KVBox<T> = Box<T, super::allocator::KVmalloc>;
|
||||
|
||||
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee:
|
||||
// https://doc.rust-lang.org/stable/std/option/index.html#representation).
|
||||
unsafe impl<T, A: Allocator> ZeroableOption for Box<T, A> {}
|
||||
|
||||
// SAFETY: `Box` is `Send` if `T` is `Send` because the `Box` owns a `T`.
|
||||
unsafe impl<T, A> Send for Box<T, A>
|
||||
where
|
||||
@ -245,6 +250,12 @@ where
|
||||
Ok(Self::new(x, flags)?.into())
|
||||
}
|
||||
|
||||
/// Convert a [`Box<T,A>`] to a [`Pin<Box<T,A>>`]. If `T` does not implement
|
||||
/// [`Unpin`], then `x` will be pinned in memory and can't be moved.
|
||||
pub fn into_pin(this: Self) -> Pin<Self> {
|
||||
this.into()
|
||||
}
|
||||
|
||||
/// Forgets the contents (does not run the destructor), but keeps the allocation.
|
||||
fn forget_contents(this: Self) -> Box<MaybeUninit<T>, A> {
|
||||
let ptr = Self::into_raw(this);
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
};
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
ptr::{addr_of_mut, NonNull},
|
||||
ptr::NonNull,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
@ -187,7 +187,7 @@ impl RequestDataWrapper {
|
||||
pub(crate) unsafe fn refcount_ptr(this: *mut Self) -> *mut AtomicU64 {
|
||||
// SAFETY: Because of the safety requirements of this function, the
|
||||
// field projection is safe.
|
||||
unsafe { addr_of_mut!((*this).refcount) }
|
||||
unsafe { &raw mut (*this).refcount }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,11 @@ use crate::{
|
||||
bindings,
|
||||
block::mq::{operations::OperationsVTable, request::RequestDataWrapper, Operations},
|
||||
error,
|
||||
prelude::PinInit,
|
||||
try_pin_init,
|
||||
prelude::try_pin_init,
|
||||
types::Opaque,
|
||||
};
|
||||
use core::{convert::TryInto, marker::PhantomData};
|
||||
use macros::{pin_data, pinned_drop};
|
||||
use pin_init::{pin_data, pinned_drop, PinInit};
|
||||
|
||||
/// A wrapper for the C `struct blk_mq_tag_set`.
|
||||
///
|
||||
|
391
rust/kernel/dma.rs
Normal file
391
rust/kernel/dma.rs
Normal file
@ -0,0 +1,391 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! Direct memory access (DMA).
|
||||
//!
|
||||
//! C header: [`include/linux/dma-mapping.h`](srctree/include/linux/dma-mapping.h)
|
||||
|
||||
use crate::{
|
||||
bindings, build_assert,
|
||||
device::Device,
|
||||
error::code::*,
|
||||
error::Result,
|
||||
transmute::{AsBytes, FromBytes},
|
||||
types::ARef,
|
||||
};
|
||||
|
||||
/// Possible attributes associated with a DMA mapping.
|
||||
///
|
||||
/// They can be combined with the operators `|`, `&`, and `!`.
|
||||
///
|
||||
/// Values can be used from the [`attrs`] module.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::device::Device;
|
||||
/// use kernel::dma::{attrs::*, CoherentAllocation};
|
||||
///
|
||||
/// # fn test(dev: &Device) -> Result {
|
||||
/// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;
|
||||
/// let c: CoherentAllocation<u64> =
|
||||
/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?;
|
||||
/// # Ok::<(), Error>(()) }
|
||||
/// ```
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct Attrs(u32);
|
||||
|
||||
impl Attrs {
|
||||
/// Get the raw representation of this attribute.
|
||||
pub(crate) fn as_raw(self) -> crate::ffi::c_ulong {
|
||||
self.0 as _
|
||||
}
|
||||
|
||||
/// Check whether `flags` is contained in `self`.
|
||||
pub fn contains(self, flags: Attrs) -> bool {
|
||||
(self & flags) == flags
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitOr for Attrs {
|
||||
type Output = Self;
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitAnd for Attrs {
|
||||
type Output = Self;
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 & rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Not for Attrs {
|
||||
type Output = Self;
|
||||
fn not(self) -> Self::Output {
|
||||
Self(!self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// DMA mapping attributes.
|
||||
pub mod attrs {
|
||||
use super::Attrs;
|
||||
|
||||
/// Specifies that reads and writes to the mapping may be weakly ordered, that is that reads
|
||||
/// and writes may pass each other.
|
||||
pub const DMA_ATTR_WEAK_ORDERING: Attrs = Attrs(bindings::DMA_ATTR_WEAK_ORDERING);
|
||||
|
||||
/// Specifies that writes to the mapping may be buffered to improve performance.
|
||||
pub const DMA_ATTR_WRITE_COMBINE: Attrs = Attrs(bindings::DMA_ATTR_WRITE_COMBINE);
|
||||
|
||||
/// Lets the platform to avoid creating a kernel virtual mapping for the allocated buffer.
|
||||
pub const DMA_ATTR_NO_KERNEL_MAPPING: Attrs = Attrs(bindings::DMA_ATTR_NO_KERNEL_MAPPING);
|
||||
|
||||
/// Allows platform code to skip synchronization of the CPU cache for the given buffer assuming
|
||||
/// that it has been already transferred to 'device' domain.
|
||||
pub const DMA_ATTR_SKIP_CPU_SYNC: Attrs = Attrs(bindings::DMA_ATTR_SKIP_CPU_SYNC);
|
||||
|
||||
/// Forces contiguous allocation of the buffer in physical memory.
|
||||
pub const DMA_ATTR_FORCE_CONTIGUOUS: Attrs = Attrs(bindings::DMA_ATTR_FORCE_CONTIGUOUS);
|
||||
|
||||
/// This is a hint to the DMA-mapping subsystem that it's probably not worth the time to try
|
||||
/// to allocate memory to in a way that gives better TLB efficiency.
|
||||
pub const DMA_ATTR_ALLOC_SINGLE_PAGES: Attrs = Attrs(bindings::DMA_ATTR_ALLOC_SINGLE_PAGES);
|
||||
|
||||
/// This tells the DMA-mapping subsystem to suppress allocation failure reports (similarly to
|
||||
/// __GFP_NOWARN).
|
||||
pub const DMA_ATTR_NO_WARN: Attrs = Attrs(bindings::DMA_ATTR_NO_WARN);
|
||||
|
||||
/// Used to indicate that the buffer is fully accessible at an elevated privilege level (and
|
||||
/// ideally inaccessible or at least read-only at lesser-privileged levels).
|
||||
pub const DMA_ATTR_PRIVILEGED: Attrs = Attrs(bindings::DMA_ATTR_PRIVILEGED);
|
||||
}
|
||||
|
||||
/// An abstraction of the `dma_alloc_coherent` API.
|
||||
///
|
||||
/// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map
|
||||
/// large consistent DMA regions.
|
||||
///
|
||||
/// A [`CoherentAllocation`] instance contains a pointer to the allocated region (in the
|
||||
/// processor's virtual address space) and the device address which can be given to the device
|
||||
/// as the DMA address base of the region. The region is released once [`CoherentAllocation`]
|
||||
/// is dropped.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// For the lifetime of an instance of [`CoherentAllocation`], the `cpu_addr` is a valid pointer
|
||||
/// to an allocated region of consistent memory and `dma_handle` is the DMA address base of
|
||||
/// the region.
|
||||
// TODO
|
||||
//
|
||||
// DMA allocations potentially carry device resources (e.g.IOMMU mappings), hence for soundness
|
||||
// reasons DMA allocation would need to be embedded in a `Devres` container, in order to ensure
|
||||
// that device resources can never survive device unbind.
|
||||
//
|
||||
// However, it is neither desirable nor necessary to protect the allocated memory of the DMA
|
||||
// allocation from surviving device unbind; it would require RCU read side critical sections to
|
||||
// access the memory, which may require subsequent unnecessary copies.
|
||||
//
|
||||
// Hence, find a way to revoke the device resources of a `CoherentAllocation`, but not the
|
||||
// entire `CoherentAllocation` including the allocated memory itself.
|
||||
pub struct CoherentAllocation<T: AsBytes + FromBytes> {
|
||||
dev: ARef<Device>,
|
||||
dma_handle: bindings::dma_addr_t,
|
||||
count: usize,
|
||||
cpu_addr: *mut T,
|
||||
dma_attrs: Attrs,
|
||||
}
|
||||
|
||||
impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
|
||||
/// Allocates a region of `size_of::<T> * count` of consistent memory.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::device::Device;
|
||||
/// use kernel::dma::{attrs::*, CoherentAllocation};
|
||||
///
|
||||
/// # fn test(dev: &Device) -> Result {
|
||||
/// let c: CoherentAllocation<u64> =
|
||||
/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
|
||||
/// # Ok::<(), Error>(()) }
|
||||
/// ```
|
||||
pub fn alloc_attrs(
|
||||
dev: &Device,
|
||||
count: usize,
|
||||
gfp_flags: kernel::alloc::Flags,
|
||||
dma_attrs: Attrs,
|
||||
) -> Result<CoherentAllocation<T>> {
|
||||
build_assert!(
|
||||
core::mem::size_of::<T>() > 0,
|
||||
"It doesn't make sense for the allocated type to be a ZST"
|
||||
);
|
||||
|
||||
let size = count
|
||||
.checked_mul(core::mem::size_of::<T>())
|
||||
.ok_or(EOVERFLOW)?;
|
||||
let mut dma_handle = 0;
|
||||
// SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
|
||||
let ret = unsafe {
|
||||
bindings::dma_alloc_attrs(
|
||||
dev.as_raw(),
|
||||
size,
|
||||
&mut dma_handle,
|
||||
gfp_flags.as_raw(),
|
||||
dma_attrs.as_raw(),
|
||||
)
|
||||
};
|
||||
if ret.is_null() {
|
||||
return Err(ENOMEM);
|
||||
}
|
||||
// INVARIANT: We just successfully allocated a coherent region which is accessible for
|
||||
// `count` elements, hence the cpu address is valid. We also hold a refcounted reference
|
||||
// to the device.
|
||||
Ok(Self {
|
||||
dev: dev.into(),
|
||||
dma_handle,
|
||||
count,
|
||||
cpu_addr: ret as *mut T,
|
||||
dma_attrs,
|
||||
})
|
||||
}
|
||||
|
||||
/// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the
|
||||
/// `dma_attrs` is 0 by default.
|
||||
pub fn alloc_coherent(
|
||||
dev: &Device,
|
||||
count: usize,
|
||||
gfp_flags: kernel::alloc::Flags,
|
||||
) -> Result<CoherentAllocation<T>> {
|
||||
CoherentAllocation::alloc_attrs(dev, count, gfp_flags, Attrs(0))
|
||||
}
|
||||
|
||||
/// Returns the base address to the allocated region in the CPU's virtual address space.
|
||||
pub fn start_ptr(&self) -> *const T {
|
||||
self.cpu_addr
|
||||
}
|
||||
|
||||
/// Returns the base address to the allocated region in the CPU's virtual address space as
|
||||
/// a mutable pointer.
|
||||
pub fn start_ptr_mut(&mut self) -> *mut T {
|
||||
self.cpu_addr
|
||||
}
|
||||
|
||||
/// Returns a DMA handle which may given to the device as the DMA address base of
|
||||
/// the region.
|
||||
pub fn dma_handle(&self) -> bindings::dma_addr_t {
|
||||
self.dma_handle
|
||||
}
|
||||
|
||||
/// Returns a pointer to an element from the region with bounds checking. `offset` is in
|
||||
/// units of `T`, not the number of bytes.
|
||||
///
|
||||
/// Public but hidden since it should only be used from [`dma_read`] and [`dma_write`] macros.
|
||||
#[doc(hidden)]
|
||||
pub fn item_from_index(&self, offset: usize) -> Result<*mut T> {
|
||||
if offset >= self.count {
|
||||
return Err(EINVAL);
|
||||
}
|
||||
// SAFETY:
|
||||
// - The pointer is valid due to type invariant on `CoherentAllocation`
|
||||
// and we've just checked that the range and index is within bounds.
|
||||
// - `offset` can't overflow since it is smaller than `self.count` and we've checked
|
||||
// that `self.count` won't overflow early in the constructor.
|
||||
Ok(unsafe { self.cpu_addr.add(offset) })
|
||||
}
|
||||
|
||||
/// Reads the value of `field` and ensures that its type is [`FromBytes`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This must be called from the [`dma_read`] macro which ensures that the `field` pointer is
|
||||
/// validated beforehand.
|
||||
///
|
||||
/// Public but hidden since it should only be used from [`dma_read`] macro.
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn field_read<F: FromBytes>(&self, field: *const F) -> F {
|
||||
// SAFETY:
|
||||
// - By the safety requirements field is valid.
|
||||
// - Using read_volatile() here is not sound as per the usual rules, the usage here is
|
||||
// a special exception with the following notes in place. When dealing with a potential
|
||||
// race from a hardware or code outside kernel (e.g. user-space program), we need that
|
||||
// read on a valid memory is not UB. Currently read_volatile() is used for this, and the
|
||||
// rationale behind is that it should generate the same code as READ_ONCE() which the
|
||||
// kernel already relies on to avoid UB on data races. Note that the usage of
|
||||
// read_volatile() is limited to this particular case, it cannot be used to prevent
|
||||
// the UB caused by racing between two kernel functions nor do they provide atomicity.
|
||||
unsafe { field.read_volatile() }
|
||||
}
|
||||
|
||||
/// Writes a value to `field` and ensures that its type is [`AsBytes`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This must be called from the [`dma_write`] macro which ensures that the `field` pointer is
|
||||
/// validated beforehand.
|
||||
///
|
||||
/// Public but hidden since it should only be used from [`dma_write`] macro.
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn field_write<F: AsBytes>(&self, field: *mut F, val: F) {
|
||||
// SAFETY:
|
||||
// - By the safety requirements field is valid.
|
||||
// - Using write_volatile() here is not sound as per the usual rules, the usage here is
|
||||
// a special exception with the following notes in place. When dealing with a potential
|
||||
// race from a hardware or code outside kernel (e.g. user-space program), we need that
|
||||
// write on a valid memory is not UB. Currently write_volatile() is used for this, and the
|
||||
// rationale behind is that it should generate the same code as WRITE_ONCE() which the
|
||||
// kernel already relies on to avoid UB on data races. Note that the usage of
|
||||
// write_volatile() is limited to this particular case, it cannot be used to prevent
|
||||
// the UB caused by racing between two kernel functions nor do they provide atomicity.
|
||||
unsafe { field.write_volatile(val) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that the device configured to do DMA must be halted before this object is dropped.
|
||||
impl<T: AsBytes + FromBytes> Drop for CoherentAllocation<T> {
|
||||
fn drop(&mut self) {
|
||||
let size = self.count * core::mem::size_of::<T>();
|
||||
// SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
|
||||
// The cpu address, and the dma handle are valid due to the type invariants on
|
||||
// `CoherentAllocation`.
|
||||
unsafe {
|
||||
bindings::dma_free_attrs(
|
||||
self.dev.as_raw(),
|
||||
size,
|
||||
self.cpu_addr as _,
|
||||
self.dma_handle,
|
||||
self.dma_attrs.as_raw(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: It is safe to send a `CoherentAllocation` to another thread if `T`
|
||||
// can be sent to another thread.
|
||||
unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {}
|
||||
|
||||
/// Reads a field of an item from an allocated region of structs.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::device::Device;
|
||||
/// use kernel::dma::{attrs::*, CoherentAllocation};
|
||||
///
|
||||
/// struct MyStruct { field: u32, }
|
||||
///
|
||||
/// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
|
||||
/// unsafe impl kernel::transmute::FromBytes for MyStruct{};
|
||||
/// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
|
||||
/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
|
||||
///
|
||||
/// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
|
||||
/// let whole = kernel::dma_read!(alloc[2]);
|
||||
/// let field = kernel::dma_read!(alloc[1].field);
|
||||
/// # Ok::<(), Error>(()) }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! dma_read {
|
||||
($dma:expr, $idx: expr, $($field:tt)*) => {{
|
||||
let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
|
||||
// SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
|
||||
// dereferenced. The compiler also further validates the expression on whether `field`
|
||||
// is a member of `item` when expanded by the macro.
|
||||
unsafe {
|
||||
let ptr_field = ::core::ptr::addr_of!((*item) $($field)*);
|
||||
$crate::dma::CoherentAllocation::field_read(&$dma, ptr_field)
|
||||
}
|
||||
}};
|
||||
($dma:ident [ $idx:expr ] $($field:tt)* ) => {
|
||||
$crate::dma_read!($dma, $idx, $($field)*);
|
||||
};
|
||||
($($dma:ident).* [ $idx:expr ] $($field:tt)* ) => {
|
||||
$crate::dma_read!($($dma).*, $idx, $($field)*);
|
||||
};
|
||||
}
|
||||
|
||||
/// Writes to a field of an item from an allocated region of structs.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::device::Device;
|
||||
/// use kernel::dma::{attrs::*, CoherentAllocation};
|
||||
///
|
||||
/// struct MyStruct { member: u32, }
|
||||
///
|
||||
/// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
|
||||
/// unsafe impl kernel::transmute::FromBytes for MyStruct{};
|
||||
/// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
|
||||
/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
|
||||
///
|
||||
/// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
|
||||
/// kernel::dma_write!(alloc[2].member = 0xf);
|
||||
/// kernel::dma_write!(alloc[1] = MyStruct { member: 0xf });
|
||||
/// # Ok::<(), Error>(()) }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! dma_write {
|
||||
($dma:ident [ $idx:expr ] $($field:tt)*) => {{
|
||||
$crate::dma_write!($dma, $idx, $($field)*);
|
||||
}};
|
||||
($($dma:ident).* [ $idx:expr ] $($field:tt)* ) => {{
|
||||
$crate::dma_write!($($dma).*, $idx, $($field)*);
|
||||
}};
|
||||
($dma:expr, $idx: expr, = $val:expr) => {
|
||||
let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
|
||||
// SAFETY: `item_from_index` ensures that `item` is always a valid item.
|
||||
unsafe { $crate::dma::CoherentAllocation::field_write(&$dma, item, $val) }
|
||||
};
|
||||
($dma:expr, $idx: expr, $(.$field:ident)* = $val:expr) => {
|
||||
let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
|
||||
// SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
|
||||
// dereferenced. The compiler also further validates the expression on whether `field`
|
||||
// is a member of `item` when expanded by the macro.
|
||||
unsafe {
|
||||
let ptr_field = ::core::ptr::addr_of_mut!((*item) $(.$field)*);
|
||||
$crate::dma::CoherentAllocation::field_write(&$dma, ptr_field, $val)
|
||||
}
|
||||
};
|
||||
}
|
@ -6,9 +6,9 @@
|
||||
//! register using the [`Registration`] class.
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::{device, init::PinInit, of, str::CStr, try_pin_init, types::Opaque, ThisModule};
|
||||
use crate::{device, of, str::CStr, try_pin_init, types::Opaque, ThisModule};
|
||||
use core::pin::Pin;
|
||||
use macros::{pin_data, pinned_drop};
|
||||
use pin_init::{pin_data, pinned_drop, PinInit};
|
||||
|
||||
/// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform,
|
||||
/// Amba, etc.) to provide the corresponding subsystem specific implementation to register /
|
||||
@ -114,7 +114,7 @@ macro_rules! module_driver {
|
||||
impl $crate::InPlaceModule for DriverModule {
|
||||
fn init(
|
||||
module: &'static $crate::ThisModule
|
||||
) -> impl $crate::init::PinInit<Self, $crate::error::Error> {
|
||||
) -> impl ::pin_init::PinInit<Self, $crate::error::Error> {
|
||||
$crate::try_pin_init!(Self {
|
||||
_driver <- $crate::driver::Registration::new(
|
||||
<Self as $crate::ModuleMetadata>::NAME,
|
||||
|
@ -64,6 +64,7 @@ pub mod code {
|
||||
declare_err!(EPIPE, "Broken pipe.");
|
||||
declare_err!(EDOM, "Math argument out of domain of func.");
|
||||
declare_err!(ERANGE, "Math result not representable.");
|
||||
declare_err!(EOVERFLOW, "Value too large for defined data type.");
|
||||
declare_err!(ERESTARTSYS, "Restart the system call.");
|
||||
declare_err!(ERESTARTNOINTR, "System call was interrupted by a signal and will be restarted.");
|
||||
declare_err!(ERESTARTNOHAND, "Restart if no handler.");
|
||||
@ -248,8 +249,129 @@ impl From<core::convert::Infallible> for Error {
|
||||
/// [`Error`] as its error type.
|
||||
///
|
||||
/// Note that even if a function does not return anything when it succeeds,
|
||||
/// it should still be modeled as returning a `Result` rather than
|
||||
/// it should still be modeled as returning a [`Result`] rather than
|
||||
/// just an [`Error`].
|
||||
///
|
||||
/// Calling a function that returns [`Result`] forces the caller to handle
|
||||
/// the returned [`Result`].
|
||||
///
|
||||
/// This can be done "manually" by using [`match`]. Using [`match`] to decode
|
||||
/// the [`Result`] is similar to C where all the return value decoding and the
|
||||
/// error handling is done explicitly by writing handling code for each
|
||||
/// error to cover. Using [`match`] the error and success handling can be
|
||||
/// implemented in all detail as required. For example (inspired by
|
||||
/// [`samples/rust/rust_minimal.rs`]):
|
||||
///
|
||||
/// ```
|
||||
/// # #[allow(clippy::single_match)]
|
||||
/// fn example() -> Result {
|
||||
/// let mut numbers = KVec::new();
|
||||
///
|
||||
/// match numbers.push(72, GFP_KERNEL) {
|
||||
/// Err(e) => {
|
||||
/// pr_err!("Error pushing 72: {e:?}");
|
||||
/// return Err(e.into());
|
||||
/// }
|
||||
/// // Do nothing, continue.
|
||||
/// Ok(()) => (),
|
||||
/// }
|
||||
///
|
||||
/// match numbers.push(108, GFP_KERNEL) {
|
||||
/// Err(e) => {
|
||||
/// pr_err!("Error pushing 108: {e:?}");
|
||||
/// return Err(e.into());
|
||||
/// }
|
||||
/// // Do nothing, continue.
|
||||
/// Ok(()) => (),
|
||||
/// }
|
||||
///
|
||||
/// match numbers.push(200, GFP_KERNEL) {
|
||||
/// Err(e) => {
|
||||
/// pr_err!("Error pushing 200: {e:?}");
|
||||
/// return Err(e.into());
|
||||
/// }
|
||||
/// // Do nothing, continue.
|
||||
/// Ok(()) => (),
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// # example()?;
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// An alternative to be more concise is the [`if let`] syntax:
|
||||
///
|
||||
/// ```
|
||||
/// fn example() -> Result {
|
||||
/// let mut numbers = KVec::new();
|
||||
///
|
||||
/// if let Err(e) = numbers.push(72, GFP_KERNEL) {
|
||||
/// pr_err!("Error pushing 72: {e:?}");
|
||||
/// return Err(e.into());
|
||||
/// }
|
||||
///
|
||||
/// if let Err(e) = numbers.push(108, GFP_KERNEL) {
|
||||
/// pr_err!("Error pushing 108: {e:?}");
|
||||
/// return Err(e.into());
|
||||
/// }
|
||||
///
|
||||
/// if let Err(e) = numbers.push(200, GFP_KERNEL) {
|
||||
/// pr_err!("Error pushing 200: {e:?}");
|
||||
/// return Err(e.into());
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// # example()?;
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// Instead of these verbose [`match`]/[`if let`], the [`?`] operator can
|
||||
/// be used to handle the [`Result`]. Using the [`?`] operator is often
|
||||
/// the best choice to handle [`Result`] in a non-verbose way as done in
|
||||
/// [`samples/rust/rust_minimal.rs`]:
|
||||
///
|
||||
/// ```
|
||||
/// fn example() -> Result {
|
||||
/// let mut numbers = KVec::new();
|
||||
///
|
||||
/// numbers.push(72, GFP_KERNEL)?;
|
||||
/// numbers.push(108, GFP_KERNEL)?;
|
||||
/// numbers.push(200, GFP_KERNEL)?;
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// # example()?;
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// Another possibility is to call [`unwrap()`](Result::unwrap) or
|
||||
/// [`expect()`](Result::expect). However, use of these functions is
|
||||
/// *heavily discouraged* in the kernel because they trigger a Rust
|
||||
/// [`panic!`] if an error happens, which may destabilize the system or
|
||||
/// entirely break it as a result -- just like the C [`BUG()`] macro.
|
||||
/// Please see the documentation for the C macro [`BUG()`] for guidance
|
||||
/// on when to use these functions.
|
||||
///
|
||||
/// Alternatively, depending on the use case, using [`unwrap_or()`],
|
||||
/// [`unwrap_or_else()`], [`unwrap_or_default()`] or [`unwrap_unchecked()`]
|
||||
/// might be an option, as well.
|
||||
///
|
||||
/// For even more details, please see the [Rust documentation].
|
||||
///
|
||||
/// [`match`]: https://doc.rust-lang.org/reference/expressions/match-expr.html
|
||||
/// [`samples/rust/rust_minimal.rs`]: srctree/samples/rust/rust_minimal.rs
|
||||
/// [`if let`]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
|
||||
/// [`?`]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator
|
||||
/// [`unwrap()`]: Result::unwrap
|
||||
/// [`expect()`]: Result::expect
|
||||
/// [`BUG()`]: https://docs.kernel.org/process/deprecated.html#bug-and-bug-on
|
||||
/// [`unwrap_or()`]: Result::unwrap_or
|
||||
/// [`unwrap_or_else()`]: Result::unwrap_or_else
|
||||
/// [`unwrap_or_default()`]: Result::unwrap_or_default
|
||||
/// [`unwrap_unchecked()`]: Result::unwrap_unchecked
|
||||
/// [Rust documentation]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
|
||||
pub type Result<T = (), E = Error> = core::result::Result<T, E>;
|
||||
|
||||
/// Converts an integer as returned by a C kernel function to an error if it's negative, and
|
||||
|
@ -267,7 +267,7 @@ impl LocalFile {
|
||||
/// # Safety
|
||||
///
|
||||
/// * The caller must ensure that `ptr` points at a valid file and that the file's refcount is
|
||||
/// positive for the duration of 'a.
|
||||
/// positive for the duration of `'a`.
|
||||
/// * The caller must ensure that if there is an active call to `fdget_pos` that did not take
|
||||
/// the `f_pos_lock` mutex, then that call is on the current thread.
|
||||
#[inline]
|
||||
@ -341,7 +341,7 @@ impl File {
|
||||
/// # Safety
|
||||
///
|
||||
/// * The caller must ensure that `ptr` points at a valid file and that the file's refcount is
|
||||
/// positive for the duration of 'a.
|
||||
/// positive for the duration of `'a`.
|
||||
/// * The caller must ensure that if there are active `fdget_pos` calls on this file, then they
|
||||
/// took the `f_pos_lock` mutex.
|
||||
#[inline]
|
||||
|
1461
rust/kernel/init.rs
1461
rust/kernel/init.rs
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,8 @@ pub fn info(args: fmt::Arguments<'_>) {
|
||||
}
|
||||
}
|
||||
|
||||
use macros::kunit_tests;
|
||||
|
||||
/// Asserts that a boolean expression is `true` at runtime.
|
||||
///
|
||||
/// Public but hidden since it should only be used from generated tests.
|
||||
@ -161,3 +163,172 @@ macro_rules! kunit_assert_eq {
|
||||
$crate::kunit_assert!($name, $file, $diff, $left == $right);
|
||||
}};
|
||||
}
|
||||
|
||||
/// Represents an individual test case.
|
||||
///
|
||||
/// The [`kunit_unsafe_test_suite!`] macro expects a NULL-terminated list of valid test cases.
|
||||
/// Use [`kunit_case_null`] to generate such a delimiter.
|
||||
#[doc(hidden)]
|
||||
pub const fn kunit_case(
|
||||
name: &'static kernel::str::CStr,
|
||||
run_case: unsafe extern "C" fn(*mut kernel::bindings::kunit),
|
||||
) -> kernel::bindings::kunit_case {
|
||||
kernel::bindings::kunit_case {
|
||||
run_case: Some(run_case),
|
||||
name: name.as_char_ptr(),
|
||||
attr: kernel::bindings::kunit_attributes {
|
||||
speed: kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
|
||||
},
|
||||
generate_params: None,
|
||||
status: kernel::bindings::kunit_status_KUNIT_SUCCESS,
|
||||
module_name: core::ptr::null_mut(),
|
||||
log: core::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the NULL test case delimiter.
|
||||
///
|
||||
/// The [`kunit_unsafe_test_suite!`] macro expects a NULL-terminated list of test cases. This
|
||||
/// function returns such a delimiter.
|
||||
#[doc(hidden)]
|
||||
pub const fn kunit_case_null() -> kernel::bindings::kunit_case {
|
||||
kernel::bindings::kunit_case {
|
||||
run_case: None,
|
||||
name: core::ptr::null_mut(),
|
||||
generate_params: None,
|
||||
attr: kernel::bindings::kunit_attributes {
|
||||
speed: kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
|
||||
},
|
||||
status: kernel::bindings::kunit_status_KUNIT_SUCCESS,
|
||||
module_name: core::ptr::null_mut(),
|
||||
log: core::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a KUnit test suite.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `test_cases` must be a NULL terminated array of valid test cases,
|
||||
/// whose lifetime is at least that of the test suite (i.e., static).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// extern "C" fn test_fn(_test: *mut kernel::bindings::kunit) {
|
||||
/// let actual = 1 + 1;
|
||||
/// let expected = 2;
|
||||
/// assert_eq!(actual, expected);
|
||||
/// }
|
||||
///
|
||||
/// static mut KUNIT_TEST_CASES: [kernel::bindings::kunit_case; 2] = [
|
||||
/// kernel::kunit::kunit_case(kernel::c_str!("name"), test_fn),
|
||||
/// kernel::kunit::kunit_case_null(),
|
||||
/// ];
|
||||
/// kernel::kunit_unsafe_test_suite!(suite_name, KUNIT_TEST_CASES);
|
||||
/// ```
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! kunit_unsafe_test_suite {
|
||||
($name:ident, $test_cases:ident) => {
|
||||
const _: () = {
|
||||
const KUNIT_TEST_SUITE_NAME: [::kernel::ffi::c_char; 256] = {
|
||||
let name_u8 = ::core::stringify!($name).as_bytes();
|
||||
let mut ret = [0; 256];
|
||||
|
||||
if name_u8.len() > 255 {
|
||||
panic!(concat!(
|
||||
"The test suite name `",
|
||||
::core::stringify!($name),
|
||||
"` exceeds the maximum length of 255 bytes."
|
||||
));
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < name_u8.len() {
|
||||
ret[i] = name_u8[i] as ::kernel::ffi::c_char;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ret
|
||||
};
|
||||
|
||||
static mut KUNIT_TEST_SUITE: ::kernel::bindings::kunit_suite =
|
||||
::kernel::bindings::kunit_suite {
|
||||
name: KUNIT_TEST_SUITE_NAME,
|
||||
#[allow(unused_unsafe)]
|
||||
// SAFETY: `$test_cases` is passed in by the user, and
|
||||
// (as documented) must be valid for the lifetime of
|
||||
// the suite (i.e., static).
|
||||
test_cases: unsafe {
|
||||
::core::ptr::addr_of_mut!($test_cases)
|
||||
.cast::<::kernel::bindings::kunit_case>()
|
||||
},
|
||||
suite_init: None,
|
||||
suite_exit: None,
|
||||
init: None,
|
||||
exit: None,
|
||||
attr: ::kernel::bindings::kunit_attributes {
|
||||
speed: ::kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
|
||||
},
|
||||
status_comment: [0; 256usize],
|
||||
debugfs: ::core::ptr::null_mut(),
|
||||
log: ::core::ptr::null_mut(),
|
||||
suite_init_err: 0,
|
||||
is_init: false,
|
||||
};
|
||||
|
||||
#[used]
|
||||
#[allow(unused_unsafe)]
|
||||
#[cfg_attr(not(target_os = "macos"), link_section = ".kunit_test_suites")]
|
||||
static mut KUNIT_TEST_SUITE_ENTRY: *const ::kernel::bindings::kunit_suite =
|
||||
// SAFETY: `KUNIT_TEST_SUITE` is static.
|
||||
unsafe { ::core::ptr::addr_of_mut!(KUNIT_TEST_SUITE) };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns whether we are currently running a KUnit test.
|
||||
///
|
||||
/// In some cases, you need to call test-only code from outside the test case, for example, to
|
||||
/// create a function mock. This function allows to change behavior depending on whether we are
|
||||
/// currently running a KUnit test or not.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// This example shows how a function can be mocked to return a well-known value while testing:
|
||||
///
|
||||
/// ```
|
||||
/// # use kernel::kunit::in_kunit_test;
|
||||
/// fn fn_mock_example(n: i32) -> i32 {
|
||||
/// if in_kunit_test() {
|
||||
/// return 100;
|
||||
/// }
|
||||
///
|
||||
/// n + 1
|
||||
/// }
|
||||
///
|
||||
/// let mock_res = fn_mock_example(5);
|
||||
/// assert_eq!(mock_res, 100);
|
||||
/// ```
|
||||
pub fn in_kunit_test() -> bool {
|
||||
// SAFETY: `kunit_get_current_test()` is always safe to call (it has fallbacks for
|
||||
// when KUnit is not enabled).
|
||||
!unsafe { bindings::kunit_get_current_test() }.is_null()
|
||||
}
|
||||
|
||||
#[kunit_tests(rust_kernel_kunit)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn rust_test_kunit_example_test() {
|
||||
#![expect(clippy::eq_op)]
|
||||
assert_eq!(1 + 1, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rust_test_kunit_in_kunit_test() {
|
||||
assert!(in_kunit_test());
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))]
|
||||
#![feature(inline_const)]
|
||||
#![feature(lint_reasons)]
|
||||
// Stable in Rust 1.82
|
||||
#![feature(raw_ref_op)]
|
||||
// Stable in Rust 1.83
|
||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||
#![feature(const_mut_refs)]
|
||||
@ -44,6 +46,7 @@ pub mod cred;
|
||||
pub mod device;
|
||||
pub mod device_id;
|
||||
pub mod devres;
|
||||
pub mod dma;
|
||||
pub mod driver;
|
||||
pub mod error;
|
||||
pub mod faux;
|
||||
@ -112,11 +115,11 @@ pub trait InPlaceModule: Sync + Send {
|
||||
/// Creates an initialiser for the module.
|
||||
///
|
||||
/// It is called when the module is loaded.
|
||||
fn init(module: &'static ThisModule) -> impl init::PinInit<Self, error::Error>;
|
||||
fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, error::Error>;
|
||||
}
|
||||
|
||||
impl<T: Module> InPlaceModule for T {
|
||||
fn init(module: &'static ThisModule) -> impl init::PinInit<Self, error::Error> {
|
||||
fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, error::Error> {
|
||||
let initer = move |slot: *mut Self| {
|
||||
let m = <Self as Module>::init(module)?;
|
||||
|
||||
@ -126,7 +129,7 @@ impl<T: Module> InPlaceModule for T {
|
||||
};
|
||||
|
||||
// SAFETY: On success, `initer` always fully initialises an instance of `Self`.
|
||||
unsafe { init::pin_init_from_closure(initer) }
|
||||
unsafe { pin_init::pin_init_from_closure(initer) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
//! A linked list implementation.
|
||||
|
||||
use crate::init::PinInit;
|
||||
use crate::sync::ArcBorrow;
|
||||
use crate::types::Opaque;
|
||||
use core::iter::{DoubleEndedIterator, FusedIterator};
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
use pin_init::PinInit;
|
||||
|
||||
mod impl_list_item_mod;
|
||||
pub use self::impl_list_item_mod::{
|
||||
@ -245,8 +245,20 @@ impl<T: ?Sized + ListItem<ID>, const ID: u64> List<T, ID> {
|
||||
self.first.is_null()
|
||||
}
|
||||
|
||||
/// Add the provided item to the back of the list.
|
||||
pub fn push_back(&mut self, item: ListArc<T, ID>) {
|
||||
/// Inserts `item` before `next` in the cycle.
|
||||
///
|
||||
/// Returns a pointer to the newly inserted element. Never changes `self.first` unless the list
|
||||
/// is empty.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `next` must be an element in this list or null.
|
||||
/// * if `next` is null, then the list must be empty.
|
||||
unsafe fn insert_inner(
|
||||
&mut self,
|
||||
item: ListArc<T, ID>,
|
||||
next: *mut ListLinksFields,
|
||||
) -> *mut ListLinksFields {
|
||||
let raw_item = ListArc::into_raw(item);
|
||||
// SAFETY:
|
||||
// * We just got `raw_item` from a `ListArc`, so it's in an `Arc`.
|
||||
@ -259,16 +271,16 @@ impl<T: ?Sized + ListItem<ID>, const ID: u64> List<T, ID> {
|
||||
// SAFETY: We have not yet called `post_remove`, so `list_links` is still valid.
|
||||
let item = unsafe { ListLinks::fields(list_links) };
|
||||
|
||||
if self.first.is_null() {
|
||||
self.first = item;
|
||||
// Check if the list is empty.
|
||||
if next.is_null() {
|
||||
// SAFETY: The caller just gave us ownership of these fields.
|
||||
// INVARIANT: A linked list with one item should be cyclic.
|
||||
unsafe {
|
||||
(*item).next = item;
|
||||
(*item).prev = item;
|
||||
}
|
||||
self.first = item;
|
||||
} else {
|
||||
let next = self.first;
|
||||
// SAFETY: By the type invariant, this pointer is valid or null. We just checked that
|
||||
// it's not null, so it must be valid.
|
||||
let prev = unsafe { (*next).prev };
|
||||
@ -282,45 +294,27 @@ impl<T: ?Sized + ListItem<ID>, const ID: u64> List<T, ID> {
|
||||
(*next).prev = item;
|
||||
}
|
||||
}
|
||||
|
||||
item
|
||||
}
|
||||
|
||||
/// Add the provided item to the back of the list.
|
||||
pub fn push_back(&mut self, item: ListArc<T, ID>) {
|
||||
// SAFETY:
|
||||
// * `self.first` is null or in the list.
|
||||
// * `self.first` is only null if the list is empty.
|
||||
unsafe { self.insert_inner(item, self.first) };
|
||||
}
|
||||
|
||||
/// Add the provided item to the front of the list.
|
||||
pub fn push_front(&mut self, item: ListArc<T, ID>) {
|
||||
let raw_item = ListArc::into_raw(item);
|
||||
// SAFETY:
|
||||
// * We just got `raw_item` from a `ListArc`, so it's in an `Arc`.
|
||||
// * If this requirement is violated, then the previous caller of `prepare_to_insert`
|
||||
// violated the safety requirement that they can't give up ownership of the `ListArc`
|
||||
// until they call `post_remove`.
|
||||
// * We own the `ListArc`.
|
||||
// * Removing items] from this list is always done using `remove_internal_inner`, which
|
||||
// calls `post_remove` before giving up ownership.
|
||||
let list_links = unsafe { T::prepare_to_insert(raw_item) };
|
||||
// SAFETY: We have not yet called `post_remove`, so `list_links` is still valid.
|
||||
let item = unsafe { ListLinks::fields(list_links) };
|
||||
// * `self.first` is null or in the list.
|
||||
// * `self.first` is only null if the list is empty.
|
||||
let new_elem = unsafe { self.insert_inner(item, self.first) };
|
||||
|
||||
if self.first.is_null() {
|
||||
// SAFETY: The caller just gave us ownership of these fields.
|
||||
// INVARIANT: A linked list with one item should be cyclic.
|
||||
unsafe {
|
||||
(*item).next = item;
|
||||
(*item).prev = item;
|
||||
}
|
||||
} else {
|
||||
let next = self.first;
|
||||
// SAFETY: We just checked that `next` is non-null.
|
||||
let prev = unsafe { (*next).prev };
|
||||
// SAFETY: Pointers in a linked list are never dangling, and the caller just gave us
|
||||
// ownership of the fields on `item`.
|
||||
// INVARIANT: This correctly inserts `item` between `prev` and `next`.
|
||||
unsafe {
|
||||
(*item).next = next;
|
||||
(*item).prev = prev;
|
||||
(*prev).next = item;
|
||||
(*next).prev = item;
|
||||
}
|
||||
}
|
||||
self.first = item;
|
||||
// INVARIANT: `new_elem` is in the list because we just inserted it.
|
||||
self.first = new_elem;
|
||||
}
|
||||
|
||||
/// Removes the last item from this list.
|
||||
@ -489,17 +483,21 @@ impl<T: ?Sized + ListItem<ID>, const ID: u64> List<T, ID> {
|
||||
other.first = ptr::null_mut();
|
||||
}
|
||||
|
||||
/// Returns a cursor to the first element of the list.
|
||||
///
|
||||
/// If the list is empty, this returns `None`.
|
||||
pub fn cursor_front(&mut self) -> Option<Cursor<'_, T, ID>> {
|
||||
if self.first.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Cursor {
|
||||
current: self.first,
|
||||
list: self,
|
||||
})
|
||||
/// Returns a cursor that points before the first element of the list.
|
||||
pub fn cursor_front(&mut self) -> Cursor<'_, T, ID> {
|
||||
// INVARIANT: `self.first` is in this list.
|
||||
Cursor {
|
||||
next: self.first,
|
||||
list: self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a cursor that points after the last element in the list.
|
||||
pub fn cursor_back(&mut self) -> Cursor<'_, T, ID> {
|
||||
// INVARIANT: `next` is allowed to be null.
|
||||
Cursor {
|
||||
next: core::ptr::null_mut(),
|
||||
list: self,
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,69 +577,358 @@ impl<'a, T: ?Sized + ListItem<ID>, const ID: u64> Iterator for Iter<'a, T, ID> {
|
||||
|
||||
/// A cursor into a [`List`].
|
||||
///
|
||||
/// A cursor always rests between two elements in the list. This means that a cursor has a previous
|
||||
/// and next element, but no current element. It also means that it's possible to have a cursor
|
||||
/// into an empty list.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::prelude::*;
|
||||
/// use kernel::list::{List, ListArc, ListLinks};
|
||||
///
|
||||
/// #[pin_data]
|
||||
/// struct ListItem {
|
||||
/// value: u32,
|
||||
/// #[pin]
|
||||
/// links: ListLinks,
|
||||
/// }
|
||||
///
|
||||
/// impl ListItem {
|
||||
/// fn new(value: u32) -> Result<ListArc<Self>> {
|
||||
/// ListArc::pin_init(try_pin_init!(Self {
|
||||
/// value,
|
||||
/// links <- ListLinks::new(),
|
||||
/// }), GFP_KERNEL)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// kernel::list::impl_has_list_links! {
|
||||
/// impl HasListLinks<0> for ListItem { self.links }
|
||||
/// }
|
||||
/// kernel::list::impl_list_arc_safe! {
|
||||
/// impl ListArcSafe<0> for ListItem { untracked; }
|
||||
/// }
|
||||
/// kernel::list::impl_list_item! {
|
||||
/// impl ListItem<0> for ListItem { using ListLinks; }
|
||||
/// }
|
||||
///
|
||||
/// // Use a cursor to remove the first element with the given value.
|
||||
/// fn remove_first(list: &mut List<ListItem>, value: u32) -> Option<ListArc<ListItem>> {
|
||||
/// let mut cursor = list.cursor_front();
|
||||
/// while let Some(next) = cursor.peek_next() {
|
||||
/// if next.value == value {
|
||||
/// return Some(next.remove());
|
||||
/// }
|
||||
/// cursor.move_next();
|
||||
/// }
|
||||
/// None
|
||||
/// }
|
||||
///
|
||||
/// // Use a cursor to remove the last element with the given value.
|
||||
/// fn remove_last(list: &mut List<ListItem>, value: u32) -> Option<ListArc<ListItem>> {
|
||||
/// let mut cursor = list.cursor_back();
|
||||
/// while let Some(prev) = cursor.peek_prev() {
|
||||
/// if prev.value == value {
|
||||
/// return Some(prev.remove());
|
||||
/// }
|
||||
/// cursor.move_prev();
|
||||
/// }
|
||||
/// None
|
||||
/// }
|
||||
///
|
||||
/// // Use a cursor to remove all elements with the given value. The removed elements are moved to
|
||||
/// // a new list.
|
||||
/// fn remove_all(list: &mut List<ListItem>, value: u32) -> List<ListItem> {
|
||||
/// let mut out = List::new();
|
||||
/// let mut cursor = list.cursor_front();
|
||||
/// while let Some(next) = cursor.peek_next() {
|
||||
/// if next.value == value {
|
||||
/// out.push_back(next.remove());
|
||||
/// } else {
|
||||
/// cursor.move_next();
|
||||
/// }
|
||||
/// }
|
||||
/// out
|
||||
/// }
|
||||
///
|
||||
/// // Use a cursor to insert a value at a specific index. Returns an error if the index is out of
|
||||
/// // bounds.
|
||||
/// fn insert_at(list: &mut List<ListItem>, new: ListArc<ListItem>, idx: usize) -> Result {
|
||||
/// let mut cursor = list.cursor_front();
|
||||
/// for _ in 0..idx {
|
||||
/// if !cursor.move_next() {
|
||||
/// return Err(EINVAL);
|
||||
/// }
|
||||
/// }
|
||||
/// cursor.insert_next(new);
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// // Merge two sorted lists into a single sorted list.
|
||||
/// fn merge_sorted(list: &mut List<ListItem>, merge: List<ListItem>) {
|
||||
/// let mut cursor = list.cursor_front();
|
||||
/// for to_insert in merge {
|
||||
/// while let Some(next) = cursor.peek_next() {
|
||||
/// if to_insert.value < next.value {
|
||||
/// break;
|
||||
/// }
|
||||
/// cursor.move_next();
|
||||
/// }
|
||||
/// cursor.insert_prev(to_insert);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut list = List::new();
|
||||
/// list.push_back(ListItem::new(14)?);
|
||||
/// list.push_back(ListItem::new(12)?);
|
||||
/// list.push_back(ListItem::new(10)?);
|
||||
/// list.push_back(ListItem::new(12)?);
|
||||
/// list.push_back(ListItem::new(15)?);
|
||||
/// list.push_back(ListItem::new(14)?);
|
||||
/// assert_eq!(remove_all(&mut list, 12).iter().count(), 2);
|
||||
/// // [14, 10, 15, 14]
|
||||
/// assert!(remove_first(&mut list, 14).is_some());
|
||||
/// // [10, 15, 14]
|
||||
/// insert_at(&mut list, ListItem::new(12)?, 2)?;
|
||||
/// // [10, 15, 12, 14]
|
||||
/// assert!(remove_last(&mut list, 15).is_some());
|
||||
/// // [10, 12, 14]
|
||||
///
|
||||
/// let mut list2 = List::new();
|
||||
/// list2.push_back(ListItem::new(11)?);
|
||||
/// list2.push_back(ListItem::new(13)?);
|
||||
/// merge_sorted(&mut list, list2);
|
||||
///
|
||||
/// let mut items = list.into_iter();
|
||||
/// assert_eq!(items.next().unwrap().value, 10);
|
||||
/// assert_eq!(items.next().unwrap().value, 11);
|
||||
/// assert_eq!(items.next().unwrap().value, 12);
|
||||
/// assert_eq!(items.next().unwrap().value, 13);
|
||||
/// assert_eq!(items.next().unwrap().value, 14);
|
||||
/// assert!(items.next().is_none());
|
||||
/// # Result::<(), Error>::Ok(())
|
||||
/// ```
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// The `current` pointer points a value in `list`.
|
||||
/// The `next` pointer is null or points a value in `list`.
|
||||
pub struct Cursor<'a, T: ?Sized + ListItem<ID>, const ID: u64 = 0> {
|
||||
current: *mut ListLinksFields,
|
||||
list: &'a mut List<T, ID>,
|
||||
/// Points at the element after this cursor, or null if the cursor is after the last element.
|
||||
next: *mut ListLinksFields,
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + ListItem<ID>, const ID: u64> Cursor<'a, T, ID> {
|
||||
/// Access the current element of this cursor.
|
||||
pub fn current(&self) -> ArcBorrow<'_, T> {
|
||||
// SAFETY: The `current` pointer points a value in the list.
|
||||
let me = unsafe { T::view_value(ListLinks::from_fields(self.current)) };
|
||||
/// Returns a pointer to the element before the cursor.
|
||||
///
|
||||
/// Returns null if there is no element before the cursor.
|
||||
fn prev_ptr(&self) -> *mut ListLinksFields {
|
||||
let mut next = self.next;
|
||||
let first = self.list.first;
|
||||
if next == first {
|
||||
// We are before the first element.
|
||||
return core::ptr::null_mut();
|
||||
}
|
||||
|
||||
if next.is_null() {
|
||||
// We are after the last element, so we need a pointer to the last element, which is
|
||||
// the same as `(*first).prev`.
|
||||
next = first;
|
||||
}
|
||||
|
||||
// SAFETY: `next` can't be null, because then `first` must also be null, but in that case
|
||||
// we would have exited at the `next == first` check. Thus, `next` is an element in the
|
||||
// list, so we can access its `prev` pointer.
|
||||
unsafe { (*next).prev }
|
||||
}
|
||||
|
||||
/// Access the element after this cursor.
|
||||
pub fn peek_next(&mut self) -> Option<CursorPeek<'_, 'a, T, true, ID>> {
|
||||
if self.next.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// INVARIANT:
|
||||
// * We just checked that `self.next` is non-null, so it must be in `self.list`.
|
||||
// * `ptr` is equal to `self.next`.
|
||||
Some(CursorPeek {
|
||||
ptr: self.next,
|
||||
cursor: self,
|
||||
})
|
||||
}
|
||||
|
||||
/// Access the element before this cursor.
|
||||
pub fn peek_prev(&mut self) -> Option<CursorPeek<'_, 'a, T, false, ID>> {
|
||||
let prev = self.prev_ptr();
|
||||
|
||||
if prev.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// INVARIANT:
|
||||
// * We just checked that `prev` is non-null, so it must be in `self.list`.
|
||||
// * `self.prev_ptr()` never returns `self.next`.
|
||||
Some(CursorPeek {
|
||||
ptr: prev,
|
||||
cursor: self,
|
||||
})
|
||||
}
|
||||
|
||||
/// Move the cursor one element forward.
|
||||
///
|
||||
/// If the cursor is after the last element, then this call does nothing. This call returns
|
||||
/// `true` if the cursor's position was changed.
|
||||
pub fn move_next(&mut self) -> bool {
|
||||
if self.next.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SAFETY: `self.next` is an element in the list and we borrow the list mutably, so we can
|
||||
// access the `next` field.
|
||||
let mut next = unsafe { (*self.next).next };
|
||||
|
||||
if next == self.list.first {
|
||||
next = core::ptr::null_mut();
|
||||
}
|
||||
|
||||
// INVARIANT: `next` is either null or the next element after an element in the list.
|
||||
self.next = next;
|
||||
true
|
||||
}
|
||||
|
||||
/// Move the cursor one element backwards.
|
||||
///
|
||||
/// If the cursor is before the first element, then this call does nothing. This call returns
|
||||
/// `true` if the cursor's position was changed.
|
||||
pub fn move_prev(&mut self) -> bool {
|
||||
if self.next == self.list.first {
|
||||
return false;
|
||||
}
|
||||
|
||||
// INVARIANT: `prev_ptr()` always returns a pointer that is null or in the list.
|
||||
self.next = self.prev_ptr();
|
||||
true
|
||||
}
|
||||
|
||||
/// Inserts an element where the cursor is pointing and get a pointer to the new element.
|
||||
fn insert_inner(&mut self, item: ListArc<T, ID>) -> *mut ListLinksFields {
|
||||
let ptr = if self.next.is_null() {
|
||||
self.list.first
|
||||
} else {
|
||||
self.next
|
||||
};
|
||||
// SAFETY:
|
||||
// * `ptr` is an element in the list or null.
|
||||
// * if `ptr` is null, then `self.list.first` is null so the list is empty.
|
||||
let item = unsafe { self.list.insert_inner(item, ptr) };
|
||||
if self.next == self.list.first {
|
||||
// INVARIANT: We just inserted `item`, so it's a member of list.
|
||||
self.list.first = item;
|
||||
}
|
||||
item
|
||||
}
|
||||
|
||||
/// Insert an element at this cursor's location.
|
||||
pub fn insert(mut self, item: ListArc<T, ID>) {
|
||||
// This is identical to `insert_prev`, but consumes the cursor. This is helpful because it
|
||||
// reduces confusion when the last operation on the cursor is an insertion; in that case,
|
||||
// you just want to insert the element at the cursor, and it is confusing that the call
|
||||
// involves the word prev or next.
|
||||
self.insert_inner(item);
|
||||
}
|
||||
|
||||
/// Inserts an element after this cursor.
|
||||
///
|
||||
/// After insertion, the new element will be after the cursor.
|
||||
pub fn insert_next(&mut self, item: ListArc<T, ID>) {
|
||||
self.next = self.insert_inner(item);
|
||||
}
|
||||
|
||||
/// Inserts an element before this cursor.
|
||||
///
|
||||
/// After insertion, the new element will be before the cursor.
|
||||
pub fn insert_prev(&mut self, item: ListArc<T, ID>) {
|
||||
self.insert_inner(item);
|
||||
}
|
||||
|
||||
/// Remove the next element from the list.
|
||||
pub fn remove_next(&mut self) -> Option<ListArc<T, ID>> {
|
||||
self.peek_next().map(|v| v.remove())
|
||||
}
|
||||
|
||||
/// Remove the previous element from the list.
|
||||
pub fn remove_prev(&mut self) -> Option<ListArc<T, ID>> {
|
||||
self.peek_prev().map(|v| v.remove())
|
||||
}
|
||||
}
|
||||
|
||||
/// References the element in the list next to the cursor.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// * `ptr` is an element in `self.cursor.list`.
|
||||
/// * `ISNEXT == (self.ptr == self.cursor.next)`.
|
||||
pub struct CursorPeek<'a, 'b, T: ?Sized + ListItem<ID>, const ISNEXT: bool, const ID: u64> {
|
||||
cursor: &'a mut Cursor<'b, T, ID>,
|
||||
ptr: *mut ListLinksFields,
|
||||
}
|
||||
|
||||
impl<'a, 'b, T: ?Sized + ListItem<ID>, const ISNEXT: bool, const ID: u64>
|
||||
CursorPeek<'a, 'b, T, ISNEXT, ID>
|
||||
{
|
||||
/// Remove the element from the list.
|
||||
pub fn remove(self) -> ListArc<T, ID> {
|
||||
if ISNEXT {
|
||||
self.cursor.move_next();
|
||||
}
|
||||
|
||||
// INVARIANT: `self.ptr` is not equal to `self.cursor.next` due to the above `move_next`
|
||||
// call.
|
||||
// SAFETY: By the type invariants of `Self`, `next` is not null, so `next` is an element of
|
||||
// `self.cursor.list` by the type invariants of `Cursor`.
|
||||
unsafe { self.cursor.list.remove_internal(self.ptr) }
|
||||
}
|
||||
|
||||
/// Access this value as an [`ArcBorrow`].
|
||||
pub fn arc(&self) -> ArcBorrow<'_, T> {
|
||||
// SAFETY: `self.ptr` points at an element in `self.cursor.list`.
|
||||
let me = unsafe { T::view_value(ListLinks::from_fields(self.ptr)) };
|
||||
// SAFETY:
|
||||
// * All values in a list are stored in an `Arc`.
|
||||
// * The value cannot be removed from the list for the duration of the lifetime annotated
|
||||
// on the returned `ArcBorrow`, because removing it from the list would require mutable
|
||||
// access to the cursor or the list. However, the `ArcBorrow` holds an immutable borrow
|
||||
// on the cursor, which in turn holds a mutable borrow on the list, so any such
|
||||
// mutable access requires first releasing the immutable borrow on the cursor.
|
||||
// access to the `CursorPeek`, the `Cursor` or the `List`. However, the `ArcBorrow` holds
|
||||
// an immutable borrow on the `CursorPeek`, which in turn holds a mutable borrow on the
|
||||
// `Cursor`, which in turn holds a mutable borrow on the `List`, so any such mutable
|
||||
// access requires first releasing the immutable borrow on the `CursorPeek`.
|
||||
// * Values in a list never have a `UniqueArc` reference, because the list has a `ListArc`
|
||||
// reference, and `UniqueArc` references must be unique.
|
||||
unsafe { ArcBorrow::from_raw(me) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the cursor to the next element.
|
||||
pub fn next(self) -> Option<Cursor<'a, T, ID>> {
|
||||
// SAFETY: The `current` field is always in a list.
|
||||
let next = unsafe { (*self.current).next };
|
||||
impl<'a, 'b, T: ?Sized + ListItem<ID>, const ISNEXT: bool, const ID: u64> core::ops::Deref
|
||||
for CursorPeek<'a, 'b, T, ISNEXT, ID>
|
||||
{
|
||||
// If you change the `ptr` field to have type `ArcBorrow<'a, T>`, it might seem like you could
|
||||
// get rid of the `CursorPeek::arc` method and change the deref target to `ArcBorrow<'a, T>`.
|
||||
// However, that doesn't work because 'a is too long. You could obtain an `ArcBorrow<'a, T>`
|
||||
// and then call `CursorPeek::remove` without giving up the `ArcBorrow<'a, T>`, which would be
|
||||
// unsound.
|
||||
type Target = T;
|
||||
|
||||
if next == self.list.first {
|
||||
None
|
||||
} else {
|
||||
// INVARIANT: Since `self.current` is in the `list`, its `next` pointer is also in the
|
||||
// `list`.
|
||||
Some(Cursor {
|
||||
current: next,
|
||||
list: self.list,
|
||||
})
|
||||
}
|
||||
}
|
||||
fn deref(&self) -> &T {
|
||||
// SAFETY: `self.ptr` points at an element in `self.cursor.list`.
|
||||
let me = unsafe { T::view_value(ListLinks::from_fields(self.ptr)) };
|
||||
|
||||
/// Move the cursor to the previous element.
|
||||
pub fn prev(self) -> Option<Cursor<'a, T, ID>> {
|
||||
// SAFETY: The `current` field is always in a list.
|
||||
let prev = unsafe { (*self.current).prev };
|
||||
|
||||
if self.current == self.list.first {
|
||||
None
|
||||
} else {
|
||||
// INVARIANT: Since `self.current` is in the `list`, its `prev` pointer is also in the
|
||||
// `list`.
|
||||
Some(Cursor {
|
||||
current: prev,
|
||||
list: self.list,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the current element from the list.
|
||||
pub fn remove(self) -> ListArc<T, ID> {
|
||||
// SAFETY: The `current` pointer always points at a member of the list.
|
||||
unsafe { self.list.remove_internal(self.current) }
|
||||
// SAFETY: The value cannot be removed from the list for the duration of the lifetime
|
||||
// annotated on the returned `&T`, because removing it from the list would require mutable
|
||||
// access to the `CursorPeek`, the `Cursor` or the `List`. However, the `&T` holds an
|
||||
// immutable borrow on the `CursorPeek`, which in turn holds a mutable borrow on the
|
||||
// `Cursor`, which in turn holds a mutable borrow on the `List`, so any such mutable access
|
||||
// requires first releasing the immutable borrow on the `CursorPeek`.
|
||||
unsafe { &*me }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,7 +790,7 @@ impl DeviceMask {
|
||||
/// DeviceId::new_with_driver::<PhySample>()
|
||||
/// ],
|
||||
/// name: "rust_sample_phy",
|
||||
/// author: "Rust for Linux Contributors",
|
||||
/// authors: ["Rust for Linux Contributors"],
|
||||
/// description: "Rust sample PHYs driver",
|
||||
/// license: "GPL",
|
||||
/// }
|
||||
@ -819,7 +819,7 @@ impl DeviceMask {
|
||||
/// module! {
|
||||
/// type: Module,
|
||||
/// name: "rust_sample_phy",
|
||||
/// author: "Rust for Linux Contributors",
|
||||
/// authors: ["Rust for Linux Contributors"],
|
||||
/// description: "Rust sample PHYs driver",
|
||||
/// license: "GPL",
|
||||
/// }
|
||||
|
@ -103,7 +103,7 @@ impl<T: Driver + 'static> Adapter<T> {
|
||||
/// kernel::module_pci_driver! {
|
||||
/// type: MyDriver,
|
||||
/// name: "Module name",
|
||||
/// author: "Author name",
|
||||
/// authors: ["Author name"],
|
||||
/// description: "Description",
|
||||
/// license: "GPL v2",
|
||||
/// }
|
||||
|
@ -101,7 +101,7 @@ impl<T: Driver + 'static> driver::Adapter for Adapter<T> {
|
||||
/// kernel::module_platform_driver! {
|
||||
/// type: MyDriver,
|
||||
/// name: "Module name",
|
||||
/// author: "Author name",
|
||||
/// authors: ["Author name"],
|
||||
/// description: "Description",
|
||||
/// license: "GPL v2",
|
||||
/// }
|
||||
|
@ -17,7 +17,9 @@ pub use core::pin::Pin;
|
||||
pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec};
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
|
||||
pub use macros::{export, module, vtable};
|
||||
|
||||
pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable};
|
||||
|
||||
pub use super::{build_assert, build_error};
|
||||
|
||||
@ -28,7 +30,7 @@ pub use super::fmt;
|
||||
pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
|
||||
pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
|
||||
|
||||
pub use super::{init, pin_init, try_init, try_pin_init};
|
||||
pub use super::{try_init, try_pin_init};
|
||||
|
||||
pub use super::static_assert;
|
||||
|
||||
@ -36,6 +38,6 @@ pub use super::error::{code::*, Error, Result};
|
||||
|
||||
pub use super::{str::CStr, ThisModule};
|
||||
|
||||
pub use super::init::{InPlaceInit, InPlaceWrite, Init, PinInit};
|
||||
pub use super::init::InPlaceInit;
|
||||
|
||||
pub use super::current;
|
||||
|
@ -6,16 +6,16 @@
|
||||
//!
|
||||
//! Reference: <https://docs.kernel.org/core-api/printk-basics.html>
|
||||
|
||||
use core::{
|
||||
use crate::{
|
||||
ffi::{c_char, c_void},
|
||||
fmt,
|
||||
prelude::*,
|
||||
str::RawFormatter,
|
||||
};
|
||||
|
||||
use crate::str::RawFormatter;
|
||||
use core::fmt;
|
||||
|
||||
// Called from `vsprintf` with format specifier `%pA`.
|
||||
#[expect(clippy::missing_safety_doc)]
|
||||
#[no_mangle]
|
||||
#[export]
|
||||
unsafe extern "C" fn rust_fmt_argument(
|
||||
buf: *mut c_char,
|
||||
end: *mut c_char,
|
||||
|
@ -886,7 +886,7 @@ impl<'a, K, V> Cursor<'a, K, V> {
|
||||
/// # Safety
|
||||
///
|
||||
/// - `node` must be a valid pointer to a node in an [`RBTree`].
|
||||
/// - The caller has immutable access to `node` for the duration of 'b.
|
||||
/// - The caller has immutable access to `node` for the duration of `'b`.
|
||||
unsafe fn to_key_value<'b>(node: NonNull<bindings::rb_node>) -> (&'b K, &'b V) {
|
||||
// SAFETY: the caller guarantees that `node` is a valid pointer in an `RBTree`.
|
||||
let (k, v) = unsafe { Self::to_key_value_raw(node) };
|
||||
@ -897,7 +897,7 @@ impl<'a, K, V> Cursor<'a, K, V> {
|
||||
/// # Safety
|
||||
///
|
||||
/// - `node` must be a valid pointer to a node in an [`RBTree`].
|
||||
/// - The caller has mutable access to `node` for the duration of 'b.
|
||||
/// - The caller has mutable access to `node` for the duration of `'b`.
|
||||
unsafe fn to_key_value_mut<'b>(node: NonNull<bindings::rb_node>) -> (&'b K, &'b mut V) {
|
||||
// SAFETY: the caller guarantees that `node` is a valid pointer in an `RBTree`.
|
||||
let (k, v) = unsafe { Self::to_key_value_raw(node) };
|
||||
@ -908,7 +908,7 @@ impl<'a, K, V> Cursor<'a, K, V> {
|
||||
/// # Safety
|
||||
///
|
||||
/// - `node` must be a valid pointer to a node in an [`RBTree`].
|
||||
/// - The caller has immutable access to the key for the duration of 'b.
|
||||
/// - The caller has immutable access to the key for the duration of `'b`.
|
||||
unsafe fn to_key_value_raw<'b>(node: NonNull<bindings::rb_node>) -> (&'b K, *mut V) {
|
||||
// SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
|
||||
// point to the links field of `Node<K, V>` objects.
|
||||
@ -1168,12 +1168,12 @@ impl<'a, K, V> RawVacantEntry<'a, K, V> {
|
||||
fn insert(self, node: RBTreeNode<K, V>) -> &'a mut V {
|
||||
let node = KBox::into_raw(node.node);
|
||||
|
||||
// SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
|
||||
// SAFETY: `node` is valid at least until we call `KBox::from_raw`, which only happens when
|
||||
// the node is removed or replaced.
|
||||
let node_links = unsafe { addr_of_mut!((*node).links) };
|
||||
|
||||
// INVARIANT: We are linking in a new node, which is valid. It remains valid because we
|
||||
// "forgot" it with `Box::into_raw`.
|
||||
// "forgot" it with `KBox::into_raw`.
|
||||
// SAFETY: The type invariants of `RawVacantEntry` are exactly the safety requirements of `rb_link_node`.
|
||||
unsafe { bindings::rb_link_node(node_links, self.parent, self.child_field_of_parent) };
|
||||
|
||||
@ -1259,7 +1259,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
|
||||
fn replace(self, node: RBTreeNode<K, V>) -> RBTreeNode<K, V> {
|
||||
let node = KBox::into_raw(node.node);
|
||||
|
||||
// SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
|
||||
// SAFETY: `node` is valid at least until we call `KBox::from_raw`, which only happens when
|
||||
// the node is removed or replaced.
|
||||
let new_node_links = unsafe { addr_of_mut!((*node).links) };
|
||||
|
||||
|
@ -18,7 +18,7 @@ impl SeqFile {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that for the duration of 'a the following is satisfied:
|
||||
/// The caller must ensure that for the duration of `'a` the following is satisfied:
|
||||
/// * The pointer points at a valid `struct seq_file`.
|
||||
/// * The `struct seq_file` is not accessed from any other thread.
|
||||
pub unsafe fn from_raw<'a>(ptr: *mut bindings::seq_file) -> &'a SeqFile {
|
||||
|
@ -31,6 +31,23 @@ impl BStr {
|
||||
// SAFETY: `BStr` is transparent to `[u8]`.
|
||||
unsafe { &*(bytes as *const [u8] as *const BStr) }
|
||||
}
|
||||
|
||||
/// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use kernel::b_str;
|
||||
/// assert_eq!(Some(b_str!("bar")), b_str!("foobar").strip_prefix(b_str!("foo")));
|
||||
/// assert_eq!(None, b_str!("foobar").strip_prefix(b_str!("bar")));
|
||||
/// assert_eq!(Some(b_str!("foobar")), b_str!("foobar").strip_prefix(b_str!("")));
|
||||
/// assert_eq!(Some(b_str!("")), b_str!("foobar").strip_prefix(b_str!("foobar")));
|
||||
/// ```
|
||||
pub fn strip_prefix(&self, pattern: impl AsRef<Self>) -> Option<&BStr> {
|
||||
self.deref()
|
||||
.strip_prefix(pattern.as_ref().deref())
|
||||
.map(Self::from_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BStr {
|
||||
@ -108,6 +125,35 @@ impl Deref for BStr {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for BStr {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.deref().eq(other.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx> Index<Idx> for BStr
|
||||
where
|
||||
[u8]: Index<Idx, Output = [u8]>,
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
fn index(&self, index: Idx) -> &Self::Output {
|
||||
BStr::from_bytes(&self.0[index])
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<BStr> for [u8] {
|
||||
fn as_ref(&self) -> &BStr {
|
||||
BStr::from_bytes(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<BStr> for BStr {
|
||||
fn as_ref(&self) -> &BStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new [`BStr`] from a string literal.
|
||||
///
|
||||
/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
|
||||
|
@ -5,9 +5,9 @@
|
||||
//! This module contains the kernel APIs related to synchronisation that have been ported or
|
||||
//! wrapped for usage by Rust code in the kernel.
|
||||
|
||||
use crate::pin_init;
|
||||
use crate::prelude::*;
|
||||
use crate::types::Opaque;
|
||||
use pin_init;
|
||||
|
||||
mod arc;
|
||||
mod condvar;
|
||||
@ -41,10 +41,11 @@ impl LockClassKey {
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use kernel::{c_str, stack_pin_init};
|
||||
/// # use kernel::c_str;
|
||||
/// # use kernel::alloc::KBox;
|
||||
/// # use kernel::types::ForeignOwnable;
|
||||
/// # use kernel::sync::{LockClassKey, SpinLock};
|
||||
/// # use pin_init::stack_pin_init;
|
||||
///
|
||||
/// let key = KBox::pin_init(LockClassKey::new_dynamic(), GFP_KERNEL)?;
|
||||
/// let key_ptr = key.into_foreign();
|
||||
|
@ -19,7 +19,7 @@
|
||||
use crate::{
|
||||
alloc::{AllocError, Flags, KBox},
|
||||
bindings,
|
||||
init::{self, InPlaceInit, Init, PinInit},
|
||||
init::InPlaceInit,
|
||||
try_init,
|
||||
types::{ForeignOwnable, Opaque},
|
||||
};
|
||||
@ -32,7 +32,7 @@ use core::{
|
||||
pin::Pin,
|
||||
ptr::NonNull,
|
||||
};
|
||||
use macros::pin_data;
|
||||
use pin_init::{self, pin_data, InPlaceWrite, Init, PinInit};
|
||||
|
||||
mod std_vendor;
|
||||
|
||||
@ -202,6 +202,26 @@ unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
|
||||
// the reference count reaches zero and `T` is dropped.
|
||||
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
|
||||
|
||||
impl<T> InPlaceInit<T> for Arc<T> {
|
||||
type PinnedSelf = Self;
|
||||
|
||||
#[inline]
|
||||
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
|
||||
where
|
||||
E: From<AllocError>,
|
||||
{
|
||||
UniqueArc::try_pin_init(init, flags).map(|u| u.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
|
||||
where
|
||||
E: From<AllocError>,
|
||||
{
|
||||
UniqueArc::try_init(init, flags).map(|u| u.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Arc<T> {
|
||||
/// Constructs a new reference counted instance of `T`.
|
||||
pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
|
||||
@ -246,6 +266,15 @@ impl<T: ?Sized> Arc<T> {
|
||||
unsafe { core::ptr::addr_of!((*ptr).data) }
|
||||
}
|
||||
|
||||
/// Return a raw pointer to the data in this arc.
|
||||
pub fn as_ptr(this: &Self) -> *const T {
|
||||
let ptr = this.ptr.as_ptr();
|
||||
|
||||
// SAFETY: As `ptr` points to a valid allocation of type `ArcInner`,
|
||||
// field projection to `data`is within bounds of the allocation.
|
||||
unsafe { core::ptr::addr_of!((*ptr).data) }
|
||||
}
|
||||
|
||||
/// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`].
|
||||
///
|
||||
/// # Safety
|
||||
@ -539,11 +568,11 @@ impl<T: ?Sized> ArcBorrow<'_, T> {
|
||||
}
|
||||
|
||||
/// Creates an [`ArcBorrow`] to an [`Arc`] that has previously been deconstructed with
|
||||
/// [`Arc::into_raw`].
|
||||
/// [`Arc::into_raw`] or [`Arc::as_ptr`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * The provided pointer must originate from a call to [`Arc::into_raw`].
|
||||
/// * The provided pointer must originate from a call to [`Arc::into_raw`] or [`Arc::as_ptr`].
|
||||
/// * For the duration of the lifetime annotated on this `ArcBorrow`, the reference count must
|
||||
/// not hit zero.
|
||||
/// * For the duration of the lifetime annotated on this `ArcBorrow`, there must not be a
|
||||
@ -659,6 +688,48 @@ pub struct UniqueArc<T: ?Sized> {
|
||||
inner: Arc<T>,
|
||||
}
|
||||
|
||||
impl<T> InPlaceInit<T> for UniqueArc<T> {
|
||||
type PinnedSelf = Pin<Self>;
|
||||
|
||||
#[inline]
|
||||
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
|
||||
where
|
||||
E: From<AllocError>,
|
||||
{
|
||||
UniqueArc::new_uninit(flags)?.write_pin_init(init)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
|
||||
where
|
||||
E: From<AllocError>,
|
||||
{
|
||||
UniqueArc::new_uninit(flags)?.write_init(init)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> {
|
||||
type Initialized = UniqueArc<T>;
|
||||
|
||||
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
|
||||
let slot = self.as_mut_ptr();
|
||||
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
|
||||
// slot is valid.
|
||||
unsafe { init.__init(slot)? };
|
||||
// SAFETY: All fields have been initialized.
|
||||
Ok(unsafe { self.assume_init() })
|
||||
}
|
||||
|
||||
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
|
||||
let slot = self.as_mut_ptr();
|
||||
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
|
||||
// slot is valid and will not be moved, because we pin it later.
|
||||
unsafe { init.__pinned_init(slot)? };
|
||||
// SAFETY: All fields have been initialized.
|
||||
Ok(unsafe { self.assume_init() }.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UniqueArc<T> {
|
||||
/// Tries to allocate a new [`UniqueArc`] instance.
|
||||
pub fn new(value: T, flags: Flags) -> Result<Self, AllocError> {
|
||||
@ -675,7 +746,7 @@ impl<T> UniqueArc<T> {
|
||||
try_init!(ArcInner {
|
||||
// SAFETY: There are no safety requirements for this FFI call.
|
||||
refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
|
||||
data <- init::uninit::<T, AllocError>(),
|
||||
data <- pin_init::uninit::<T, AllocError>(),
|
||||
}? AllocError),
|
||||
flags,
|
||||
)?;
|
||||
|
@ -8,8 +8,6 @@
|
||||
use super::{lock::Backend, lock::Guard, LockClassKey};
|
||||
use crate::{
|
||||
ffi::{c_int, c_long},
|
||||
init::PinInit,
|
||||
pin_init,
|
||||
str::CStr,
|
||||
task::{
|
||||
MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE,
|
||||
@ -18,7 +16,7 @@ use crate::{
|
||||
types::Opaque,
|
||||
};
|
||||
use core::{marker::PhantomPinned, pin::Pin, ptr};
|
||||
use macros::pin_data;
|
||||
use pin_init::{pin_data, pin_init, PinInit};
|
||||
|
||||
/// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class.
|
||||
#[macro_export]
|
||||
@ -38,7 +36,7 @@ pub use new_condvar;
|
||||
/// spuriously.
|
||||
///
|
||||
/// Instances of [`CondVar`] need a lock class and to be pinned. The recommended way to create such
|
||||
/// instances is with the [`pin_init`](crate::pin_init) and [`new_condvar`] macros.
|
||||
/// instances is with the [`pin_init`](crate::pin_init!) and [`new_condvar`] macros.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -7,13 +7,11 @@
|
||||
|
||||
use super::LockClassKey;
|
||||
use crate::{
|
||||
init::PinInit,
|
||||
pin_init,
|
||||
str::CStr,
|
||||
types::{NotThreadSafe, Opaque, ScopeGuard},
|
||||
};
|
||||
use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
|
||||
use macros::pin_data;
|
||||
use pin_init::{pin_data, pin_init, PinInit};
|
||||
|
||||
pub mod mutex;
|
||||
pub mod spinlock;
|
||||
@ -208,7 +206,8 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
|
||||
/// lock is held.
|
||||
///
|
||||
/// ```
|
||||
/// # use kernel::{new_spinlock, stack_pin_init, sync::lock::{Backend, Guard, Lock}};
|
||||
/// # use kernel::{new_spinlock, sync::lock::{Backend, Guard, Lock}};
|
||||
/// # use pin_init::stack_pin_init;
|
||||
///
|
||||
/// fn assert_held<T, B: Backend>(guard: &Guard<'_, T, B>, lock: &Lock<T, B>) {
|
||||
/// // Address-equal means the same lock.
|
||||
|
@ -26,7 +26,7 @@ pub use new_mutex;
|
||||
/// Since it may block, [`Mutex`] needs to be used with care in atomic contexts.
|
||||
///
|
||||
/// Instances of [`Mutex`] need a lock class and to be pinned. The recommended way to create such
|
||||
/// instances is with the [`pin_init`](crate::pin_init) and [`new_mutex`] macros.
|
||||
/// instances is with the [`pin_init`](pin_init::pin_init) and [`new_mutex`] macros.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -24,7 +24,7 @@ pub use new_spinlock;
|
||||
/// unlocked, at which point another CPU will be allowed to make progress.
|
||||
///
|
||||
/// Instances of [`SpinLock`] need a lock class and to be pinned. The recommended way to create such
|
||||
/// instances is with the [`pin_init`](crate::pin_init) and [`new_spinlock`] macros.
|
||||
/// instances is with the [`pin_init`](pin_init::pin_init) and [`new_spinlock`] macros.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -43,11 +43,11 @@ impl PollTable {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that for the duration of 'a, the pointer will point at a valid poll
|
||||
/// The caller must ensure that for the duration of `'a`, the pointer will point at a valid poll
|
||||
/// table (as defined in the type invariants).
|
||||
///
|
||||
/// The caller must also ensure that the `poll_table` is only accessed via the returned
|
||||
/// reference for the duration of 'a.
|
||||
/// reference for the duration of `'a`.
|
||||
pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut PollTable {
|
||||
// SAFETY: The safety requirements guarantee the validity of the dereference, while the
|
||||
// `PollTable` type being transparent makes the cast ok.
|
||||
|
@ -108,7 +108,7 @@ unsafe impl Send for Task {}
|
||||
unsafe impl Sync for Task {}
|
||||
|
||||
/// The type of process identifiers (PIDs).
|
||||
type Pid = bindings::pid_t;
|
||||
pub type Pid = bindings::pid_t;
|
||||
|
||||
/// The type of user identifiers (UIDs).
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -8,6 +8,8 @@
|
||||
//! C header: [`include/linux/jiffies.h`](srctree/include/linux/jiffies.h).
|
||||
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).
|
||||
|
||||
pub mod hrtimer;
|
||||
|
||||
/// The number of nanoseconds per millisecond.
|
||||
pub const NSEC_PER_MSEC: i64 = bindings::NSEC_PER_MSEC as i64;
|
||||
|
||||
@ -81,3 +83,69 @@ impl core::ops::Sub for Ktime {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier for a clock. Used when specifying clock sources.
|
||||
///
|
||||
///
|
||||
/// Selection of the clock depends on the use case. In some cases the usage of a
|
||||
/// particular clock is mandatory, e.g. in network protocols, filesystems.In other
|
||||
/// cases the user of the clock has to decide which clock is best suited for the
|
||||
/// purpose. In most scenarios clock [`ClockId::Monotonic`] is the best choice as it
|
||||
/// provides a accurate monotonic notion of time (leap second smearing ignored).
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum ClockId {
|
||||
/// A settable system-wide clock that measures real (i.e., wall-clock) time.
|
||||
///
|
||||
/// Setting this clock requires appropriate privileges. This clock is
|
||||
/// affected by discontinuous jumps in the system time (e.g., if the system
|
||||
/// administrator manually changes the clock), and by frequency adjustments
|
||||
/// performed by NTP and similar applications via adjtime(3), adjtimex(2),
|
||||
/// clock_adjtime(2), and ntp_adjtime(3). This clock normally counts the
|
||||
/// number of seconds since 1970-01-01 00:00:00 Coordinated Universal Time
|
||||
/// (UTC) except that it ignores leap seconds; near a leap second it may be
|
||||
/// adjusted by leap second smearing to stay roughly in sync with UTC. Leap
|
||||
/// second smearing applies frequency adjustments to the clock to speed up
|
||||
/// or slow down the clock to account for the leap second without
|
||||
/// discontinuities in the clock. If leap second smearing is not applied,
|
||||
/// the clock will experience discontinuity around leap second adjustment.
|
||||
RealTime = bindings::CLOCK_REALTIME,
|
||||
/// A monotonically increasing clock.
|
||||
///
|
||||
/// A nonsettable system-wide clock that represents monotonic time since—as
|
||||
/// described by POSIX—"some unspecified point in the past". On Linux, that
|
||||
/// point corresponds to the number of seconds that the system has been
|
||||
/// running since it was booted.
|
||||
///
|
||||
/// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the
|
||||
/// CLOCK_REAL (e.g., if the system administrator manually changes the
|
||||
/// clock), but is affected by frequency adjustments. This clock does not
|
||||
/// count time that the system is suspended.
|
||||
Monotonic = bindings::CLOCK_MONOTONIC,
|
||||
/// A monotonic that ticks while system is suspended.
|
||||
///
|
||||
/// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC,
|
||||
/// except that it also includes any time that the system is suspended. This
|
||||
/// allows applications to get a suspend-aware monotonic clock without
|
||||
/// having to deal with the complications of CLOCK_REALTIME, which may have
|
||||
/// discontinuities if the time is changed using settimeofday(2) or similar.
|
||||
BootTime = bindings::CLOCK_BOOTTIME,
|
||||
/// International Atomic Time.
|
||||
///
|
||||
/// A system-wide clock derived from wall-clock time but counting leap seconds.
|
||||
///
|
||||
/// This clock is coupled to CLOCK_REALTIME and will be set when CLOCK_REALTIME is
|
||||
/// set, or when the offset to CLOCK_REALTIME is changed via adjtimex(2). This
|
||||
/// usually happens during boot and **should** not happen during normal operations.
|
||||
/// However, if NTP or another application adjusts CLOCK_REALTIME by leap second
|
||||
/// smearing, this clock will not be precise during leap second smearing.
|
||||
///
|
||||
/// The acronym TAI refers to International Atomic Time.
|
||||
TAI = bindings::CLOCK_TAI,
|
||||
}
|
||||
|
||||
impl ClockId {
|
||||
fn into_c(self) -> bindings::clockid_t {
|
||||
self as bindings::clockid_t
|
||||
}
|
||||
}
|
||||
|
520
rust/kernel/time/hrtimer.rs
Normal file
520
rust/kernel/time/hrtimer.rs
Normal file
@ -0,0 +1,520 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! Intrusive high resolution timers.
|
||||
//!
|
||||
//! Allows running timer callbacks without doing allocations at the time of
|
||||
//! starting the timer. For now, only one timer per type is allowed.
|
||||
//!
|
||||
//! # Vocabulary
|
||||
//!
|
||||
//! States:
|
||||
//!
|
||||
//! - Stopped: initialized but not started, or cancelled, or not restarted.
|
||||
//! - Started: initialized and started or restarted.
|
||||
//! - Running: executing the callback.
|
||||
//!
|
||||
//! Operations:
|
||||
//!
|
||||
//! * Start
|
||||
//! * Cancel
|
||||
//! * Restart
|
||||
//!
|
||||
//! Events:
|
||||
//!
|
||||
//! * Expire
|
||||
//!
|
||||
//! ## State Diagram
|
||||
//!
|
||||
//! ```text
|
||||
//! Return NoRestart
|
||||
//! +---------------------------------------------------------------------+
|
||||
//! | |
|
||||
//! | |
|
||||
//! | |
|
||||
//! | Return Restart |
|
||||
//! | +------------------------+ |
|
||||
//! | | | |
|
||||
//! | | | |
|
||||
//! v v | |
|
||||
//! +-----------------+ Start +------------------+ +--------+-----+--+
|
||||
//! | +---------------->| | | |
|
||||
//! Init | | | | Expire | |
|
||||
//! --------->| Stopped | | Started +---------->| Running |
|
||||
//! | | Cancel | | | |
|
||||
//! | |<----------------+ | | |
|
||||
//! +-----------------+ +---------------+--+ +-----------------+
|
||||
//! ^ |
|
||||
//! | |
|
||||
//! +---------+
|
||||
//! Restart
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! A timer is initialized in the **stopped** state. A stopped timer can be
|
||||
//! **started** by the `start` operation, with an **expiry** time. After the
|
||||
//! `start` operation, the timer is in the **started** state. When the timer
|
||||
//! **expires**, the timer enters the **running** state and the handler is
|
||||
//! executed. After the handler has returned, the timer may enter the
|
||||
//! **started* or **stopped** state, depending on the return value of the
|
||||
//! handler. A timer in the **started** or **running** state may be **canceled**
|
||||
//! by the `cancel` operation. A timer that is cancelled enters the **stopped**
|
||||
//! state.
|
||||
//!
|
||||
//! A `cancel` or `restart` operation on a timer in the **running** state takes
|
||||
//! effect after the handler has returned and the timer has transitioned
|
||||
//! out of the **running** state.
|
||||
//!
|
||||
//! A `restart` operation on a timer in the **stopped** state is equivalent to a
|
||||
//! `start` operation.
|
||||
|
||||
use super::ClockId;
|
||||
use crate::{prelude::*, time::Ktime, types::Opaque};
|
||||
use core::marker::PhantomData;
|
||||
use pin_init::PinInit;
|
||||
|
||||
/// A timer backed by a C `struct hrtimer`.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// * `self.timer` is initialized by `bindings::hrtimer_setup`.
|
||||
#[pin_data]
|
||||
#[repr(C)]
|
||||
pub struct HrTimer<T> {
|
||||
#[pin]
|
||||
timer: Opaque<bindings::hrtimer>,
|
||||
mode: HrTimerMode,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
// SAFETY: Ownership of an `HrTimer` can be moved to other threads and
|
||||
// used/dropped from there.
|
||||
unsafe impl<T> Send for HrTimer<T> {}
|
||||
|
||||
// SAFETY: Timer operations are locked on the C side, so it is safe to operate
|
||||
// on a timer from multiple threads.
|
||||
unsafe impl<T> Sync for HrTimer<T> {}
|
||||
|
||||
impl<T> HrTimer<T> {
|
||||
/// Return an initializer for a new timer instance.
|
||||
pub fn new(mode: HrTimerMode, clock: ClockId) -> impl PinInit<Self>
|
||||
where
|
||||
T: HrTimerCallback,
|
||||
{
|
||||
pin_init!(Self {
|
||||
// INVARIANT: We initialize `timer` with `hrtimer_setup` below.
|
||||
timer <- Opaque::ffi_init(move |place: *mut bindings::hrtimer| {
|
||||
// SAFETY: By design of `pin_init!`, `place` is a pointer to a
|
||||
// live allocation. hrtimer_setup will initialize `place` and
|
||||
// does not require `place` to be initialized prior to the call.
|
||||
unsafe {
|
||||
bindings::hrtimer_setup(
|
||||
place,
|
||||
Some(T::Pointer::run),
|
||||
clock.into_c(),
|
||||
mode.into_c(),
|
||||
);
|
||||
}
|
||||
}),
|
||||
mode: mode,
|
||||
_t: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a pointer to the contained `bindings::hrtimer`.
|
||||
///
|
||||
/// This function is useful to get access to the value without creating
|
||||
/// intermediate references.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `this` must point to a live allocation of at least the size of `Self`.
|
||||
unsafe fn raw_get(this: *const Self) -> *mut bindings::hrtimer {
|
||||
// SAFETY: The field projection to `timer` does not go out of bounds,
|
||||
// because the caller of this function promises that `this` points to an
|
||||
// allocation of at least the size of `Self`.
|
||||
unsafe { Opaque::raw_get(core::ptr::addr_of!((*this).timer)) }
|
||||
}
|
||||
|
||||
/// Cancel an initialized and potentially running timer.
|
||||
///
|
||||
/// If the timer handler is running, this function will block until the
|
||||
/// handler returns.
|
||||
///
|
||||
/// Note that the timer might be started by a concurrent start operation. If
|
||||
/// so, the timer might not be in the **stopped** state when this function
|
||||
/// returns.
|
||||
///
|
||||
/// Users of the `HrTimer` API would not usually call this method directly.
|
||||
/// Instead they would use the safe [`HrTimerHandle::cancel`] on the handle
|
||||
/// returned when the timer was started.
|
||||
///
|
||||
/// This function is useful to get access to the value without creating
|
||||
/// intermediate references.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `this` must point to a valid `Self`.
|
||||
pub(crate) unsafe fn raw_cancel(this: *const Self) -> bool {
|
||||
// SAFETY: `this` points to an allocation of at least `HrTimer` size.
|
||||
let c_timer_ptr = unsafe { HrTimer::raw_get(this) };
|
||||
|
||||
// If the handler is running, this will wait for the handler to return
|
||||
// before returning.
|
||||
// SAFETY: `c_timer_ptr` is initialized and valid. Synchronization is
|
||||
// handled on the C side.
|
||||
unsafe { bindings::hrtimer_cancel(c_timer_ptr) != 0 }
|
||||
}
|
||||
}
|
||||
|
||||
/// Implemented by pointer types that point to structs that contain a [`HrTimer`].
|
||||
///
|
||||
/// `Self` must be [`Sync`] because it is passed to timer callbacks in another
|
||||
/// thread of execution (hard or soft interrupt context).
|
||||
///
|
||||
/// Starting a timer returns a [`HrTimerHandle`] that can be used to manipulate
|
||||
/// the timer. Note that it is OK to call the start function repeatedly, and
|
||||
/// that more than one [`HrTimerHandle`] associated with a [`HrTimerPointer`] may
|
||||
/// exist. A timer can be manipulated through any of the handles, and a handle
|
||||
/// may represent a cancelled timer.
|
||||
pub trait HrTimerPointer: Sync + Sized {
|
||||
/// A handle representing a started or restarted timer.
|
||||
///
|
||||
/// If the timer is running or if the timer callback is executing when the
|
||||
/// handle is dropped, the drop method of [`HrTimerHandle`] should not return
|
||||
/// until the timer is stopped and the callback has completed.
|
||||
///
|
||||
/// Note: When implementing this trait, consider that it is not unsafe to
|
||||
/// leak the handle.
|
||||
type TimerHandle: HrTimerHandle;
|
||||
|
||||
/// Start the timer with expiry after `expires` time units. If the timer was
|
||||
/// already running, it is restarted with the new expiry time.
|
||||
fn start(self, expires: Ktime) -> Self::TimerHandle;
|
||||
}
|
||||
|
||||
/// Unsafe version of [`HrTimerPointer`] for situations where leaking the
|
||||
/// [`HrTimerHandle`] returned by `start` would be unsound. This is the case for
|
||||
/// stack allocated timers.
|
||||
///
|
||||
/// Typical implementers are pinned references such as [`Pin<&T>`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Implementers of this trait must ensure that instances of types implementing
|
||||
/// [`UnsafeHrTimerPointer`] outlives any associated [`HrTimerPointer::TimerHandle`]
|
||||
/// instances.
|
||||
pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
|
||||
/// A handle representing a running timer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If the timer is running, or if the timer callback is executing when the
|
||||
/// handle is dropped, the drop method of [`Self::TimerHandle`] must not return
|
||||
/// until the timer is stopped and the callback has completed.
|
||||
type TimerHandle: HrTimerHandle;
|
||||
|
||||
/// Start the timer after `expires` time units. If the timer was already
|
||||
/// running, it is restarted at the new expiry time.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Caller promises keep the timer structure alive until the timer is dead.
|
||||
/// Caller can ensure this by not leaking the returned [`Self::TimerHandle`].
|
||||
unsafe fn start(self, expires: Ktime) -> Self::TimerHandle;
|
||||
}
|
||||
|
||||
/// A trait for stack allocated timers.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Implementers must ensure that `start_scoped` does not return until the
|
||||
/// timer is dead and the timer handler is not running.
|
||||
pub unsafe trait ScopedHrTimerPointer {
|
||||
/// Start the timer to run after `expires` time units and immediately
|
||||
/// after call `f`. When `f` returns, the timer is cancelled.
|
||||
fn start_scoped<T, F>(self, expires: Ktime, f: F) -> T
|
||||
where
|
||||
F: FnOnce() -> T;
|
||||
}
|
||||
|
||||
// SAFETY: By the safety requirement of [`UnsafeHrTimerPointer`], dropping the
|
||||
// handle returned by [`UnsafeHrTimerPointer::start`] ensures that the timer is
|
||||
// killed.
|
||||
unsafe impl<T> ScopedHrTimerPointer for T
|
||||
where
|
||||
T: UnsafeHrTimerPointer,
|
||||
{
|
||||
fn start_scoped<U, F>(self, expires: Ktime, f: F) -> U
|
||||
where
|
||||
F: FnOnce() -> U,
|
||||
{
|
||||
// SAFETY: We drop the timer handle below before returning.
|
||||
let handle = unsafe { UnsafeHrTimerPointer::start(self, expires) };
|
||||
let t = f();
|
||||
drop(handle);
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
/// Implemented by [`HrTimerPointer`] implementers to give the C timer callback a
|
||||
/// function to call.
|
||||
// This is split from `HrTimerPointer` to make it easier to specify trait bounds.
|
||||
pub trait RawHrTimerCallback {
|
||||
/// Type of the parameter passed to [`HrTimerCallback::run`]. It may be
|
||||
/// [`Self`], or a pointer type derived from [`Self`].
|
||||
type CallbackTarget<'a>;
|
||||
|
||||
/// Callback to be called from C when timer fires.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Only to be called by C code in the `hrtimer` subsystem. `this` must point
|
||||
/// to the `bindings::hrtimer` structure that was used to start the timer.
|
||||
unsafe extern "C" fn run(this: *mut bindings::hrtimer) -> bindings::hrtimer_restart;
|
||||
}
|
||||
|
||||
/// Implemented by structs that can be the target of a timer callback.
|
||||
pub trait HrTimerCallback {
|
||||
/// The type whose [`RawHrTimerCallback::run`] method will be invoked when
|
||||
/// the timer expires.
|
||||
type Pointer<'a>: RawHrTimerCallback;
|
||||
|
||||
/// Called by the timer logic when the timer fires.
|
||||
fn run(this: <Self::Pointer<'_> as RawHrTimerCallback>::CallbackTarget<'_>) -> HrTimerRestart
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
/// A handle representing a potentially running timer.
|
||||
///
|
||||
/// More than one handle representing the same timer might exist.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When dropped, the timer represented by this handle must be cancelled, if it
|
||||
/// is running. If the timer handler is running when the handle is dropped, the
|
||||
/// drop method must wait for the handler to return before returning.
|
||||
///
|
||||
/// Note: One way to satisfy the safety requirement is to call `Self::cancel` in
|
||||
/// the drop implementation for `Self.`
|
||||
pub unsafe trait HrTimerHandle {
|
||||
/// Cancel the timer. If the timer is in the running state, block till the
|
||||
/// handler has returned.
|
||||
///
|
||||
/// Note that the timer might be started by a concurrent start operation. If
|
||||
/// so, the timer might not be in the **stopped** state when this function
|
||||
/// returns.
|
||||
fn cancel(&mut self) -> bool;
|
||||
}
|
||||
|
||||
/// Implemented by structs that contain timer nodes.
|
||||
///
|
||||
/// Clients of the timer API would usually safely implement this trait by using
|
||||
/// the [`crate::impl_has_hr_timer`] macro.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Implementers of this trait must ensure that the implementer has a
|
||||
/// [`HrTimer`] field and that all trait methods are implemented according to
|
||||
/// their documentation. All the methods of this trait must operate on the same
|
||||
/// field.
|
||||
pub unsafe trait HasHrTimer<T> {
|
||||
/// Return a pointer to the [`HrTimer`] within `Self`.
|
||||
///
|
||||
/// This function is useful to get access to the value without creating
|
||||
/// intermediate references.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `this` must be a valid pointer.
|
||||
unsafe fn raw_get_timer(this: *const Self) -> *const HrTimer<T>;
|
||||
|
||||
/// Return a pointer to the struct that is containing the [`HrTimer`] pointed
|
||||
/// to by `ptr`.
|
||||
///
|
||||
/// This function is useful to get access to the value without creating
|
||||
/// intermediate references.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `ptr` must point to a [`HrTimer<T>`] field in a struct of type `Self`.
|
||||
unsafe fn timer_container_of(ptr: *mut HrTimer<T>) -> *mut Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Get pointer to the contained `bindings::hrtimer` struct.
|
||||
///
|
||||
/// This function is useful to get access to the value without creating
|
||||
/// intermediate references.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `this` must be a valid pointer.
|
||||
unsafe fn c_timer_ptr(this: *const Self) -> *const bindings::hrtimer {
|
||||
// SAFETY: `this` is a valid pointer to a `Self`.
|
||||
let timer_ptr = unsafe { Self::raw_get_timer(this) };
|
||||
|
||||
// SAFETY: timer_ptr points to an allocation of at least `HrTimer` size.
|
||||
unsafe { HrTimer::raw_get(timer_ptr) }
|
||||
}
|
||||
|
||||
/// Start the timer contained in the `Self` pointed to by `self_ptr`. If
|
||||
/// it is already running it is removed and inserted.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `this` must point to a valid `Self`.
|
||||
/// - Caller must ensure that the pointee of `this` lives until the timer
|
||||
/// fires or is canceled.
|
||||
unsafe fn start(this: *const Self, expires: Ktime) {
|
||||
// SAFETY: By function safety requirement, `this` is a valid `Self`.
|
||||
unsafe {
|
||||
bindings::hrtimer_start_range_ns(
|
||||
Self::c_timer_ptr(this).cast_mut(),
|
||||
expires.to_ns(),
|
||||
0,
|
||||
(*Self::raw_get_timer(this)).mode.into_c(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Restart policy for timers.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum HrTimerRestart {
|
||||
/// Timer should not be restarted.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
NoRestart = bindings::hrtimer_restart_HRTIMER_NORESTART as u32,
|
||||
/// Timer should be restarted.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
Restart = bindings::hrtimer_restart_HRTIMER_RESTART as u32,
|
||||
}
|
||||
|
||||
impl HrTimerRestart {
|
||||
fn into_c(self) -> bindings::hrtimer_restart {
|
||||
self as bindings::hrtimer_restart
|
||||
}
|
||||
}
|
||||
|
||||
/// Operational mode of [`HrTimer`].
|
||||
// NOTE: Some of these have the same encoding on the C side, so we keep
|
||||
// `repr(Rust)` and convert elsewhere.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum HrTimerMode {
|
||||
/// Timer expires at the given expiration time.
|
||||
Absolute,
|
||||
/// Timer expires after the given expiration time interpreted as a duration from now.
|
||||
Relative,
|
||||
/// Timer does not move between CPU cores.
|
||||
Pinned,
|
||||
/// Timer handler is executed in soft irq context.
|
||||
Soft,
|
||||
/// Timer handler is executed in hard irq context.
|
||||
Hard,
|
||||
/// Timer expires at the given expiration time.
|
||||
/// Timer does not move between CPU cores.
|
||||
AbsolutePinned,
|
||||
/// Timer expires after the given expiration time interpreted as a duration from now.
|
||||
/// Timer does not move between CPU cores.
|
||||
RelativePinned,
|
||||
/// Timer expires at the given expiration time.
|
||||
/// Timer handler is executed in soft irq context.
|
||||
AbsoluteSoft,
|
||||
/// Timer expires after the given expiration time interpreted as a duration from now.
|
||||
/// Timer handler is executed in soft irq context.
|
||||
RelativeSoft,
|
||||
/// Timer expires at the given expiration time.
|
||||
/// Timer does not move between CPU cores.
|
||||
/// Timer handler is executed in soft irq context.
|
||||
AbsolutePinnedSoft,
|
||||
/// Timer expires after the given expiration time interpreted as a duration from now.
|
||||
/// Timer does not move between CPU cores.
|
||||
/// Timer handler is executed in soft irq context.
|
||||
RelativePinnedSoft,
|
||||
/// Timer expires at the given expiration time.
|
||||
/// Timer handler is executed in hard irq context.
|
||||
AbsoluteHard,
|
||||
/// Timer expires after the given expiration time interpreted as a duration from now.
|
||||
/// Timer handler is executed in hard irq context.
|
||||
RelativeHard,
|
||||
/// Timer expires at the given expiration time.
|
||||
/// Timer does not move between CPU cores.
|
||||
/// Timer handler is executed in hard irq context.
|
||||
AbsolutePinnedHard,
|
||||
/// Timer expires after the given expiration time interpreted as a duration from now.
|
||||
/// Timer does not move between CPU cores.
|
||||
/// Timer handler is executed in hard irq context.
|
||||
RelativePinnedHard,
|
||||
}
|
||||
|
||||
impl HrTimerMode {
|
||||
fn into_c(self) -> bindings::hrtimer_mode {
|
||||
use bindings::*;
|
||||
match self {
|
||||
HrTimerMode::Absolute => hrtimer_mode_HRTIMER_MODE_ABS,
|
||||
HrTimerMode::Relative => hrtimer_mode_HRTIMER_MODE_REL,
|
||||
HrTimerMode::Pinned => hrtimer_mode_HRTIMER_MODE_PINNED,
|
||||
HrTimerMode::Soft => hrtimer_mode_HRTIMER_MODE_SOFT,
|
||||
HrTimerMode::Hard => hrtimer_mode_HRTIMER_MODE_HARD,
|
||||
HrTimerMode::AbsolutePinned => hrtimer_mode_HRTIMER_MODE_ABS_PINNED,
|
||||
HrTimerMode::RelativePinned => hrtimer_mode_HRTIMER_MODE_REL_PINNED,
|
||||
HrTimerMode::AbsoluteSoft => hrtimer_mode_HRTIMER_MODE_ABS_SOFT,
|
||||
HrTimerMode::RelativeSoft => hrtimer_mode_HRTIMER_MODE_REL_SOFT,
|
||||
HrTimerMode::AbsolutePinnedSoft => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT,
|
||||
HrTimerMode::RelativePinnedSoft => hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT,
|
||||
HrTimerMode::AbsoluteHard => hrtimer_mode_HRTIMER_MODE_ABS_HARD,
|
||||
HrTimerMode::RelativeHard => hrtimer_mode_HRTIMER_MODE_REL_HARD,
|
||||
HrTimerMode::AbsolutePinnedHard => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD,
|
||||
HrTimerMode::RelativePinnedHard => hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Use to implement the [`HasHrTimer<T>`] trait.
|
||||
///
|
||||
/// See [`module`] documentation for an example.
|
||||
///
|
||||
/// [`module`]: crate::time::hrtimer
|
||||
#[macro_export]
|
||||
macro_rules! impl_has_hr_timer {
|
||||
(
|
||||
impl$({$($generics:tt)*})?
|
||||
HasHrTimer<$timer_type:ty>
|
||||
for $self:ty
|
||||
{ self.$field:ident }
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
// SAFETY: This implementation of `raw_get_timer` only compiles if the
|
||||
// field has the right type.
|
||||
unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self {
|
||||
|
||||
#[inline]
|
||||
unsafe fn raw_get_timer(
|
||||
this: *const Self,
|
||||
) -> *const $crate::time::hrtimer::HrTimer<$timer_type> {
|
||||
// SAFETY: The caller promises that the pointer is not dangling.
|
||||
unsafe { ::core::ptr::addr_of!((*this).$field) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn timer_container_of(
|
||||
ptr: *mut $crate::time::hrtimer::HrTimer<$timer_type>,
|
||||
) -> *mut Self {
|
||||
// SAFETY: As per the safety requirement of this function, `ptr`
|
||||
// is pointing inside a `$timer_type`.
|
||||
unsafe { ::kernel::container_of!(ptr, $timer_type, $field).cast_mut() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod arc;
|
||||
pub use arc::ArcHrTimerHandle;
|
||||
mod pin;
|
||||
pub use pin::PinHrTimerHandle;
|
||||
mod pin_mut;
|
||||
pub use pin_mut::PinMutHrTimerHandle;
|
||||
// `box` is a reserved keyword, so prefix with `t` for timer
|
||||
mod tbox;
|
||||
pub use tbox::BoxHrTimerHandle;
|
100
rust/kernel/time/hrtimer/arc.rs
Normal file
100
rust/kernel/time/hrtimer/arc.rs
Normal file
@ -0,0 +1,100 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use super::HasHrTimer;
|
||||
use super::HrTimer;
|
||||
use super::HrTimerCallback;
|
||||
use super::HrTimerHandle;
|
||||
use super::HrTimerPointer;
|
||||
use super::RawHrTimerCallback;
|
||||
use crate::sync::Arc;
|
||||
use crate::sync::ArcBorrow;
|
||||
use crate::time::Ktime;
|
||||
|
||||
/// A handle for an `Arc<HasHrTimer<T>>` returned by a call to
|
||||
/// [`HrTimerPointer::start`].
|
||||
pub struct ArcHrTimerHandle<T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
pub(crate) inner: Arc<T>,
|
||||
}
|
||||
|
||||
// SAFETY: We implement drop below, and we cancel the timer in the drop
|
||||
// implementation.
|
||||
unsafe impl<T> HrTimerHandle for ArcHrTimerHandle<T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
fn cancel(&mut self) -> bool {
|
||||
let self_ptr = Arc::as_ptr(&self.inner);
|
||||
|
||||
// SAFETY: As we obtained `self_ptr` from a valid reference above, it
|
||||
// must point to a valid `T`.
|
||||
let timer_ptr = unsafe { <T as HasHrTimer<T>>::raw_get_timer(self_ptr) };
|
||||
|
||||
// SAFETY: As `timer_ptr` points into `T` and `T` is valid, `timer_ptr`
|
||||
// must point to a valid `HrTimer` instance.
|
||||
unsafe { HrTimer::<T>::raw_cancel(timer_ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for ArcHrTimerHandle<T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> HrTimerPointer for Arc<T>
|
||||
where
|
||||
T: 'static,
|
||||
T: Send + Sync,
|
||||
T: HasHrTimer<T>,
|
||||
T: for<'a> HrTimerCallback<Pointer<'a> = Self>,
|
||||
{
|
||||
type TimerHandle = ArcHrTimerHandle<T>;
|
||||
|
||||
fn start(self, expires: Ktime) -> ArcHrTimerHandle<T> {
|
||||
// SAFETY:
|
||||
// - We keep `self` alive by wrapping it in a handle below.
|
||||
// - Since we generate the pointer passed to `start` from a valid
|
||||
// reference, it is a valid pointer.
|
||||
unsafe { T::start(Arc::as_ptr(&self), expires) };
|
||||
ArcHrTimerHandle { inner: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RawHrTimerCallback for Arc<T>
|
||||
where
|
||||
T: 'static,
|
||||
T: HasHrTimer<T>,
|
||||
T: for<'a> HrTimerCallback<Pointer<'a> = Self>,
|
||||
{
|
||||
type CallbackTarget<'a> = ArcBorrow<'a, T>;
|
||||
|
||||
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
|
||||
// `HrTimer` is `repr(C)`
|
||||
let timer_ptr = ptr.cast::<super::HrTimer<T>>();
|
||||
|
||||
// SAFETY: By C API contract `ptr` is the pointer we passed when
|
||||
// queuing the timer, so it is a `HrTimer<T>` embedded in a `T`.
|
||||
let data_ptr = unsafe { T::timer_container_of(timer_ptr) };
|
||||
|
||||
// SAFETY:
|
||||
// - `data_ptr` is derived form the pointer to the `T` that was used to
|
||||
// queue the timer.
|
||||
// - As per the safety requirements of the trait `HrTimerHandle`, the
|
||||
// `ArcHrTimerHandle` associated with this timer is guaranteed to
|
||||
// be alive until this method returns. That handle borrows the `T`
|
||||
// behind `data_ptr` thus guaranteeing the validity of
|
||||
// the `ArcBorrow` created below.
|
||||
// - We own one refcount in the `ArcTimerHandle` associated with this
|
||||
// timer, so it is not possible to get a `UniqueArc` to this
|
||||
// allocation from other `Arc` clones.
|
||||
let receiver = unsafe { ArcBorrow::from_raw(data_ptr) };
|
||||
|
||||
T::run(receiver).into_c()
|
||||
}
|
||||
}
|
104
rust/kernel/time/hrtimer/pin.rs
Normal file
104
rust/kernel/time/hrtimer/pin.rs
Normal file
@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use super::HasHrTimer;
|
||||
use super::HrTimer;
|
||||
use super::HrTimerCallback;
|
||||
use super::HrTimerHandle;
|
||||
use super::RawHrTimerCallback;
|
||||
use super::UnsafeHrTimerPointer;
|
||||
use crate::time::Ktime;
|
||||
use core::pin::Pin;
|
||||
|
||||
/// A handle for a `Pin<&HasHrTimer>`. When the handle exists, the timer might be
|
||||
/// running.
|
||||
pub struct PinHrTimerHandle<'a, T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
pub(crate) inner: Pin<&'a T>,
|
||||
}
|
||||
|
||||
// SAFETY: We cancel the timer when the handle is dropped. The implementation of
|
||||
// the `cancel` method will block if the timer handler is running.
|
||||
unsafe impl<'a, T> HrTimerHandle for PinHrTimerHandle<'a, T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
fn cancel(&mut self) -> bool {
|
||||
let self_ptr: *const T = self.inner.get_ref();
|
||||
|
||||
// SAFETY: As we got `self_ptr` from a reference above, it must point to
|
||||
// a valid `T`.
|
||||
let timer_ptr = unsafe { <T as HasHrTimer<T>>::raw_get_timer(self_ptr) };
|
||||
|
||||
// SAFETY: As `timer_ptr` is derived from a reference, it must point to
|
||||
// a valid and initialized `HrTimer`.
|
||||
unsafe { HrTimer::<T>::raw_cancel(timer_ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for PinHrTimerHandle<'a, T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: We capture the lifetime of `Self` when we create a `PinHrTimerHandle`,
|
||||
// so `Self` will outlive the handle.
|
||||
unsafe impl<'a, T> UnsafeHrTimerPointer for Pin<&'a T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
T: HasHrTimer<T>,
|
||||
T: HrTimerCallback<Pointer<'a> = Self>,
|
||||
{
|
||||
type TimerHandle = PinHrTimerHandle<'a, T>;
|
||||
|
||||
unsafe fn start(self, expires: Ktime) -> Self::TimerHandle {
|
||||
// Cast to pointer
|
||||
let self_ptr: *const T = self.get_ref();
|
||||
|
||||
// SAFETY:
|
||||
// - As we derive `self_ptr` from a reference above, it must point to a
|
||||
// valid `T`.
|
||||
// - We keep `self` alive by wrapping it in a handle below.
|
||||
unsafe { T::start(self_ptr, expires) };
|
||||
|
||||
PinHrTimerHandle { inner: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RawHrTimerCallback for Pin<&'a T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
T: HrTimerCallback<Pointer<'a> = Self>,
|
||||
{
|
||||
type CallbackTarget<'b> = Self;
|
||||
|
||||
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
|
||||
// `HrTimer` is `repr(C)`
|
||||
let timer_ptr = ptr as *mut HrTimer<T>;
|
||||
|
||||
// SAFETY: By the safety requirement of this function, `timer_ptr`
|
||||
// points to a `HrTimer<T>` contained in an `T`.
|
||||
let receiver_ptr = unsafe { T::timer_container_of(timer_ptr) };
|
||||
|
||||
// SAFETY:
|
||||
// - By the safety requirement of this function, `timer_ptr`
|
||||
// points to a `HrTimer<T>` contained in an `T`.
|
||||
// - As per the safety requirements of the trait `HrTimerHandle`, the
|
||||
// `PinHrTimerHandle` associated with this timer is guaranteed to
|
||||
// be alive until this method returns. That handle borrows the `T`
|
||||
// behind `receiver_ptr`, thus guaranteeing the validity of
|
||||
// the reference created below.
|
||||
let receiver_ref = unsafe { &*receiver_ptr };
|
||||
|
||||
// SAFETY: `receiver_ref` only exists as pinned, so it is safe to pin it
|
||||
// here.
|
||||
let receiver_pin = unsafe { Pin::new_unchecked(receiver_ref) };
|
||||
|
||||
T::run(receiver_pin).into_c()
|
||||
}
|
||||
}
|
108
rust/kernel/time/hrtimer/pin_mut.rs
Normal file
108
rust/kernel/time/hrtimer/pin_mut.rs
Normal file
@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use super::{
|
||||
HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, RawHrTimerCallback, UnsafeHrTimerPointer,
|
||||
};
|
||||
use crate::time::Ktime;
|
||||
use core::{marker::PhantomData, pin::Pin, ptr::NonNull};
|
||||
|
||||
/// A handle for a `Pin<&mut HasHrTimer>`. When the handle exists, the timer might
|
||||
/// be running.
|
||||
pub struct PinMutHrTimerHandle<'a, T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
pub(crate) inner: NonNull<T>,
|
||||
_p: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
// SAFETY: We cancel the timer when the handle is dropped. The implementation of
|
||||
// the `cancel` method will block if the timer handler is running.
|
||||
unsafe impl<'a, T> HrTimerHandle for PinMutHrTimerHandle<'a, T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
fn cancel(&mut self) -> bool {
|
||||
let self_ptr = self.inner.as_ptr();
|
||||
|
||||
// SAFETY: As we got `self_ptr` from a reference above, it must point to
|
||||
// a valid `T`.
|
||||
let timer_ptr = unsafe { <T as HasHrTimer<T>>::raw_get_timer(self_ptr) };
|
||||
|
||||
// SAFETY: As `timer_ptr` is derived from a reference, it must point to
|
||||
// a valid and initialized `HrTimer`.
|
||||
unsafe { HrTimer::<T>::raw_cancel(timer_ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for PinMutHrTimerHandle<'a, T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: We capture the lifetime of `Self` when we create a
|
||||
// `PinMutHrTimerHandle`, so `Self` will outlive the handle.
|
||||
unsafe impl<'a, T> UnsafeHrTimerPointer for Pin<&'a mut T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
T: HasHrTimer<T>,
|
||||
T: HrTimerCallback<Pointer<'a> = Self>,
|
||||
{
|
||||
type TimerHandle = PinMutHrTimerHandle<'a, T>;
|
||||
|
||||
unsafe fn start(mut self, expires: Ktime) -> Self::TimerHandle {
|
||||
// SAFETY:
|
||||
// - We promise not to move out of `self`. We only pass `self`
|
||||
// back to the caller as a `Pin<&mut self>`.
|
||||
// - The return value of `get_unchecked_mut` is guaranteed not to be null.
|
||||
let self_ptr = unsafe { NonNull::new_unchecked(self.as_mut().get_unchecked_mut()) };
|
||||
|
||||
// SAFETY:
|
||||
// - As we derive `self_ptr` from a reference above, it must point to a
|
||||
// valid `T`.
|
||||
// - We keep `self` alive by wrapping it in a handle below.
|
||||
unsafe { T::start(self_ptr.as_ptr(), expires) };
|
||||
|
||||
PinMutHrTimerHandle {
|
||||
inner: self_ptr,
|
||||
_p: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RawHrTimerCallback for Pin<&'a mut T>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
T: HrTimerCallback<Pointer<'a> = Self>,
|
||||
{
|
||||
type CallbackTarget<'b> = Self;
|
||||
|
||||
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
|
||||
// `HrTimer` is `repr(C)`
|
||||
let timer_ptr = ptr as *mut HrTimer<T>;
|
||||
|
||||
// SAFETY: By the safety requirement of this function, `timer_ptr`
|
||||
// points to a `HrTimer<T>` contained in an `T`.
|
||||
let receiver_ptr = unsafe { T::timer_container_of(timer_ptr) };
|
||||
|
||||
// SAFETY:
|
||||
// - By the safety requirement of this function, `timer_ptr`
|
||||
// points to a `HrTimer<T>` contained in an `T`.
|
||||
// - As per the safety requirements of the trait `HrTimerHandle`, the
|
||||
// `PinMutHrTimerHandle` associated with this timer is guaranteed to
|
||||
// be alive until this method returns. That handle borrows the `T`
|
||||
// behind `receiver_ptr` mutably thus guaranteeing the validity of
|
||||
// the reference created below.
|
||||
let receiver_ref = unsafe { &mut *receiver_ptr };
|
||||
|
||||
// SAFETY: `receiver_ref` only exists as pinned, so it is safe to pin it
|
||||
// here.
|
||||
let receiver_pin = unsafe { Pin::new_unchecked(receiver_ref) };
|
||||
|
||||
T::run(receiver_pin).into_c()
|
||||
}
|
||||
}
|
120
rust/kernel/time/hrtimer/tbox.rs
Normal file
120
rust/kernel/time/hrtimer/tbox.rs
Normal file
@ -0,0 +1,120 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use super::HasHrTimer;
|
||||
use super::HrTimer;
|
||||
use super::HrTimerCallback;
|
||||
use super::HrTimerHandle;
|
||||
use super::HrTimerPointer;
|
||||
use super::RawHrTimerCallback;
|
||||
use crate::prelude::*;
|
||||
use crate::time::Ktime;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// A handle for a [`Box<HasHrTimer<T>>`] returned by a call to
|
||||
/// [`HrTimerPointer::start`].
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// - `self.inner` comes from a `Box::into_raw` call.
|
||||
pub struct BoxHrTimerHandle<T, A>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
A: crate::alloc::Allocator,
|
||||
{
|
||||
pub(crate) inner: NonNull<T>,
|
||||
_p: core::marker::PhantomData<A>,
|
||||
}
|
||||
|
||||
// SAFETY: We implement drop below, and we cancel the timer in the drop
|
||||
// implementation.
|
||||
unsafe impl<T, A> HrTimerHandle for BoxHrTimerHandle<T, A>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
A: crate::alloc::Allocator,
|
||||
{
|
||||
fn cancel(&mut self) -> bool {
|
||||
// SAFETY: As we obtained `self.inner` from a valid reference when we
|
||||
// created `self`, it must point to a valid `T`.
|
||||
let timer_ptr = unsafe { <T as HasHrTimer<T>>::raw_get_timer(self.inner.as_ptr()) };
|
||||
|
||||
// SAFETY: As `timer_ptr` points into `T` and `T` is valid, `timer_ptr`
|
||||
// must point to a valid `HrTimer` instance.
|
||||
unsafe { HrTimer::<T>::raw_cancel(timer_ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A> Drop for BoxHrTimerHandle<T, A>
|
||||
where
|
||||
T: HasHrTimer<T>,
|
||||
A: crate::alloc::Allocator,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.cancel();
|
||||
// SAFETY: By type invariant, `self.inner` came from a `Box::into_raw`
|
||||
// call.
|
||||
drop(unsafe { Box::<T, A>::from_raw(self.inner.as_ptr()) })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A> HrTimerPointer for Pin<Box<T, A>>
|
||||
where
|
||||
T: 'static,
|
||||
T: Send + Sync,
|
||||
T: HasHrTimer<T>,
|
||||
T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
|
||||
A: crate::alloc::Allocator,
|
||||
{
|
||||
type TimerHandle = BoxHrTimerHandle<T, A>;
|
||||
|
||||
fn start(self, expires: Ktime) -> Self::TimerHandle {
|
||||
// SAFETY:
|
||||
// - We will not move out of this box during timer callback (we pass an
|
||||
// immutable reference to the callback).
|
||||
// - `Box::into_raw` is guaranteed to return a valid pointer.
|
||||
let inner =
|
||||
unsafe { NonNull::new_unchecked(Box::into_raw(Pin::into_inner_unchecked(self))) };
|
||||
|
||||
// SAFETY:
|
||||
// - We keep `self` alive by wrapping it in a handle below.
|
||||
// - Since we generate the pointer passed to `start` from a valid
|
||||
// reference, it is a valid pointer.
|
||||
unsafe { T::start(inner.as_ptr(), expires) };
|
||||
|
||||
// INVARIANT: `inner` came from `Box::into_raw` above.
|
||||
BoxHrTimerHandle {
|
||||
inner,
|
||||
_p: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A> RawHrTimerCallback for Pin<Box<T, A>>
|
||||
where
|
||||
T: 'static,
|
||||
T: HasHrTimer<T>,
|
||||
T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
|
||||
A: crate::alloc::Allocator,
|
||||
{
|
||||
type CallbackTarget<'a> = Pin<&'a mut T>;
|
||||
|
||||
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
|
||||
// `HrTimer` is `repr(C)`
|
||||
let timer_ptr = ptr.cast::<super::HrTimer<T>>();
|
||||
|
||||
// SAFETY: By C API contract `ptr` is the pointer we passed when
|
||||
// queuing the timer, so it is a `HrTimer<T>` embedded in a `T`.
|
||||
let data_ptr = unsafe { T::timer_container_of(timer_ptr) };
|
||||
|
||||
// SAFETY:
|
||||
// - As per the safety requirements of the trait `HrTimerHandle`, the
|
||||
// `BoxHrTimerHandle` associated with this timer is guaranteed to
|
||||
// be alive until this method returns. That handle owns the `T`
|
||||
// behind `data_ptr` thus guaranteeing the validity of
|
||||
// the reference created below.
|
||||
// - As `data_ptr` comes from a `Pin<Box<T>>`, only pinned references to
|
||||
// `data_ptr` exist.
|
||||
let data_mut_ref = unsafe { Pin::new_unchecked(&mut *data_ptr) };
|
||||
|
||||
T::run(data_mut_ref).into_c()
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
|
||||
//! Kernel types.
|
||||
|
||||
use crate::init::{self, PinInit};
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
marker::{PhantomData, PhantomPinned},
|
||||
@ -10,6 +9,7 @@ use core::{
|
||||
ops::{Deref, DerefMut},
|
||||
ptr::NonNull,
|
||||
};
|
||||
use pin_init::{PinInit, Zeroable};
|
||||
|
||||
/// Used to transfer ownership to and from foreign (non-Rust) languages.
|
||||
///
|
||||
@ -77,7 +77,7 @@ pub trait ForeignOwnable: Sized {
|
||||
///
|
||||
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and if
|
||||
/// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of
|
||||
/// the lifetime 'a.
|
||||
/// the lifetime `'a`.
|
||||
///
|
||||
/// [`into_foreign`]: Self::into_foreign
|
||||
/// [`from_foreign`]: Self::from_foreign
|
||||
@ -100,9 +100,9 @@ pub trait ForeignOwnable: Sized {
|
||||
///
|
||||
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and if
|
||||
/// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of
|
||||
/// the lifetime 'a.
|
||||
/// the lifetime `'a`.
|
||||
///
|
||||
/// The lifetime 'a must not overlap with the lifetime of any other call to [`borrow`] or
|
||||
/// The lifetime `'a` must not overlap with the lifetime of any other call to [`borrow`] or
|
||||
/// `borrow_mut` on the same object.
|
||||
///
|
||||
/// [`into_foreign`]: Self::into_foreign
|
||||
@ -251,7 +251,7 @@ impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
|
||||
|
||||
/// Stores an opaque value.
|
||||
///
|
||||
/// `Opaque<T>` is meant to be used with FFI objects that are never interpreted by Rust code.
|
||||
/// [`Opaque<T>`] is meant to be used with FFI objects that are never interpreted by Rust code.
|
||||
///
|
||||
/// It is used to wrap structs from the C side, like for example `Opaque<bindings::mutex>`.
|
||||
/// It gets rid of all the usual assumptions that Rust has for a value:
|
||||
@ -266,7 +266,7 @@ impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
|
||||
/// This has to be used for all values that the C side has access to, because it can't be ensured
|
||||
/// that the C side is adhering to the usual constraints that Rust needs.
|
||||
///
|
||||
/// Using `Opaque<T>` allows to continue to use references on the Rust side even for values shared
|
||||
/// Using [`Opaque<T>`] allows to continue to use references on the Rust side even for values shared
|
||||
/// with C.
|
||||
///
|
||||
/// # Examples
|
||||
@ -309,6 +309,9 @@ pub struct Opaque<T> {
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
// SAFETY: `Opaque<T>` allows the inner value to be any bit pattern, including all zeros.
|
||||
unsafe impl<T> Zeroable for Opaque<T> {}
|
||||
|
||||
impl<T> Opaque<T> {
|
||||
/// Creates a new opaque value.
|
||||
pub const fn new(value: T) -> Self {
|
||||
@ -333,7 +336,7 @@ impl<T> Opaque<T> {
|
||||
// - `ptr` is a valid pointer to uninitialized memory,
|
||||
// - `slot` is not accessed on error; the call is infallible,
|
||||
// - `slot` is pinned in memory.
|
||||
let _ = unsafe { init::PinInit::<T>::__pinned_init(slot, ptr) };
|
||||
let _ = unsafe { PinInit::<T>::__pinned_init(slot, ptr) };
|
||||
})
|
||||
}
|
||||
|
||||
@ -349,7 +352,7 @@ impl<T> Opaque<T> {
|
||||
// SAFETY: We contain a `MaybeUninit`, so it is OK for the `init_func` to not fully
|
||||
// initialize the `T`.
|
||||
unsafe {
|
||||
init::pin_init_from_closure::<_, ::core::convert::Infallible>(move |slot| {
|
||||
pin_init::pin_init_from_closure::<_, ::core::convert::Infallible>(move |slot| {
|
||||
init_func(Self::raw_get(slot));
|
||||
Ok(())
|
||||
})
|
||||
@ -369,7 +372,9 @@ impl<T> Opaque<T> {
|
||||
) -> impl PinInit<Self, E> {
|
||||
// SAFETY: We contain a `MaybeUninit`, so it is OK for the `init_func` to not fully
|
||||
// initialize the `T`.
|
||||
unsafe { init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::raw_get(slot))) }
|
||||
unsafe {
|
||||
pin_init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::raw_get(slot)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the opaque data.
|
||||
|
@ -285,8 +285,7 @@ impl UserSliceReader {
|
||||
let len = self.length;
|
||||
buf.reserve(len, flags)?;
|
||||
|
||||
// The call to `try_reserve` was successful, so the spare capacity is at least `len` bytes
|
||||
// long.
|
||||
// The call to `reserve` was successful, so the spare capacity is at least `len` bytes long.
|
||||
self.read_raw(&mut buf.spare_capacity_mut()[..len])?;
|
||||
|
||||
// SAFETY: Since the call to `read_raw` was successful, so the next `len` bytes of the
|
||||
|
29
rust/macros/export.rs
Normal file
29
rust/macros/export.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use crate::helpers::function_name;
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
/// Please see [`crate::export`] for documentation.
|
||||
pub(crate) fn export(_attr: TokenStream, ts: TokenStream) -> TokenStream {
|
||||
let Some(name) = function_name(ts.clone()) else {
|
||||
return "::core::compile_error!(\"The #[export] attribute must be used on a function.\");"
|
||||
.parse::<TokenStream>()
|
||||
.unwrap();
|
||||
};
|
||||
|
||||
// This verifies that the function has the same signature as the declaration generated by
|
||||
// bindgen. It makes use of the fact that all branches of an if/else must have the same type.
|
||||
let signature_check = quote!(
|
||||
const _: () = {
|
||||
if true {
|
||||
::kernel::bindings::#name
|
||||
} else {
|
||||
#name
|
||||
};
|
||||
};
|
||||
);
|
||||
|
||||
let no_mangle = quote!(#[no_mangle]);
|
||||
|
||||
TokenStream::from_iter([signature_check, no_mangle, ts])
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use proc_macro::{token_stream, Group, TokenStream, TokenTree};
|
||||
use proc_macro::{token_stream, Group, Ident, TokenStream, TokenTree};
|
||||
|
||||
pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
|
||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||
@ -70,148 +70,19 @@ pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parsed generics.
|
||||
///
|
||||
/// See the field documentation for an explanation what each of the fields represents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// # let input = todo!();
|
||||
/// let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input);
|
||||
/// quote! {
|
||||
/// struct Foo<$($decl_generics)*> {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// impl<$impl_generics> Foo<$ty_generics> {
|
||||
/// fn foo() {
|
||||
/// // ...
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub(crate) struct Generics {
|
||||
/// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`).
|
||||
///
|
||||
/// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`).
|
||||
pub(crate) decl_generics: Vec<TokenTree>,
|
||||
/// The generics with bounds (e.g. `T: Clone, const N: usize`).
|
||||
///
|
||||
/// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`.
|
||||
pub(crate) impl_generics: Vec<TokenTree>,
|
||||
/// The generics without bounds and without default values (e.g. `T, N`).
|
||||
///
|
||||
/// Use this when you use the type that is declared with these generics e.g.
|
||||
/// `Foo<$ty_generics>`.
|
||||
pub(crate) ty_generics: Vec<TokenTree>,
|
||||
}
|
||||
|
||||
/// Parses the given `TokenStream` into `Generics` and the rest.
|
||||
///
|
||||
/// The generics are not present in the rest, but a where clause might remain.
|
||||
pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) {
|
||||
// The generics with bounds and default values.
|
||||
let mut decl_generics = vec![];
|
||||
// `impl_generics`, the declared generics with their bounds.
|
||||
let mut impl_generics = vec![];
|
||||
// Only the names of the generics, without any bounds.
|
||||
let mut ty_generics = vec![];
|
||||
// Tokens not related to the generics e.g. the `where` token and definition.
|
||||
let mut rest = vec![];
|
||||
// The current level of `<`.
|
||||
let mut nesting = 0;
|
||||
let mut toks = input.into_iter();
|
||||
// If we are at the beginning of a generic parameter.
|
||||
let mut at_start = true;
|
||||
let mut skip_until_comma = false;
|
||||
while let Some(tt) = toks.next() {
|
||||
if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') {
|
||||
// Found the end of the generics.
|
||||
break;
|
||||
} else if nesting >= 1 {
|
||||
decl_generics.push(tt.clone());
|
||||
}
|
||||
match tt.clone() {
|
||||
TokenTree::Punct(p) if p.as_char() == '<' => {
|
||||
if nesting >= 1 && !skip_until_comma {
|
||||
// This is inside of the generics and part of some bound.
|
||||
impl_generics.push(tt);
|
||||
/// Given a function declaration, finds the name of the function.
|
||||
pub(crate) fn function_name(input: TokenStream) -> Option<Ident> {
|
||||
let mut input = input.into_iter();
|
||||
while let Some(token) = input.next() {
|
||||
match token {
|
||||
TokenTree::Ident(i) if i.to_string() == "fn" => {
|
||||
if let Some(TokenTree::Ident(i)) = input.next() {
|
||||
return Some(i);
|
||||
}
|
||||
nesting += 1;
|
||||
return None;
|
||||
}
|
||||
TokenTree::Punct(p) if p.as_char() == '>' => {
|
||||
// This is a parsing error, so we just end it here.
|
||||
if nesting == 0 {
|
||||
break;
|
||||
} else {
|
||||
nesting -= 1;
|
||||
if nesting >= 1 && !skip_until_comma {
|
||||
// We are still inside of the generics and part of some bound.
|
||||
impl_generics.push(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => {
|
||||
if nesting == 1 {
|
||||
impl_generics.push(tt.clone());
|
||||
impl_generics.push(tt);
|
||||
skip_until_comma = false;
|
||||
}
|
||||
}
|
||||
_ if !skip_until_comma => {
|
||||
match nesting {
|
||||
// If we haven't entered the generics yet, we still want to keep these tokens.
|
||||
0 => rest.push(tt),
|
||||
1 => {
|
||||
// Here depending on the token, it might be a generic variable name.
|
||||
match tt.clone() {
|
||||
TokenTree::Ident(i) if at_start && i.to_string() == "const" => {
|
||||
let Some(name) = toks.next() else {
|
||||
// Parsing error.
|
||||
break;
|
||||
};
|
||||
impl_generics.push(tt);
|
||||
impl_generics.push(name.clone());
|
||||
ty_generics.push(name.clone());
|
||||
decl_generics.push(name);
|
||||
at_start = false;
|
||||
}
|
||||
TokenTree::Ident(_) if at_start => {
|
||||
impl_generics.push(tt.clone());
|
||||
ty_generics.push(tt);
|
||||
at_start = false;
|
||||
}
|
||||
TokenTree::Punct(p) if p.as_char() == ',' => {
|
||||
impl_generics.push(tt.clone());
|
||||
ty_generics.push(tt);
|
||||
at_start = true;
|
||||
}
|
||||
// Lifetimes begin with `'`.
|
||||
TokenTree::Punct(p) if p.as_char() == '\'' && at_start => {
|
||||
impl_generics.push(tt.clone());
|
||||
ty_generics.push(tt);
|
||||
}
|
||||
// Generics can have default values, we skip these.
|
||||
TokenTree::Punct(p) if p.as_char() == '=' => {
|
||||
skip_until_comma = true;
|
||||
}
|
||||
_ => impl_generics.push(tt),
|
||||
}
|
||||
}
|
||||
_ => impl_generics.push(tt),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
rest.extend(toks);
|
||||
(
|
||||
Generics {
|
||||
impl_generics,
|
||||
decl_generics,
|
||||
ty_generics,
|
||||
},
|
||||
rest,
|
||||
)
|
||||
None
|
||||
}
|
||||
|
161
rust/macros/kunit.rs
Normal file
161
rust/macros/kunit.rs
Normal file
@ -0,0 +1,161 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! Procedural macro to run KUnit tests using a user-space like syntax.
|
||||
//!
|
||||
//! Copyright (c) 2023 José Expósito <jose.exposito89@gmail.com>
|
||||
|
||||
use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
|
||||
use std::fmt::Write;
|
||||
|
||||
pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
|
||||
let attr = attr.to_string();
|
||||
|
||||
if attr.is_empty() {
|
||||
panic!("Missing test name in `#[kunit_tests(test_name)]` macro")
|
||||
}
|
||||
|
||||
if attr.len() > 255 {
|
||||
panic!(
|
||||
"The test suite name `{}` exceeds the maximum length of 255 bytes",
|
||||
attr
|
||||
)
|
||||
}
|
||||
|
||||
let mut tokens: Vec<_> = ts.into_iter().collect();
|
||||
|
||||
// Scan for the `mod` keyword.
|
||||
tokens
|
||||
.iter()
|
||||
.find_map(|token| match token {
|
||||
TokenTree::Ident(ident) => match ident.to_string().as_str() {
|
||||
"mod" => Some(true),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
.expect("`#[kunit_tests(test_name)]` attribute should only be applied to modules");
|
||||
|
||||
// Retrieve the main body. The main body should be the last token tree.
|
||||
let body = match tokens.pop() {
|
||||
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => group,
|
||||
_ => panic!("Cannot locate main body of module"),
|
||||
};
|
||||
|
||||
// Get the functions set as tests. Search for `[test]` -> `fn`.
|
||||
let mut body_it = body.stream().into_iter();
|
||||
let mut tests = Vec::new();
|
||||
while let Some(token) = body_it.next() {
|
||||
match token {
|
||||
TokenTree::Group(ident) if ident.to_string() == "[test]" => match body_it.next() {
|
||||
Some(TokenTree::Ident(ident)) if ident.to_string() == "fn" => {
|
||||
let test_name = match body_it.next() {
|
||||
Some(TokenTree::Ident(ident)) => ident.to_string(),
|
||||
_ => continue,
|
||||
};
|
||||
tests.push(test_name);
|
||||
}
|
||||
_ => continue,
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Add `#[cfg(CONFIG_KUNIT)]` before the module declaration.
|
||||
let config_kunit = "#[cfg(CONFIG_KUNIT)]".to_owned().parse().unwrap();
|
||||
tokens.insert(
|
||||
0,
|
||||
TokenTree::Group(Group::new(Delimiter::None, config_kunit)),
|
||||
);
|
||||
|
||||
// Generate the test KUnit test suite and a test case for each `#[test]`.
|
||||
// The code generated for the following test module:
|
||||
//
|
||||
// ```
|
||||
// #[kunit_tests(kunit_test_suit_name)]
|
||||
// mod tests {
|
||||
// #[test]
|
||||
// fn foo() {
|
||||
// assert_eq!(1, 1);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn bar() {
|
||||
// assert_eq!(2, 2);
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Looks like:
|
||||
//
|
||||
// ```
|
||||
// unsafe extern "C" fn kunit_rust_wrapper_foo(_test: *mut kernel::bindings::kunit) { foo(); }
|
||||
// unsafe extern "C" fn kunit_rust_wrapper_bar(_test: *mut kernel::bindings::kunit) { bar(); }
|
||||
//
|
||||
// static mut TEST_CASES: [kernel::bindings::kunit_case; 3] = [
|
||||
// kernel::kunit::kunit_case(kernel::c_str!("foo"), kunit_rust_wrapper_foo),
|
||||
// kernel::kunit::kunit_case(kernel::c_str!("bar"), kunit_rust_wrapper_bar),
|
||||
// kernel::kunit::kunit_case_null(),
|
||||
// ];
|
||||
//
|
||||
// kernel::kunit_unsafe_test_suite!(kunit_test_suit_name, TEST_CASES);
|
||||
// ```
|
||||
let mut kunit_macros = "".to_owned();
|
||||
let mut test_cases = "".to_owned();
|
||||
for test in &tests {
|
||||
let kunit_wrapper_fn_name = format!("kunit_rust_wrapper_{}", test);
|
||||
let kunit_wrapper = format!(
|
||||
"unsafe extern \"C\" fn {}(_test: *mut kernel::bindings::kunit) {{ {}(); }}",
|
||||
kunit_wrapper_fn_name, test
|
||||
);
|
||||
writeln!(kunit_macros, "{kunit_wrapper}").unwrap();
|
||||
writeln!(
|
||||
test_cases,
|
||||
" kernel::kunit::kunit_case(kernel::c_str!(\"{}\"), {}),",
|
||||
test, kunit_wrapper_fn_name
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
writeln!(kunit_macros).unwrap();
|
||||
writeln!(
|
||||
kunit_macros,
|
||||
"static mut TEST_CASES: [kernel::bindings::kunit_case; {}] = [\n{test_cases} kernel::kunit::kunit_case_null(),\n];",
|
||||
tests.len() + 1
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
writeln!(
|
||||
kunit_macros,
|
||||
"kernel::kunit_unsafe_test_suite!({attr}, TEST_CASES);"
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Remove the `#[test]` macros.
|
||||
// We do this at a token level, in order to preserve span information.
|
||||
let mut new_body = vec![];
|
||||
let mut body_it = body.stream().into_iter();
|
||||
|
||||
while let Some(token) = body_it.next() {
|
||||
match token {
|
||||
TokenTree::Punct(ref c) if c.as_char() == '#' => match body_it.next() {
|
||||
Some(TokenTree::Group(group)) if group.to_string() == "[test]" => (),
|
||||
Some(next) => {
|
||||
new_body.extend([token, next]);
|
||||
}
|
||||
_ => {
|
||||
new_body.push(token);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
new_body.push(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_body = TokenStream::from_iter(new_body);
|
||||
new_body.extend::<TokenStream>(kunit_macros.parse().unwrap());
|
||||
|
||||
tokens.push(TokenTree::Group(Group::new(Delimiter::Brace, new_body)));
|
||||
|
||||
tokens.into_iter().collect()
|
||||
}
|
@ -9,13 +9,12 @@
|
||||
#[macro_use]
|
||||
mod quote;
|
||||
mod concat_idents;
|
||||
mod export;
|
||||
mod helpers;
|
||||
mod kunit;
|
||||
mod module;
|
||||
mod paste;
|
||||
mod pin_data;
|
||||
mod pinned_drop;
|
||||
mod vtable;
|
||||
mod zeroable;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
@ -36,7 +35,7 @@ use proc_macro::TokenStream;
|
||||
/// module!{
|
||||
/// type: MyModule,
|
||||
/// name: "my_kernel_module",
|
||||
/// author: "Rust for Linux Contributors",
|
||||
/// authors: ["Rust for Linux Contributors"],
|
||||
/// description: "My very own kernel module!",
|
||||
/// license: "GPL",
|
||||
/// alias: ["alternate_module_name"],
|
||||
@ -69,7 +68,7 @@ use proc_macro::TokenStream;
|
||||
/// module!{
|
||||
/// type: MyDeviceDriverModule,
|
||||
/// name: "my_device_driver_module",
|
||||
/// author: "Rust for Linux Contributors",
|
||||
/// authors: ["Rust for Linux Contributors"],
|
||||
/// description: "My device driver requires firmware",
|
||||
/// license: "GPL",
|
||||
/// firmware: ["my_device_firmware1.bin", "my_device_firmware2.bin"],
|
||||
@ -88,7 +87,7 @@ use proc_macro::TokenStream;
|
||||
/// # Supported argument types
|
||||
/// - `type`: type which implements the [`Module`] trait (required).
|
||||
/// - `name`: ASCII string literal of the name of the kernel module (required).
|
||||
/// - `author`: string literal of the author of the kernel module.
|
||||
/// - `authors`: array of ASCII string literals of the authors of the kernel module.
|
||||
/// - `description`: string literal of the description of the kernel module.
|
||||
/// - `license`: ASCII string literal of the license of the kernel module (required).
|
||||
/// - `alias`: array of ASCII string literals of the alias names of the kernel module.
|
||||
@ -174,6 +173,29 @@ pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
|
||||
vtable::vtable(attr, ts)
|
||||
}
|
||||
|
||||
/// Export a function so that C code can call it via a header file.
|
||||
///
|
||||
/// Functions exported using this macro can be called from C code using the declaration in the
|
||||
/// appropriate header file. It should only be used in cases where C calls the function through a
|
||||
/// header file; cases where C calls into Rust via a function pointer in a vtable (such as
|
||||
/// `file_operations`) should not use this macro.
|
||||
///
|
||||
/// This macro has the following effect:
|
||||
///
|
||||
/// * Disables name mangling for this function.
|
||||
/// * Verifies at compile-time that the function signature matches the declaration in the header
|
||||
/// file.
|
||||
///
|
||||
/// You must declare the signature of the Rust function in a header file that is included by
|
||||
/// `rust/bindings/bindings_helper.h`.
|
||||
///
|
||||
/// This macro is *not* the same as the C macros `EXPORT_SYMBOL_*`. All Rust symbols are currently
|
||||
/// automatically exported with `EXPORT_SYMBOL_GPL`.
|
||||
#[proc_macro_attribute]
|
||||
pub fn export(attr: TokenStream, ts: TokenStream) -> TokenStream {
|
||||
export::export(attr, ts)
|
||||
}
|
||||
|
||||
/// Concatenate two identifiers.
|
||||
///
|
||||
/// This is useful in macros that need to declare or reference items with names
|
||||
@ -232,106 +254,6 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {
|
||||
concat_idents::concat_idents(ts)
|
||||
}
|
||||
|
||||
/// Used to specify the pinning information of the fields of a struct.
|
||||
///
|
||||
/// This is somewhat similar in purpose as
|
||||
/// [pin-project-lite](https://crates.io/crates/pin-project-lite).
|
||||
/// Place this macro on a struct definition and then `#[pin]` in front of the attributes of each
|
||||
/// field you want to structurally pin.
|
||||
///
|
||||
/// This macro enables the use of the [`pin_init!`] macro. When pin-initializing a `struct`,
|
||||
/// then `#[pin]` directs the type of initializer that is required.
|
||||
///
|
||||
/// If your `struct` implements `Drop`, then you need to add `PinnedDrop` as arguments to this
|
||||
/// macro, and change your `Drop` implementation to `PinnedDrop` annotated with
|
||||
/// `#[`[`macro@pinned_drop`]`]`, since dropping pinned values requires extra care.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(lint_reasons)]
|
||||
/// # use kernel::prelude::*;
|
||||
/// # use std::{sync::Mutex, process::Command};
|
||||
/// # use kernel::macros::pin_data;
|
||||
/// #[pin_data]
|
||||
/// struct DriverData {
|
||||
/// #[pin]
|
||||
/// queue: Mutex<KVec<Command>>,
|
||||
/// buf: KBox<[u8; 1024 * 1024]>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(lint_reasons)]
|
||||
/// # use kernel::prelude::*;
|
||||
/// # use std::{sync::Mutex, process::Command};
|
||||
/// # use core::pin::Pin;
|
||||
/// # pub struct Info;
|
||||
/// # mod bindings {
|
||||
/// # pub unsafe fn destroy_info(_ptr: *mut super::Info) {}
|
||||
/// # }
|
||||
/// use kernel::macros::{pin_data, pinned_drop};
|
||||
///
|
||||
/// #[pin_data(PinnedDrop)]
|
||||
/// struct DriverData {
|
||||
/// #[pin]
|
||||
/// queue: Mutex<KVec<Command>>,
|
||||
/// buf: KBox<[u8; 1024 * 1024]>,
|
||||
/// raw_info: *mut Info,
|
||||
/// }
|
||||
///
|
||||
/// #[pinned_drop]
|
||||
/// impl PinnedDrop for DriverData {
|
||||
/// fn drop(self: Pin<&mut Self>) {
|
||||
/// unsafe { bindings::destroy_info(self.raw_info) };
|
||||
/// }
|
||||
/// }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`pin_init!`]: ../kernel/macro.pin_init.html
|
||||
// ^ cannot use direct link, since `kernel` is not a dependency of `macros`.
|
||||
#[proc_macro_attribute]
|
||||
pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
|
||||
pin_data::pin_data(inner, item)
|
||||
}
|
||||
|
||||
/// Used to implement `PinnedDrop` safely.
|
||||
///
|
||||
/// Only works on structs that are annotated via `#[`[`macro@pin_data`]`]`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(lint_reasons)]
|
||||
/// # use kernel::prelude::*;
|
||||
/// # use macros::{pin_data, pinned_drop};
|
||||
/// # use std::{sync::Mutex, process::Command};
|
||||
/// # use core::pin::Pin;
|
||||
/// # mod bindings {
|
||||
/// # pub struct Info;
|
||||
/// # pub unsafe fn destroy_info(_ptr: *mut Info) {}
|
||||
/// # }
|
||||
/// #[pin_data(PinnedDrop)]
|
||||
/// struct DriverData {
|
||||
/// #[pin]
|
||||
/// queue: Mutex<KVec<Command>>,
|
||||
/// buf: KBox<[u8; 1024 * 1024]>,
|
||||
/// raw_info: *mut bindings::Info,
|
||||
/// }
|
||||
///
|
||||
/// #[pinned_drop]
|
||||
/// impl PinnedDrop for DriverData {
|
||||
/// fn drop(self: Pin<&mut Self>) {
|
||||
/// unsafe { bindings::destroy_info(self.raw_info) };
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
pinned_drop::pinned_drop(args, input)
|
||||
}
|
||||
|
||||
/// Paste identifiers together.
|
||||
///
|
||||
/// Within the `paste!` macro, identifiers inside `[<` and `>]` are concatenated together to form a
|
||||
@ -472,23 +394,29 @@ pub fn paste(input: TokenStream) -> TokenStream {
|
||||
tokens.into_iter().collect()
|
||||
}
|
||||
|
||||
/// Derives the [`Zeroable`] trait for the given struct.
|
||||
/// Registers a KUnit test suite and its test cases using a user-space like syntax.
|
||||
///
|
||||
/// This can only be used for structs where every field implements the [`Zeroable`] trait.
|
||||
/// This macro should be used on modules. If `CONFIG_KUNIT` (in `.config`) is `n`, the target module
|
||||
/// is ignored.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::macros::Zeroable;
|
||||
/// ```ignore
|
||||
/// # use macros::kunit_tests;
|
||||
/// #[kunit_tests(kunit_test_suit_name)]
|
||||
/// mod tests {
|
||||
/// #[test]
|
||||
/// fn foo() {
|
||||
/// assert_eq!(1, 1);
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Zeroable)]
|
||||
/// pub struct DriverData {
|
||||
/// id: i64,
|
||||
/// buf_ptr: *mut u8,
|
||||
/// len: usize,
|
||||
/// #[test]
|
||||
/// fn bar() {
|
||||
/// assert_eq!(2, 2);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_derive(Zeroable)]
|
||||
pub fn derive_zeroable(input: TokenStream) -> TokenStream {
|
||||
zeroable::derive(input)
|
||||
#[proc_macro_attribute]
|
||||
pub fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
|
||||
kunit::kunit_tests(attr, ts)
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ impl<'a> ModInfoBuilder<'a> {
|
||||
"
|
||||
{cfg}
|
||||
#[doc(hidden)]
|
||||
#[link_section = \".modinfo\"]
|
||||
#[cfg_attr(not(target_os = \"macos\"), link_section = \".modinfo\")]
|
||||
#[used]
|
||||
pub static __{module}_{counter}: [u8; {length}] = *{string};
|
||||
",
|
||||
@ -95,6 +95,7 @@ struct ModuleInfo {
|
||||
license: String,
|
||||
name: String,
|
||||
author: Option<String>,
|
||||
authors: Option<Vec<String>>,
|
||||
description: Option<String>,
|
||||
alias: Option<Vec<String>>,
|
||||
firmware: Option<Vec<String>>,
|
||||
@ -108,6 +109,7 @@ impl ModuleInfo {
|
||||
"type",
|
||||
"name",
|
||||
"author",
|
||||
"authors",
|
||||
"description",
|
||||
"license",
|
||||
"alias",
|
||||
@ -136,6 +138,7 @@ impl ModuleInfo {
|
||||
"type" => info.type_ = expect_ident(it),
|
||||
"name" => info.name = expect_string_ascii(it),
|
||||
"author" => info.author = Some(expect_string(it)),
|
||||
"authors" => info.authors = Some(expect_string_array(it)),
|
||||
"description" => info.description = Some(expect_string(it)),
|
||||
"license" => info.license = expect_string_ascii(it),
|
||||
"alias" => info.alias = Some(expect_string_array(it)),
|
||||
@ -186,6 +189,11 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
|
||||
if let Some(author) = info.author {
|
||||
modinfo.emit("author", &author);
|
||||
}
|
||||
if let Some(authors) = info.authors {
|
||||
for author in authors {
|
||||
modinfo.emit("author", &author);
|
||||
}
|
||||
}
|
||||
if let Some(description) = info.description {
|
||||
modinfo.emit("description", &description);
|
||||
}
|
||||
@ -240,7 +248,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
|
||||
mod __module_init {{
|
||||
mod __module_init {{
|
||||
use super::super::{type_};
|
||||
use kernel::init::PinInit;
|
||||
use pin_init::PinInit;
|
||||
|
||||
/// The \"Rust loadable module\" mark.
|
||||
//
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use proc_macro::{TokenStream, TokenTree};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) trait ToTokens {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream);
|
||||
}
|
||||
@ -20,6 +21,12 @@ impl ToTokens for proc_macro::Group {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for proc_macro::Ident {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.extend([TokenTree::from(self.clone())]);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for TokenTree {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.extend([self.clone()]);
|
||||
@ -40,7 +47,7 @@ impl ToTokens for TokenStream {
|
||||
/// `quote` crate but provides only just enough functionality needed by the current `macros` crate.
|
||||
macro_rules! quote_spanned {
|
||||
($span:expr => $($tt:tt)*) => {{
|
||||
let mut tokens;
|
||||
let mut tokens: ::std::vec::Vec<::proc_macro::TokenTree>;
|
||||
#[allow(clippy::vec_init_then_push)]
|
||||
{
|
||||
tokens = ::std::vec::Vec::new();
|
||||
@ -65,7 +72,8 @@ macro_rules! quote_spanned {
|
||||
quote_spanned!(@proc $v $span $($tt)*);
|
||||
};
|
||||
(@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => {
|
||||
let mut tokens = ::std::vec::Vec::new();
|
||||
#[allow(unused_mut)]
|
||||
let mut tokens = ::std::vec::Vec::<::proc_macro::TokenTree>::new();
|
||||
quote_spanned!(@proc tokens $span $($inner)*);
|
||||
$v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
|
||||
::proc_macro::Delimiter::Parenthesis,
|
||||
@ -136,6 +144,22 @@ macro_rules! quote_spanned {
|
||||
));
|
||||
quote_spanned!(@proc $v $span $($tt)*);
|
||||
};
|
||||
(@proc $v:ident $span:ident = $($tt:tt)*) => {
|
||||
$v.push(::proc_macro::TokenTree::Punct(
|
||||
::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone)
|
||||
));
|
||||
quote_spanned!(@proc $v $span $($tt)*);
|
||||
};
|
||||
(@proc $v:ident $span:ident # $($tt:tt)*) => {
|
||||
$v.push(::proc_macro::TokenTree::Punct(
|
||||
::proc_macro::Punct::new('#', ::proc_macro::Spacing::Alone)
|
||||
));
|
||||
quote_spanned!(@proc $v $span $($tt)*);
|
||||
};
|
||||
(@proc $v:ident $span:ident _ $($tt:tt)*) => {
|
||||
$v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new("_", $span)));
|
||||
quote_spanned!(@proc $v $span $($tt)*);
|
||||
};
|
||||
(@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
|
||||
$v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span)));
|
||||
quote_spanned!(@proc $v $span $($tt)*);
|
||||
|
72
rust/pin-init/CONTRIBUTING.md
Normal file
72
rust/pin-init/CONTRIBUTING.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Contributing to `pin-init`
|
||||
|
||||
Thanks for showing interest in contributing to `pin-init`! This document outlines the guidelines for
|
||||
contributing to `pin-init`.
|
||||
|
||||
All contributions are double-licensed under Apache 2.0 and MIT. You can find the respective licenses
|
||||
in the `LICENSE-APACHE` and `LICENSE-MIT` files.
|
||||
|
||||
## Non-Code Contributions
|
||||
|
||||
### Bug Reports
|
||||
|
||||
For any type of bug report, please submit an issue using the bug report issue template.
|
||||
|
||||
If the issue is a soundness issue, please privately report it as a security vulnerability via the
|
||||
GitHub web interface.
|
||||
|
||||
### Feature Requests
|
||||
|
||||
If you have any feature requests, please submit an issue using the feature request issue template.
|
||||
|
||||
### Questions and Getting Help
|
||||
|
||||
You can ask questions in the Discussions page of the GitHub repository. If you're encountering
|
||||
problems or just have questions related to `pin-init` in the Linux kernel, you can also ask your
|
||||
questions in the [Rust-for-Linux Zulip](https://rust-for-linux.zulipchat.com/) or see
|
||||
<https://rust-for-linux.com/contact>.
|
||||
|
||||
## Contributing Code
|
||||
|
||||
### Linux Kernel
|
||||
|
||||
`pin-init` is used by the Linux kernel and all commits are synchronized to it. For this reason, the
|
||||
same requirements for commits apply to `pin-init`. See [the kernel's documentation] for details. The
|
||||
rest of this document will also cover some of the rules listed there and additional ones.
|
||||
|
||||
[the kernel's documentation]: https://docs.kernel.org/process/submitting-patches.html
|
||||
|
||||
Contributions to `pin-init` ideally go through the [GitHub repository], because that repository runs
|
||||
a CI with lots of tests not present in the kernel. However, patches are also accepted (though not
|
||||
preferred). Do note that there are some files that are only present in the GitHub repository such as
|
||||
tests, licenses and cargo related files. Making changes to them can only happen via GitHub.
|
||||
|
||||
[GitHub repository]: https://github.com/Rust-for-Linux/pin-init
|
||||
|
||||
### Commit Style
|
||||
|
||||
Everything must compile without errors or warnings and all tests must pass after **every commit**.
|
||||
This is important for bisection and also required by the kernel.
|
||||
|
||||
Each commit should be a single, logically cohesive change. Of course it's best to keep the changes
|
||||
small and digestible, but logically linked changes should be made in the same commit. For example,
|
||||
when fixing typos, create a single commit that fixes all of them instead of one commit per typo.
|
||||
|
||||
Commits must have a meaningful commit title. Commits with changes to files in the `internal`
|
||||
directory should have a title prefixed with `internal:`. The commit message should explain the
|
||||
change and its rationale. You also have to add your `Signed-off-by` tag, see [Developer's
|
||||
Certificate of Origin]. This has to be done for both mailing list submissions as well as GitHub
|
||||
submissions.
|
||||
|
||||
[Developer's Certificate of Origin]: https://docs.kernel.org/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
|
||||
|
||||
Any changes made to public APIs must be documented not only in the commit message, but also in the
|
||||
`CHANGELOG.md` file. This is especially important for breaking changes, as those warrant a major
|
||||
version bump.
|
||||
|
||||
If you make changes to the top-level crate documentation, you also need to update the `README.md`
|
||||
via `cargo rdme`.
|
||||
|
||||
Some of these rules can be ignored if the change is done solely to files that are not present in the
|
||||
kernel version of this library. Those files are documented in the `sync-kernel.sh` script at the
|
||||
very bottom in the `--exclude` flag given to the `git am` command.
|
228
rust/pin-init/README.md
Normal file
228
rust/pin-init/README.md
Normal file
@ -0,0 +1,228 @@
|
||||
[](https://crates.io/crates/pin-init)
|
||||
[](https://docs.rs/pin-init/)
|
||||
[](https://deps.rs/repo/github/Rust-for-Linux/pin-init)
|
||||

|
||||
[](#nightly-only)
|
||||

|
||||
# `pin-init`
|
||||
|
||||
<!-- cargo-rdme start -->
|
||||
|
||||
Library to safely and fallibly initialize pinned `struct`s using in-place constructors.
|
||||
|
||||
[Pinning][pinning] is Rust's way of ensuring data does not move.
|
||||
|
||||
It also allows in-place initialization of big `struct`s that would otherwise produce a stack
|
||||
overflow.
|
||||
|
||||
This library's main use-case is in [Rust-for-Linux]. Although this version can be used
|
||||
standalone.
|
||||
|
||||
There are cases when you want to in-place initialize a struct. For example when it is very big
|
||||
and moving it from the stack is not an option, because it is bigger than the stack itself.
|
||||
Another reason would be that you need the address of the object to initialize it. This stands
|
||||
in direct conflict with Rust's normal process of first initializing an object and then moving
|
||||
it into it's final memory location. For more information, see
|
||||
<https://rust-for-linux.com/the-safe-pinned-initialization-problem>.
|
||||
|
||||
This library allows you to do in-place initialization safely.
|
||||
|
||||
### Nightly Needed for `alloc` feature
|
||||
|
||||
This library requires the [`allocator_api` unstable feature] when the `alloc` feature is
|
||||
enabled and thus this feature can only be used with a nightly compiler. When enabling the
|
||||
`alloc` feature, the user will be required to activate `allocator_api` as well.
|
||||
|
||||
[`allocator_api` unstable feature]: https://doc.rust-lang.org/nightly/unstable-book/library-features/allocator-api.html
|
||||
|
||||
The feature is enabled by default, thus by default `pin-init` will require a nightly compiler.
|
||||
However, using the crate on stable compilers is possible by disabling `alloc`. In practice this
|
||||
will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
|
||||
mode.
|
||||
|
||||
## Overview
|
||||
|
||||
To initialize a `struct` with an in-place constructor you will need two things:
|
||||
- an in-place constructor,
|
||||
- a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`],
|
||||
[`Box<T>`] or any other smart pointer that supports this library).
|
||||
|
||||
To get an in-place constructor there are generally three options:
|
||||
- directly creating an in-place constructor using the [`pin_init!`] macro,
|
||||
- a custom function/macro returning an in-place constructor provided by someone else,
|
||||
- using the unsafe function [`pin_init_from_closure()`] to manually create an initializer.
|
||||
|
||||
Aside from pinned initialization, this library also supports in-place construction without
|
||||
pinning, the macros/types/functions are generally named like the pinned variants without the
|
||||
`pin_` prefix.
|
||||
|
||||
## Examples
|
||||
|
||||
Throughout the examples we will often make use of the `CMutex` type which can be found in
|
||||
`../examples/mutex.rs`. It is essentially a userland rebuild of the `struct mutex` type from
|
||||
the Linux kernel. It also uses a wait list and a basic spinlock. Importantly the wait list
|
||||
requires it to be pinned to be locked and thus is a prime candidate for using this library.
|
||||
|
||||
### Using the [`pin_init!`] macro
|
||||
|
||||
If you want to use [`PinInit`], then you will have to annotate your `struct` with
|
||||
`#[`[`pin_data`]`]`. It is a macro that uses `#[pin]` as a marker for
|
||||
[structurally pinned fields]. After doing this, you can then create an in-place constructor via
|
||||
[`pin_init!`]. The syntax is almost the same as normal `struct` initializers. The difference is
|
||||
that you need to write `<-` instead of `:` for fields that you want to initialize in-place.
|
||||
|
||||
```rust
|
||||
use pin_init::{pin_data, pin_init, InPlaceInit};
|
||||
|
||||
#[pin_data]
|
||||
struct Foo {
|
||||
#[pin]
|
||||
a: CMutex<usize>,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
let foo = pin_init!(Foo {
|
||||
a <- CMutex::new(42),
|
||||
b: 24,
|
||||
});
|
||||
```
|
||||
|
||||
`foo` now is of the type [`impl PinInit<Foo>`]. We can now use any smart pointer that we like
|
||||
(or just the stack) to actually initialize a `Foo`:
|
||||
|
||||
```rust
|
||||
let foo: Result<Pin<Box<Foo>>, AllocError> = Box::pin_init(foo);
|
||||
```
|
||||
|
||||
For more information see the [`pin_init!`] macro.
|
||||
|
||||
### Using a custom function/macro that returns an initializer
|
||||
|
||||
Many types that use this library supply a function/macro that returns an initializer, because
|
||||
the above method only works for types where you can access the fields.
|
||||
|
||||
```rust
|
||||
let mtx: Result<Pin<Arc<CMutex<usize>>>, _> = Arc::pin_init(CMutex::new(42));
|
||||
```
|
||||
|
||||
To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
|
||||
|
||||
```rust
|
||||
#[pin_data]
|
||||
struct DriverData {
|
||||
#[pin]
|
||||
status: CMutex<i32>,
|
||||
buffer: Box<[u8; 1_000_000]>,
|
||||
}
|
||||
|
||||
impl DriverData {
|
||||
fn new() -> impl PinInit<Self, Error> {
|
||||
try_pin_init!(Self {
|
||||
status <- CMutex::new(0),
|
||||
buffer: Box::init(pin_init::zeroed())?,
|
||||
}? Error)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Manual creation of an initializer
|
||||
|
||||
Often when working with primitives the previous approaches are not sufficient. That is where
|
||||
[`pin_init_from_closure()`] comes in. This `unsafe` function allows you to create a
|
||||
[`impl PinInit<T, E>`] directly from a closure. Of course you have to ensure that the closure
|
||||
actually does the initialization in the correct way. Here are the things to look out for
|
||||
(we are calling the parameter to the closure `slot`):
|
||||
- when the closure returns `Ok(())`, then it has completed the initialization successfully, so
|
||||
`slot` now contains a valid bit pattern for the type `T`,
|
||||
- when the closure returns `Err(e)`, then the caller may deallocate the memory at `slot`, so
|
||||
you need to take care to clean up anything if your initialization fails mid-way,
|
||||
- you may assume that `slot` will stay pinned even after the closure returns until `drop` of
|
||||
`slot` gets called.
|
||||
|
||||
```rust
|
||||
use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
|
||||
use core::{
|
||||
ptr::addr_of_mut,
|
||||
marker::PhantomPinned,
|
||||
cell::UnsafeCell,
|
||||
pin::Pin,
|
||||
mem::MaybeUninit,
|
||||
};
|
||||
mod bindings {
|
||||
#[repr(C)]
|
||||
pub struct foo {
|
||||
/* fields from C ... */
|
||||
}
|
||||
extern "C" {
|
||||
pub fn init_foo(ptr: *mut foo);
|
||||
pub fn destroy_foo(ptr: *mut foo);
|
||||
#[must_use = "you must check the error return code"]
|
||||
pub fn enable_foo(ptr: *mut foo, flags: u32) -> i32;
|
||||
}
|
||||
}
|
||||
|
||||
/// # Invariants
|
||||
///
|
||||
/// `foo` is always initialized
|
||||
#[pin_data(PinnedDrop)]
|
||||
pub struct RawFoo {
|
||||
#[pin]
|
||||
_p: PhantomPinned,
|
||||
#[pin]
|
||||
foo: UnsafeCell<MaybeUninit<bindings::foo>>,
|
||||
}
|
||||
|
||||
impl RawFoo {
|
||||
pub fn new(flags: u32) -> impl PinInit<Self, i32> {
|
||||
// SAFETY:
|
||||
// - when the closure returns `Ok(())`, then it has successfully initialized and
|
||||
// enabled `foo`,
|
||||
// - when it returns `Err(e)`, then it has cleaned up before
|
||||
unsafe {
|
||||
pin_init_from_closure(move |slot: *mut Self| {
|
||||
// `slot` contains uninit memory, avoid creating a reference.
|
||||
let foo = addr_of_mut!((*slot).foo);
|
||||
let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
|
||||
|
||||
// Initialize the `foo`
|
||||
bindings::init_foo(foo);
|
||||
|
||||
// Try to enable it.
|
||||
let err = bindings::enable_foo(foo, flags);
|
||||
if err != 0 {
|
||||
// Enabling has failed, first clean up the foo and then return the error.
|
||||
bindings::destroy_foo(foo);
|
||||
Err(err)
|
||||
} else {
|
||||
// All fields of `RawFoo` have been initialized, since `_p` is a ZST.
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pinned_drop]
|
||||
impl PinnedDrop for RawFoo {
|
||||
fn drop(self: Pin<&mut Self>) {
|
||||
// SAFETY: Since `foo` is initialized, destroying is safe.
|
||||
unsafe { bindings::destroy_foo(self.foo.get().cast::<bindings::foo>()) };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For more information on how to use [`pin_init_from_closure()`], take a look at the uses inside
|
||||
the `kernel` crate. The [`sync`] module is a good starting point.
|
||||
|
||||
[`sync`]: https://rust.docs.kernel.org/kernel/sync/index.html
|
||||
[pinning]: https://doc.rust-lang.org/std/pin/index.html
|
||||
[structurally pinned fields]: https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
|
||||
[stack]: https://docs.rs/pin-init/latest/pin_init/macro.stack_pin_init.html
|
||||
[`Arc<T>`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html
|
||||
[`Box<T>`]: https://doc.rust-lang.org/stable/alloc/boxed/struct.Box.html
|
||||
[`impl PinInit<Foo>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
|
||||
[`impl PinInit<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
|
||||
[`impl Init<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.Init.html
|
||||
[Rust-for-Linux]: https://rust-for-linux.com/
|
||||
|
||||
<!-- cargo-rdme end -->
|
39
rust/pin-init/examples/big_struct_in_place.rs
Normal file
39
rust/pin-init/examples/big_struct_in_place.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
use pin_init::*;
|
||||
|
||||
// Struct with size over 1GiB
|
||||
#[derive(Debug)]
|
||||
pub struct BigStruct {
|
||||
buf: [u8; 1024 * 1024 * 1024],
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
managed_buf: ManagedBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ManagedBuf {
|
||||
buf: [u8; 1024 * 1024],
|
||||
}
|
||||
|
||||
impl ManagedBuf {
|
||||
pub fn new() -> impl Init<Self> {
|
||||
init!(ManagedBuf { buf <- zeroed() })
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// we want to initialize the struct in-place, otherwise we would get a stackoverflow
|
||||
let buf: Box<BigStruct> = Box::init(init!(BigStruct {
|
||||
buf <- zeroed(),
|
||||
a: 7,
|
||||
b: 186,
|
||||
c: 7789,
|
||||
d: 34,
|
||||
managed_buf <- ManagedBuf::new(),
|
||||
}))
|
||||
.unwrap();
|
||||
println!("{}", core::mem::size_of_val(&*buf));
|
||||
}
|
27
rust/pin-init/examples/error.rs
Normal file
27
rust/pin-init/examples/error.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
#![cfg_attr(feature = "alloc", feature(allocator_api))]
|
||||
|
||||
use core::convert::Infallible;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use std::alloc::AllocError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error;
|
||||
|
||||
impl From<Infallible> for Error {
|
||||
fn from(e: Infallible) -> Self {
|
||||
match e {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl From<AllocError> for Error {
|
||||
fn from(_: AllocError) -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn main() {}
|
161
rust/pin-init/examples/linked_list.rs
Normal file
161
rust/pin-init/examples/linked_list.rs
Normal file
@ -0,0 +1,161 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
#![allow(clippy::undocumented_unsafe_blocks)]
|
||||
#![cfg_attr(feature = "alloc", feature(allocator_api))]
|
||||
|
||||
use core::{
|
||||
cell::Cell,
|
||||
convert::Infallible,
|
||||
marker::PhantomPinned,
|
||||
pin::Pin,
|
||||
ptr::{self, NonNull},
|
||||
};
|
||||
|
||||
use pin_init::*;
|
||||
|
||||
#[expect(unused_attributes)]
|
||||
mod error;
|
||||
use error::Error;
|
||||
|
||||
#[pin_data(PinnedDrop)]
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct ListHead {
|
||||
next: Link,
|
||||
prev: Link,
|
||||
#[pin]
|
||||
pin: PhantomPinned,
|
||||
}
|
||||
|
||||
impl ListHead {
|
||||
#[inline]
|
||||
pub fn new() -> impl PinInit<Self, Infallible> {
|
||||
try_pin_init!(&this in Self {
|
||||
next: unsafe { Link::new_unchecked(this) },
|
||||
prev: unsafe { Link::new_unchecked(this) },
|
||||
pin: PhantomPinned,
|
||||
}? Infallible)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
|
||||
try_pin_init!(&this in Self {
|
||||
prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}),
|
||||
next: list.next.replace(unsafe { Link::new_unchecked(this)}),
|
||||
pin: PhantomPinned,
|
||||
}? Infallible)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn insert_prev(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
|
||||
try_pin_init!(&this in Self {
|
||||
next: list.prev.next().replace(unsafe { Link::new_unchecked(this)}),
|
||||
prev: list.prev.replace(unsafe { Link::new_unchecked(this)}),
|
||||
pin: PhantomPinned,
|
||||
}? Infallible)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next(&self) -> Option<NonNull<Self>> {
|
||||
if ptr::eq(self.next.as_ptr(), self) {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { NonNull::new_unchecked(self.next.as_ptr() as *mut Self) })
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn size(&self) -> usize {
|
||||
let mut size = 1;
|
||||
let mut cur = self.next.clone();
|
||||
while !ptr::eq(self, cur.cur()) {
|
||||
cur = cur.next().clone();
|
||||
size += 1;
|
||||
}
|
||||
size
|
||||
}
|
||||
}
|
||||
|
||||
#[pinned_drop]
|
||||
impl PinnedDrop for ListHead {
|
||||
//#[inline]
|
||||
fn drop(self: Pin<&mut Self>) {
|
||||
if !ptr::eq(self.next.as_ptr(), &*self) {
|
||||
let next = unsafe { &*self.next.as_ptr() };
|
||||
let prev = unsafe { &*self.prev.as_ptr() };
|
||||
next.prev.set(&self.prev);
|
||||
prev.next.set(&self.next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct Link(Cell<NonNull<ListHead>>);
|
||||
|
||||
impl Link {
|
||||
/// # Safety
|
||||
///
|
||||
/// The contents of the pointer should form a consistent circular
|
||||
/// linked list; for example, a "next" link should be pointed back
|
||||
/// by the target `ListHead`'s "prev" link and a "prev" link should be
|
||||
/// pointed back by the target `ListHead`'s "next" link.
|
||||
#[inline]
|
||||
unsafe fn new_unchecked(ptr: NonNull<ListHead>) -> Self {
|
||||
Self(Cell::new(ptr))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next(&self) -> &Link {
|
||||
unsafe { &(*self.0.get().as_ptr()).next }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn prev(&self) -> &Link {
|
||||
unsafe { &(*self.0.get().as_ptr()).prev }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn cur(&self) -> &ListHead {
|
||||
unsafe { &*self.0.get().as_ptr() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn replace(&self, other: Link) -> Link {
|
||||
unsafe { Link::new_unchecked(self.0.replace(other.0.get())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_ptr(&self) -> *const ListHead {
|
||||
self.0.get().as_ptr()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set(&self, val: &Link) {
|
||||
self.0.set(val.0.get());
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg_attr(test, test)]
|
||||
fn main() -> Result<(), Error> {
|
||||
let a = Box::pin_init(ListHead::new())?;
|
||||
stack_pin_init!(let b = ListHead::insert_next(&a));
|
||||
stack_pin_init!(let c = ListHead::insert_next(&a));
|
||||
stack_pin_init!(let d = ListHead::insert_next(&b));
|
||||
let e = Box::pin_init(ListHead::insert_next(&b))?;
|
||||
println!("a ({a:p}): {a:?}");
|
||||
println!("b ({b:p}): {b:?}");
|
||||
println!("c ({c:p}): {c:?}");
|
||||
println!("d ({d:p}): {d:?}");
|
||||
println!("e ({e:p}): {e:?}");
|
||||
let mut inspect = &*a;
|
||||
while let Some(next) = inspect.next() {
|
||||
println!("({inspect:p}): {inspect:?}");
|
||||
inspect = unsafe { &*next.as_ptr() };
|
||||
if core::ptr::eq(inspect, &*a) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
209
rust/pin-init/examples/mutex.rs
Normal file
209
rust/pin-init/examples/mutex.rs
Normal file
@ -0,0 +1,209 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
#![allow(clippy::undocumented_unsafe_blocks)]
|
||||
#![cfg_attr(feature = "alloc", feature(allocator_api))]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
||||
use core::{
|
||||
cell::{Cell, UnsafeCell},
|
||||
marker::PhantomPinned,
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
use std::{
|
||||
sync::Arc,
|
||||
thread::{self, park, sleep, Builder, Thread},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use pin_init::*;
|
||||
#[expect(unused_attributes)]
|
||||
#[path = "./linked_list.rs"]
|
||||
pub mod linked_list;
|
||||
use linked_list::*;
|
||||
|
||||
pub struct SpinLock {
|
||||
inner: AtomicBool,
|
||||
}
|
||||
|
||||
impl SpinLock {
|
||||
#[inline]
|
||||
pub fn acquire(&self) -> SpinLockGuard<'_> {
|
||||
while self
|
||||
.inner
|
||||
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
while self.inner.load(Ordering::Relaxed) {
|
||||
thread::yield_now();
|
||||
}
|
||||
}
|
||||
SpinLockGuard(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
inner: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpinLockGuard<'a>(&'a SpinLock);
|
||||
|
||||
impl Drop for SpinLockGuard<'_> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
self.0.inner.store(false, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_data]
|
||||
pub struct CMutex<T> {
|
||||
#[pin]
|
||||
wait_list: ListHead,
|
||||
spin_lock: SpinLock,
|
||||
locked: Cell<bool>,
|
||||
#[pin]
|
||||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
impl<T> CMutex<T> {
|
||||
#[inline]
|
||||
pub fn new(val: impl PinInit<T>) -> impl PinInit<Self> {
|
||||
pin_init!(CMutex {
|
||||
wait_list <- ListHead::new(),
|
||||
spin_lock: SpinLock::new(),
|
||||
locked: Cell::new(false),
|
||||
data <- unsafe {
|
||||
pin_init_from_closure(|slot: *mut UnsafeCell<T>| {
|
||||
val.__pinned_init(slot.cast::<T>())
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn lock(&self) -> Pin<CMutexGuard<'_, T>> {
|
||||
let mut sguard = self.spin_lock.acquire();
|
||||
if self.locked.get() {
|
||||
stack_pin_init!(let wait_entry = WaitEntry::insert_new(&self.wait_list));
|
||||
// println!("wait list length: {}", self.wait_list.size());
|
||||
while self.locked.get() {
|
||||
drop(sguard);
|
||||
park();
|
||||
sguard = self.spin_lock.acquire();
|
||||
}
|
||||
// This does have an effect, as the ListHead inside wait_entry implements Drop!
|
||||
#[expect(clippy::drop_non_drop)]
|
||||
drop(wait_entry);
|
||||
}
|
||||
self.locked.set(true);
|
||||
unsafe {
|
||||
Pin::new_unchecked(CMutexGuard {
|
||||
mtx: self,
|
||||
_pin: PhantomPinned,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_data_mut(self: Pin<&mut Self>) -> &mut T {
|
||||
// SAFETY: we have an exclusive reference and thus nobody has access to data.
|
||||
unsafe { &mut *self.data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for CMutex<T> {}
|
||||
unsafe impl<T: Send> Sync for CMutex<T> {}
|
||||
|
||||
pub struct CMutexGuard<'a, T> {
|
||||
mtx: &'a CMutex<T>,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
impl<T> Drop for CMutexGuard<'_, T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
let sguard = self.mtx.spin_lock.acquire();
|
||||
self.mtx.locked.set(false);
|
||||
if let Some(list_field) = self.mtx.wait_list.next() {
|
||||
let wait_entry = list_field.as_ptr().cast::<WaitEntry>();
|
||||
unsafe { (*wait_entry).thread.unpark() };
|
||||
}
|
||||
drop(sguard);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for CMutexGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.mtx.data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for CMutexGuard<'_, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { &mut *self.mtx.data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_data]
|
||||
#[repr(C)]
|
||||
struct WaitEntry {
|
||||
#[pin]
|
||||
wait_list: ListHead,
|
||||
thread: Thread,
|
||||
}
|
||||
|
||||
impl WaitEntry {
|
||||
#[inline]
|
||||
fn insert_new(list: &ListHead) -> impl PinInit<Self> + '_ {
|
||||
pin_init!(Self {
|
||||
thread: thread::current(),
|
||||
wait_list <- ListHead::insert_prev(list),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn main() {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg_attr(test, test)]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn main() {
|
||||
let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap();
|
||||
let mut handles = vec![];
|
||||
let thread_count = 20;
|
||||
let workload = if cfg!(miri) { 100 } else { 1_000 };
|
||||
for i in 0..thread_count {
|
||||
let mtx = mtx.clone();
|
||||
handles.push(
|
||||
Builder::new()
|
||||
.name(format!("worker #{i}"))
|
||||
.spawn(move || {
|
||||
for _ in 0..workload {
|
||||
*mtx.lock() += 1;
|
||||
}
|
||||
println!("{i} halfway");
|
||||
sleep(Duration::from_millis((i as u64) * 10));
|
||||
for _ in 0..workload {
|
||||
*mtx.lock() += 1;
|
||||
}
|
||||
println!("{i} finished");
|
||||
})
|
||||
.expect("should not fail"),
|
||||
);
|
||||
}
|
||||
for h in handles {
|
||||
h.join().expect("thread panicked");
|
||||
}
|
||||
println!("{:?}", &*mtx.lock());
|
||||
assert_eq!(*mtx.lock(), workload * thread_count * 2);
|
||||
}
|
178
rust/pin-init/examples/pthread_mutex.rs
Normal file
178
rust/pin-init/examples/pthread_mutex.rs
Normal file
@ -0,0 +1,178 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
// inspired by https://github.com/nbdd0121/pin-init/blob/trunk/examples/pthread_mutex.rs
|
||||
#![allow(clippy::undocumented_unsafe_blocks)]
|
||||
#![cfg_attr(feature = "alloc", feature(allocator_api))]
|
||||
#[cfg(not(windows))]
|
||||
mod pthread_mtx {
|
||||
#[cfg(feature = "alloc")]
|
||||
use core::alloc::AllocError;
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
marker::PhantomPinned,
|
||||
mem::MaybeUninit,
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
};
|
||||
use pin_init::*;
|
||||
use std::convert::Infallible;
|
||||
|
||||
#[pin_data(PinnedDrop)]
|
||||
pub struct PThreadMutex<T> {
|
||||
#[pin]
|
||||
raw: UnsafeCell<libc::pthread_mutex_t>,
|
||||
data: UnsafeCell<T>,
|
||||
#[pin]
|
||||
pin: PhantomPinned,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for PThreadMutex<T> {}
|
||||
unsafe impl<T: Send> Sync for PThreadMutex<T> {}
|
||||
|
||||
#[pinned_drop]
|
||||
impl<T> PinnedDrop for PThreadMutex<T> {
|
||||
fn drop(self: Pin<&mut Self>) {
|
||||
unsafe {
|
||||
libc::pthread_mutex_destroy(self.raw.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
#[expect(dead_code)]
|
||||
IO(std::io::Error),
|
||||
Alloc,
|
||||
}
|
||||
|
||||
impl From<Infallible> for Error {
|
||||
fn from(e: Infallible) -> Self {
|
||||
match e {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl From<AllocError> for Error {
|
||||
fn from(_: AllocError) -> Self {
|
||||
Self::Alloc
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PThreadMutex<T> {
|
||||
pub fn new(data: T) -> impl PinInit<Self, Error> {
|
||||
fn init_raw() -> impl PinInit<UnsafeCell<libc::pthread_mutex_t>, Error> {
|
||||
let init = |slot: *mut UnsafeCell<libc::pthread_mutex_t>| {
|
||||
// we can cast, because `UnsafeCell` has the same layout as T.
|
||||
let slot: *mut libc::pthread_mutex_t = slot.cast();
|
||||
let mut attr = MaybeUninit::uninit();
|
||||
let attr = attr.as_mut_ptr();
|
||||
// SAFETY: ptr is valid
|
||||
let ret = unsafe { libc::pthread_mutexattr_init(attr) };
|
||||
if ret != 0 {
|
||||
return Err(Error::IO(std::io::Error::from_raw_os_error(ret)));
|
||||
}
|
||||
// SAFETY: attr is initialized
|
||||
let ret = unsafe {
|
||||
libc::pthread_mutexattr_settype(attr, libc::PTHREAD_MUTEX_NORMAL)
|
||||
};
|
||||
if ret != 0 {
|
||||
// SAFETY: attr is initialized
|
||||
unsafe { libc::pthread_mutexattr_destroy(attr) };
|
||||
return Err(Error::IO(std::io::Error::from_raw_os_error(ret)));
|
||||
}
|
||||
// SAFETY: slot is valid
|
||||
unsafe { slot.write(libc::PTHREAD_MUTEX_INITIALIZER) };
|
||||
// SAFETY: attr and slot are valid ptrs and attr is initialized
|
||||
let ret = unsafe { libc::pthread_mutex_init(slot, attr) };
|
||||
// SAFETY: attr was initialized
|
||||
unsafe { libc::pthread_mutexattr_destroy(attr) };
|
||||
if ret != 0 {
|
||||
return Err(Error::IO(std::io::Error::from_raw_os_error(ret)));
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
// SAFETY: mutex has been initialized
|
||||
unsafe { pin_init_from_closure(init) }
|
||||
}
|
||||
try_pin_init!(Self {
|
||||
data: UnsafeCell::new(data),
|
||||
raw <- init_raw(),
|
||||
pin: PhantomPinned,
|
||||
}? Error)
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> PThreadMutexGuard<'_, T> {
|
||||
// SAFETY: raw is always initialized
|
||||
unsafe { libc::pthread_mutex_lock(self.raw.get()) };
|
||||
PThreadMutexGuard { mtx: self }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PThreadMutexGuard<'a, T> {
|
||||
mtx: &'a PThreadMutex<T>,
|
||||
}
|
||||
|
||||
impl<T> Drop for PThreadMutexGuard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: raw is always initialized
|
||||
unsafe { libc::pthread_mutex_unlock(self.mtx.raw.get()) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for PThreadMutexGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.mtx.data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for PThreadMutexGuard<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { &mut *self.mtx.data.get() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(test, test)]
|
||||
fn main() {
|
||||
#[cfg(all(any(feature = "std", feature = "alloc"), not(windows)))]
|
||||
{
|
||||
use core::pin::Pin;
|
||||
use pin_init::*;
|
||||
use pthread_mtx::*;
|
||||
use std::{
|
||||
sync::Arc,
|
||||
thread::{sleep, Builder},
|
||||
time::Duration,
|
||||
};
|
||||
let mtx: Pin<Arc<PThreadMutex<usize>>> = Arc::try_pin_init(PThreadMutex::new(0)).unwrap();
|
||||
let mut handles = vec![];
|
||||
let thread_count = 20;
|
||||
let workload = 1_000_000;
|
||||
for i in 0..thread_count {
|
||||
let mtx = mtx.clone();
|
||||
handles.push(
|
||||
Builder::new()
|
||||
.name(format!("worker #{i}"))
|
||||
.spawn(move || {
|
||||
for _ in 0..workload {
|
||||
*mtx.lock() += 1;
|
||||
}
|
||||
println!("{i} halfway");
|
||||
sleep(Duration::from_millis((i as u64) * 10));
|
||||
for _ in 0..workload {
|
||||
*mtx.lock() += 1;
|
||||
}
|
||||
println!("{i} finished");
|
||||
})
|
||||
.expect("should not fail"),
|
||||
);
|
||||
}
|
||||
for h in handles {
|
||||
h.join().expect("thread panicked");
|
||||
}
|
||||
println!("{:?}", &*mtx.lock());
|
||||
assert_eq!(*mtx.lock(), workload * thread_count * 2);
|
||||
}
|
||||
}
|
122
rust/pin-init/examples/static_init.rs
Normal file
122
rust/pin-init/examples/static_init.rs
Normal file
@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
#![allow(clippy::undocumented_unsafe_blocks)]
|
||||
#![cfg_attr(feature = "alloc", feature(allocator_api))]
|
||||
|
||||
use core::{
|
||||
cell::{Cell, UnsafeCell},
|
||||
mem::MaybeUninit,
|
||||
ops,
|
||||
pin::Pin,
|
||||
time::Duration,
|
||||
};
|
||||
use pin_init::*;
|
||||
use std::{
|
||||
sync::Arc,
|
||||
thread::{sleep, Builder},
|
||||
};
|
||||
|
||||
#[expect(unused_attributes)]
|
||||
mod mutex;
|
||||
use mutex::*;
|
||||
|
||||
pub struct StaticInit<T, I> {
|
||||
cell: UnsafeCell<MaybeUninit<T>>,
|
||||
init: Cell<Option<I>>,
|
||||
lock: SpinLock,
|
||||
present: Cell<bool>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Sync, I> Sync for StaticInit<T, I> {}
|
||||
unsafe impl<T: Send, I> Send for StaticInit<T, I> {}
|
||||
|
||||
impl<T, I: PinInit<T>> StaticInit<T, I> {
|
||||
pub const fn new(init: I) -> Self {
|
||||
Self {
|
||||
cell: UnsafeCell::new(MaybeUninit::uninit()),
|
||||
init: Cell::new(Some(init)),
|
||||
lock: SpinLock::new(),
|
||||
present: Cell::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: PinInit<T>> ops::Deref for StaticInit<T, I> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
if self.present.get() {
|
||||
unsafe { (*self.cell.get()).assume_init_ref() }
|
||||
} else {
|
||||
println!("acquire spinlock on static init");
|
||||
let _guard = self.lock.acquire();
|
||||
println!("rechecking present...");
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
if self.present.get() {
|
||||
return unsafe { (*self.cell.get()).assume_init_ref() };
|
||||
}
|
||||
println!("doing init");
|
||||
let ptr = self.cell.get().cast::<T>();
|
||||
match self.init.take() {
|
||||
Some(f) => unsafe { f.__pinned_init(ptr).unwrap() },
|
||||
None => unsafe { core::hint::unreachable_unchecked() },
|
||||
}
|
||||
self.present.set(true);
|
||||
unsafe { (*self.cell.get()).assume_init_ref() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CountInit;
|
||||
|
||||
unsafe impl PinInit<CMutex<usize>> for CountInit {
|
||||
unsafe fn __pinned_init(
|
||||
self,
|
||||
slot: *mut CMutex<usize>,
|
||||
) -> Result<(), core::convert::Infallible> {
|
||||
let init = CMutex::new(0);
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||
unsafe { init.__pinned_init(slot) }
|
||||
}
|
||||
}
|
||||
|
||||
pub static COUNT: StaticInit<CMutex<usize>, CountInit> = StaticInit::new(CountInit);
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn main() {}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn main() {
|
||||
let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap();
|
||||
let mut handles = vec![];
|
||||
let thread_count = 20;
|
||||
let workload = 1_000;
|
||||
for i in 0..thread_count {
|
||||
let mtx = mtx.clone();
|
||||
handles.push(
|
||||
Builder::new()
|
||||
.name(format!("worker #{i}"))
|
||||
.spawn(move || {
|
||||
for _ in 0..workload {
|
||||
*COUNT.lock() += 1;
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
*mtx.lock() += 1;
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
*COUNT.lock() += 1;
|
||||
}
|
||||
println!("{i} halfway");
|
||||
sleep(Duration::from_millis((i as u64) * 10));
|
||||
for _ in 0..workload {
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
*mtx.lock() += 1;
|
||||
}
|
||||
println!("{i} finished");
|
||||
})
|
||||
.expect("should not fail"),
|
||||
);
|
||||
}
|
||||
for h in handles {
|
||||
h.join().expect("thread panicked");
|
||||
}
|
||||
println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock());
|
||||
assert_eq!(*mtx.lock(), workload * thread_count * 2);
|
||||
}
|
152
rust/pin-init/internal/src/helpers.rs
Normal file
152
rust/pin-init/internal/src/helpers.rs
Normal file
@ -0,0 +1,152 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
#[cfg(not(kernel))]
|
||||
use proc_macro2 as proc_macro;
|
||||
|
||||
use proc_macro::{TokenStream, TokenTree};
|
||||
|
||||
/// Parsed generics.
|
||||
///
|
||||
/// See the field documentation for an explanation what each of the fields represents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// # let input = todo!();
|
||||
/// let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input);
|
||||
/// quote! {
|
||||
/// struct Foo<$($decl_generics)*> {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// impl<$impl_generics> Foo<$ty_generics> {
|
||||
/// fn foo() {
|
||||
/// // ...
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub(crate) struct Generics {
|
||||
/// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`).
|
||||
///
|
||||
/// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`).
|
||||
pub(crate) decl_generics: Vec<TokenTree>,
|
||||
/// The generics with bounds (e.g. `T: Clone, const N: usize`).
|
||||
///
|
||||
/// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`.
|
||||
pub(crate) impl_generics: Vec<TokenTree>,
|
||||
/// The generics without bounds and without default values (e.g. `T, N`).
|
||||
///
|
||||
/// Use this when you use the type that is declared with these generics e.g.
|
||||
/// `Foo<$ty_generics>`.
|
||||
pub(crate) ty_generics: Vec<TokenTree>,
|
||||
}
|
||||
|
||||
/// Parses the given `TokenStream` into `Generics` and the rest.
|
||||
///
|
||||
/// The generics are not present in the rest, but a where clause might remain.
|
||||
pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) {
|
||||
// The generics with bounds and default values.
|
||||
let mut decl_generics = vec![];
|
||||
// `impl_generics`, the declared generics with their bounds.
|
||||
let mut impl_generics = vec![];
|
||||
// Only the names of the generics, without any bounds.
|
||||
let mut ty_generics = vec![];
|
||||
// Tokens not related to the generics e.g. the `where` token and definition.
|
||||
let mut rest = vec![];
|
||||
// The current level of `<`.
|
||||
let mut nesting = 0;
|
||||
let mut toks = input.into_iter();
|
||||
// If we are at the beginning of a generic parameter.
|
||||
let mut at_start = true;
|
||||
let mut skip_until_comma = false;
|
||||
while let Some(tt) = toks.next() {
|
||||
if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') {
|
||||
// Found the end of the generics.
|
||||
break;
|
||||
} else if nesting >= 1 {
|
||||
decl_generics.push(tt.clone());
|
||||
}
|
||||
match tt.clone() {
|
||||
TokenTree::Punct(p) if p.as_char() == '<' => {
|
||||
if nesting >= 1 && !skip_until_comma {
|
||||
// This is inside of the generics and part of some bound.
|
||||
impl_generics.push(tt);
|
||||
}
|
||||
nesting += 1;
|
||||
}
|
||||
TokenTree::Punct(p) if p.as_char() == '>' => {
|
||||
// This is a parsing error, so we just end it here.
|
||||
if nesting == 0 {
|
||||
break;
|
||||
} else {
|
||||
nesting -= 1;
|
||||
if nesting >= 1 && !skip_until_comma {
|
||||
// We are still inside of the generics and part of some bound.
|
||||
impl_generics.push(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => {
|
||||
if nesting == 1 {
|
||||
impl_generics.push(tt.clone());
|
||||
impl_generics.push(tt);
|
||||
skip_until_comma = false;
|
||||
}
|
||||
}
|
||||
_ if !skip_until_comma => {
|
||||
match nesting {
|
||||
// If we haven't entered the generics yet, we still want to keep these tokens.
|
||||
0 => rest.push(tt),
|
||||
1 => {
|
||||
// Here depending on the token, it might be a generic variable name.
|
||||
match tt.clone() {
|
||||
TokenTree::Ident(i) if at_start && i.to_string() == "const" => {
|
||||
let Some(name) = toks.next() else {
|
||||
// Parsing error.
|
||||
break;
|
||||
};
|
||||
impl_generics.push(tt);
|
||||
impl_generics.push(name.clone());
|
||||
ty_generics.push(name.clone());
|
||||
decl_generics.push(name);
|
||||
at_start = false;
|
||||
}
|
||||
TokenTree::Ident(_) if at_start => {
|
||||
impl_generics.push(tt.clone());
|
||||
ty_generics.push(tt);
|
||||
at_start = false;
|
||||
}
|
||||
TokenTree::Punct(p) if p.as_char() == ',' => {
|
||||
impl_generics.push(tt.clone());
|
||||
ty_generics.push(tt);
|
||||
at_start = true;
|
||||
}
|
||||
// Lifetimes begin with `'`.
|
||||
TokenTree::Punct(p) if p.as_char() == '\'' && at_start => {
|
||||
impl_generics.push(tt.clone());
|
||||
ty_generics.push(tt);
|
||||
}
|
||||
// Generics can have default values, we skip these.
|
||||
TokenTree::Punct(p) if p.as_char() == '=' => {
|
||||
skip_until_comma = true;
|
||||
}
|
||||
_ => impl_generics.push(tt),
|
||||
}
|
||||
}
|
||||
_ => impl_generics.push(tt),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
rest.extend(toks);
|
||||
(
|
||||
Generics {
|
||||
impl_generics,
|
||||
decl_generics,
|
||||
ty_generics,
|
||||
},
|
||||
rest,
|
||||
)
|
||||
}
|
48
rust/pin-init/internal/src/lib.rs
Normal file
48
rust/pin-init/internal/src/lib.rs
Normal file
@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
// When fixdep scans this, it will find this string `CONFIG_RUSTC_VERSION_TEXT`
|
||||
// and thus add a dependency on `include/config/RUSTC_VERSION_TEXT`, which is
|
||||
// touched by Kconfig when the version string from the compiler changes.
|
||||
|
||||
//! `pin-init` proc macros.
|
||||
|
||||
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
|
||||
// Allow `.into()` to convert
|
||||
// - `proc_macro2::TokenStream` into `proc_macro::TokenStream` in the user-space version.
|
||||
// - `proc_macro::TokenStream` into `proc_macro::TokenStream` in the kernel version.
|
||||
// Clippy warns on this conversion, but it's required by the user-space version.
|
||||
//
|
||||
// Remove once we have `proc_macro2` in the kernel.
|
||||
#![allow(clippy::useless_conversion)]
|
||||
// Documentation is done in the pin-init crate instead.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[cfg(kernel)]
|
||||
#[path = "../../../macros/quote.rs"]
|
||||
#[macro_use]
|
||||
mod quote;
|
||||
#[cfg(not(kernel))]
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
|
||||
mod helpers;
|
||||
mod pin_data;
|
||||
mod pinned_drop;
|
||||
mod zeroable;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
|
||||
pin_data::pin_data(inner.into(), item.into()).into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
pinned_drop::pinned_drop(args.into(), input.into()).into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Zeroable)]
|
||||
pub fn derive_zeroable(input: TokenStream) -> TokenStream {
|
||||
zeroable::derive(input.into()).into()
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
#[cfg(not(kernel))]
|
||||
use proc_macro2 as proc_macro;
|
||||
|
||||
use crate::helpers::{parse_generics, Generics};
|
||||
use proc_macro::{Group, Punct, Spacing, TokenStream, TokenTree};
|
||||
|
||||
pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
// This proc-macro only does some pre-parsing and then delegates the actual parsing to
|
||||
// `kernel::__pin_data!`.
|
||||
// `pin_init::__pin_data!`.
|
||||
|
||||
let (
|
||||
Generics {
|
||||
@ -71,7 +74,7 @@ pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
.collect::<Vec<_>>();
|
||||
// This should be the body of the struct `{...}`.
|
||||
let last = rest.pop();
|
||||
let mut quoted = quote!(::kernel::__pin_data! {
|
||||
let mut quoted = quote!(::pin_init::__pin_data! {
|
||||
parse_input:
|
||||
@args(#args),
|
||||
@sig(#(#rest)*),
|
@ -1,5 +1,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
#[cfg(not(kernel))]
|
||||
use proc_macro2 as proc_macro;
|
||||
|
||||
use proc_macro::{TokenStream, TokenTree};
|
||||
|
||||
pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
@ -35,11 +38,11 @@ pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream
|
||||
let idx = pinned_drop_idx
|
||||
.unwrap_or_else(|| panic!("Expected an `impl` block implementing `PinnedDrop`."));
|
||||
// Fully qualify the `PinnedDrop`, as to avoid any tampering.
|
||||
toks.splice(idx..idx, quote!(::kernel::init::));
|
||||
toks.splice(idx..idx, quote!(::pin_init::));
|
||||
// Take the `{}` body and call the declarative macro.
|
||||
if let Some(TokenTree::Group(last)) = toks.pop() {
|
||||
let last = last.stream();
|
||||
quote!(::kernel::__pinned_drop! {
|
||||
quote!(::pin_init::__pinned_drop! {
|
||||
@impl_sig(#(#toks)*),
|
||||
@impl_body(#last),
|
||||
})
|
@ -1,5 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#[cfg(not(kernel))]
|
||||
use proc_macro2 as proc_macro;
|
||||
|
||||
use crate::helpers::{parse_generics, Generics};
|
||||
use proc_macro::{TokenStream, TokenTree};
|
||||
|
||||
@ -27,7 +30,7 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {
|
||||
// If we find a `,`, then we have finished a generic/constant/lifetime parameter.
|
||||
TokenTree::Punct(p) if nested == 0 && p.as_char() == ',' => {
|
||||
if in_generic && !inserted {
|
||||
new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });
|
||||
new_impl_generics.extend(quote! { : ::pin_init::Zeroable });
|
||||
}
|
||||
in_generic = true;
|
||||
inserted = false;
|
||||
@ -41,7 +44,7 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {
|
||||
TokenTree::Punct(p) if nested == 0 && p.as_char() == ':' => {
|
||||
new_impl_generics.push(tt);
|
||||
if in_generic {
|
||||
new_impl_generics.extend(quote! { ::kernel::init::Zeroable + });
|
||||
new_impl_generics.extend(quote! { ::pin_init::Zeroable + });
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
@ -59,10 +62,10 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
assert_eq!(nested, 0);
|
||||
if in_generic && !inserted {
|
||||
new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });
|
||||
new_impl_generics.extend(quote! { : ::pin_init::Zeroable });
|
||||
}
|
||||
quote! {
|
||||
::kernel::__derive_zeroable!(
|
||||
::pin_init::__derive_zeroable!(
|
||||
parse_input:
|
||||
@sig(#(#rest)*),
|
||||
@impl_generics(#(#new_impl_generics)*),
|
@ -1,19 +1,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
//! This module contains API-internal items for pin-init.
|
||||
//! This module contains library internal items.
|
||||
//!
|
||||
//! These items must not be used outside of
|
||||
//! - `kernel/init.rs`
|
||||
//! - `macros/pin_data.rs`
|
||||
//! - `macros/pinned_drop.rs`
|
||||
//! These items must not be used outside of this crate and the pin-init-internal crate located at
|
||||
//! `../internal`.
|
||||
|
||||
use super::*;
|
||||
|
||||
/// See the [nomicon] for what subtyping is. See also [this table].
|
||||
///
|
||||
/// The reason for not using `PhantomData<*mut T>` is that that type never implements [`Send`] and
|
||||
/// [`Sync`]. Hence `fn(*mut T) -> *mut T` is used, as that type always implements them.
|
||||
///
|
||||
/// [nomicon]: https://doc.rust-lang.org/nomicon/subtyping.html
|
||||
/// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns
|
||||
pub(super) type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>;
|
||||
pub(crate) type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>;
|
||||
|
||||
/// Module-internal type implementing `PinInit` and `Init`.
|
||||
///
|
||||
@ -105,7 +106,7 @@ pub unsafe trait InitData: Copy {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AllData<T: ?Sized>(PhantomData<fn(KBox<T>) -> KBox<T>>);
|
||||
pub struct AllData<T: ?Sized>(Invariant<T>);
|
||||
|
||||
impl<T: ?Sized> Clone for AllData<T> {
|
||||
fn clone(&self) -> Self {
|
||||
@ -135,7 +136,7 @@ unsafe impl<T: ?Sized> HasInitData for T {
|
||||
///
|
||||
/// If `self.is_init` is true, then `self.value` is initialized.
|
||||
///
|
||||
/// [`stack_pin_init`]: kernel::stack_pin_init
|
||||
/// [`stack_pin_init`]: crate::stack_pin_init
|
||||
pub struct StackInit<T> {
|
||||
value: MaybeUninit<T>,
|
||||
is_init: bool,
|
||||
@ -156,7 +157,7 @@ impl<T> StackInit<T> {
|
||||
/// Creates a new [`StackInit<T>`] that is uninitialized. Use [`stack_pin_init`] instead of this
|
||||
/// primitive.
|
||||
///
|
||||
/// [`stack_pin_init`]: kernel::stack_pin_init
|
||||
/// [`stack_pin_init`]: crate::stack_pin_init
|
||||
#[inline]
|
||||
pub fn uninit() -> Self {
|
||||
Self {
|
||||
@ -186,6 +187,33 @@ impl<T> StackInit<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stack_init_reuse() {
|
||||
use ::std::{borrow::ToOwned, println, string::String};
|
||||
use core::pin::pin;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Foo {
|
||||
a: usize,
|
||||
b: String,
|
||||
}
|
||||
let mut slot: Pin<&mut StackInit<Foo>> = pin!(StackInit::uninit());
|
||||
let value: Result<Pin<&mut Foo>, core::convert::Infallible> =
|
||||
slot.as_mut().init(crate::init!(Foo {
|
||||
a: 42,
|
||||
b: "Hello".to_owned(),
|
||||
}));
|
||||
let value = value.unwrap();
|
||||
println!("{value:?}");
|
||||
let value: Result<Pin<&mut Foo>, core::convert::Infallible> =
|
||||
slot.as_mut().init(crate::init!(Foo {
|
||||
a: 24,
|
||||
b: "world!".to_owned(),
|
||||
}));
|
||||
let value = value.unwrap();
|
||||
println!("{value:?}");
|
||||
}
|
||||
|
||||
/// When a value of this type is dropped, it drops a `T`.
|
||||
///
|
||||
/// Can be forgotten to prevent the drop.
|
158
rust/pin-init/src/alloc.rs
Normal file
158
rust/pin-init/src/alloc.rs
Normal file
@ -0,0 +1,158 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
#[cfg(feature = "alloc")]
|
||||
use core::alloc::AllocError;
|
||||
use core::{mem::MaybeUninit, pin::Pin};
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
type AllocError = core::convert::Infallible;
|
||||
|
||||
use crate::{
|
||||
init_from_closure, pin_init_from_closure, InPlaceWrite, Init, PinInit, ZeroableOption,
|
||||
};
|
||||
|
||||
pub extern crate alloc;
|
||||
|
||||
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee).
|
||||
//
|
||||
// In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant and there
|
||||
// is no problem with a VTABLE pointer being null.
|
||||
unsafe impl<T: ?Sized> ZeroableOption for Box<T> {}
|
||||
|
||||
/// Smart pointer that can initialize memory in-place.
|
||||
pub trait InPlaceInit<T>: Sized {
|
||||
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
|
||||
/// type.
|
||||
///
|
||||
/// If `T: !Unpin` it will not be able to move afterwards.
|
||||
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
|
||||
where
|
||||
E: From<AllocError>;
|
||||
|
||||
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
|
||||
/// type.
|
||||
///
|
||||
/// If `T: !Unpin` it will not be able to move afterwards.
|
||||
fn pin_init(init: impl PinInit<T>) -> Result<Pin<Self>, AllocError> {
|
||||
// SAFETY: We delegate to `init` and only change the error type.
|
||||
let init = unsafe {
|
||||
pin_init_from_closure(|slot| match init.__pinned_init(slot) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(i) => match i {},
|
||||
})
|
||||
};
|
||||
Self::try_pin_init(init)
|
||||
}
|
||||
|
||||
/// Use the given initializer to in-place initialize a `T`.
|
||||
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
|
||||
where
|
||||
E: From<AllocError>;
|
||||
|
||||
/// Use the given initializer to in-place initialize a `T`.
|
||||
fn init(init: impl Init<T>) -> Result<Self, AllocError> {
|
||||
// SAFETY: We delegate to `init` and only change the error type.
|
||||
let init = unsafe {
|
||||
init_from_closure(|slot| match init.__init(slot) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(i) => match i {},
|
||||
})
|
||||
};
|
||||
Self::try_init(init)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
macro_rules! try_new_uninit {
|
||||
($type:ident) => {
|
||||
$type::try_new_uninit()?
|
||||
};
|
||||
}
|
||||
#[cfg(all(feature = "std", not(feature = "alloc")))]
|
||||
macro_rules! try_new_uninit {
|
||||
($type:ident) => {
|
||||
$type::new_uninit()
|
||||
};
|
||||
}
|
||||
|
||||
impl<T> InPlaceInit<T> for Box<T> {
|
||||
#[inline]
|
||||
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
|
||||
where
|
||||
E: From<AllocError>,
|
||||
{
|
||||
try_new_uninit!(Box).write_pin_init(init)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
|
||||
where
|
||||
E: From<AllocError>,
|
||||
{
|
||||
try_new_uninit!(Box).write_init(init)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> InPlaceInit<T> for Arc<T> {
|
||||
#[inline]
|
||||
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
|
||||
where
|
||||
E: From<AllocError>,
|
||||
{
|
||||
let mut this = try_new_uninit!(Arc);
|
||||
let Some(slot) = Arc::get_mut(&mut this) else {
|
||||
// SAFETY: the Arc has just been created and has no external references
|
||||
unsafe { core::hint::unreachable_unchecked() }
|
||||
};
|
||||
let slot = slot.as_mut_ptr();
|
||||
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
|
||||
// slot is valid and will not be moved, because we pin it later.
|
||||
unsafe { init.__pinned_init(slot)? };
|
||||
// SAFETY: All fields have been initialized and this is the only `Arc` to that data.
|
||||
Ok(unsafe { Pin::new_unchecked(this.assume_init()) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
|
||||
where
|
||||
E: From<AllocError>,
|
||||
{
|
||||
let mut this = try_new_uninit!(Arc);
|
||||
let Some(slot) = Arc::get_mut(&mut this) else {
|
||||
// SAFETY: the Arc has just been created and has no external references
|
||||
unsafe { core::hint::unreachable_unchecked() }
|
||||
};
|
||||
let slot = slot.as_mut_ptr();
|
||||
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
|
||||
// slot is valid.
|
||||
unsafe { init.__init(slot)? };
|
||||
// SAFETY: All fields have been initialized.
|
||||
Ok(unsafe { this.assume_init() })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> InPlaceWrite<T> for Box<MaybeUninit<T>> {
|
||||
type Initialized = Box<T>;
|
||||
|
||||
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
|
||||
let slot = self.as_mut_ptr();
|
||||
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
|
||||
// slot is valid.
|
||||
unsafe { init.__init(slot)? };
|
||||
// SAFETY: All fields have been initialized.
|
||||
Ok(unsafe { self.assume_init() })
|
||||
}
|
||||
|
||||
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
|
||||
let slot = self.as_mut_ptr();
|
||||
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
|
||||
// slot is valid and will not be moved, because we pin it later.
|
||||
unsafe { init.__pinned_init(slot)? };
|
||||
// SAFETY: All fields have been initialized.
|
||||
Ok(unsafe { self.assume_init() }.into())
|
||||
}
|
||||
}
|
1483
rust/pin-init/src/lib.rs
Normal file
1483
rust/pin-init/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
//! This module provides the macros that actually implement the proc-macros `pin_data` and
|
||||
//! `pinned_drop`. It also contains `__init_internal` the implementation of the `{try_}{pin_}init!`
|
||||
//! macros.
|
||||
//! `pinned_drop`. It also contains `__init_internal`, the implementation of the
|
||||
//! `{try_}{pin_}init!` macros.
|
||||
//!
|
||||
//! These macros should never be called directly, since they expect their input to be
|
||||
//! in a certain format which is internal. If used incorrectly, these macros can lead to UB even in
|
||||
@ -11,16 +11,17 @@
|
||||
//! This architecture has been chosen because the kernel does not yet have access to `syn` which
|
||||
//! would make matters a lot easier for implementing these as proc-macros.
|
||||
//!
|
||||
//! Since this library and the kernel implementation should diverge as little as possible, the same
|
||||
//! approach has been taken here.
|
||||
//!
|
||||
//! # Macro expansion example
|
||||
//!
|
||||
//! This section is intended for readers trying to understand the macros in this module and the
|
||||
//! `pin_init!` macros from `init.rs`.
|
||||
//! `[try_][pin_]init!` macros from `lib.rs`.
|
||||
//!
|
||||
//! We will look at the following example:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # use kernel::init::*;
|
||||
//! # use core::pin::Pin;
|
||||
//! #[pin_data]
|
||||
//! #[repr(C)]
|
||||
//! struct Bar<T> {
|
||||
@ -45,7 +46,7 @@
|
||||
//! #[pinned_drop]
|
||||
//! impl PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>) {
|
||||
//! pr_info!("{self:p} is getting dropped.\n");
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
@ -75,7 +76,6 @@
|
||||
//! Here is the definition of `Bar` from our example:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # use kernel::init::*;
|
||||
//! #[pin_data]
|
||||
//! #[repr(C)]
|
||||
//! struct Bar<T> {
|
||||
@ -121,22 +121,22 @@
|
||||
//! self,
|
||||
//! slot: *mut T,
|
||||
//! // Since `t` is `#[pin]`, this is `PinInit`.
|
||||
//! init: impl ::kernel::init::PinInit<T, E>,
|
||||
//! init: impl ::pin_init::PinInit<T, E>,
|
||||
//! ) -> ::core::result::Result<(), E> {
|
||||
//! unsafe { ::kernel::init::PinInit::__pinned_init(init, slot) }
|
||||
//! unsafe { ::pin_init::PinInit::__pinned_init(init, slot) }
|
||||
//! }
|
||||
//! pub unsafe fn x<E>(
|
||||
//! self,
|
||||
//! slot: *mut usize,
|
||||
//! // Since `x` is not `#[pin]`, this is `Init`.
|
||||
//! init: impl ::kernel::init::Init<usize, E>,
|
||||
//! init: impl ::pin_init::Init<usize, E>,
|
||||
//! ) -> ::core::result::Result<(), E> {
|
||||
//! unsafe { ::kernel::init::Init::__init(init, slot) }
|
||||
//! unsafe { ::pin_init::Init::__init(init, slot) }
|
||||
//! }
|
||||
//! }
|
||||
//! // Implement the internal `HasPinData` trait that associates `Bar` with the pin-data struct
|
||||
//! // that we constructed above.
|
||||
//! unsafe impl<T> ::kernel::init::__internal::HasPinData for Bar<T> {
|
||||
//! unsafe impl<T> ::pin_init::__internal::HasPinData for Bar<T> {
|
||||
//! type PinData = __ThePinData<T>;
|
||||
//! unsafe fn __pin_data() -> Self::PinData {
|
||||
//! __ThePinData {
|
||||
@ -147,7 +147,7 @@
|
||||
//! // Implement the internal `PinData` trait that marks the pin-data struct as a pin-data
|
||||
//! // struct. This is important to ensure that no user can implement a rogue `__pin_data`
|
||||
//! // function without using `unsafe`.
|
||||
//! unsafe impl<T> ::kernel::init::__internal::PinData for __ThePinData<T> {
|
||||
//! unsafe impl<T> ::pin_init::__internal::PinData for __ThePinData<T> {
|
||||
//! type Datee = Bar<T>;
|
||||
//! }
|
||||
//! // Now we only want to implement `Unpin` for `Bar` when every structurally pinned field is
|
||||
@ -191,7 +191,7 @@
|
||||
//! #[expect(non_camel_case_types)]
|
||||
//! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
|
||||
//! impl<
|
||||
//! T: ::kernel::init::PinnedDrop,
|
||||
//! T: ::pin_init::PinnedDrop,
|
||||
//! > UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
|
||||
//! impl<T> UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for Bar<T> {}
|
||||
//! };
|
||||
@ -227,11 +227,11 @@
|
||||
//! // - we `use` the `HasPinData` trait in the block, it is only available in that
|
||||
//! // scope.
|
||||
//! let data = unsafe {
|
||||
//! use ::kernel::init::__internal::HasPinData;
|
||||
//! use ::pin_init::__internal::HasPinData;
|
||||
//! Self::__pin_data()
|
||||
//! };
|
||||
//! // Ensure that `data` really is of type `PinData` and help with type inference:
|
||||
//! let init = ::kernel::init::__internal::PinData::make_closure::<
|
||||
//! let init = ::pin_init::__internal::PinData::make_closure::<
|
||||
//! _,
|
||||
//! __InitOk,
|
||||
//! ::core::convert::Infallible,
|
||||
@ -251,7 +251,7 @@
|
||||
//! // is an error later. This `DropGuard` will drop the field when it gets
|
||||
//! // dropped and has not yet been forgotten.
|
||||
//! let __t_guard = unsafe {
|
||||
//! ::pinned_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).t))
|
||||
//! ::pin_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).t))
|
||||
//! };
|
||||
//! // Expansion of `x: 0,`:
|
||||
//! // Since this can be an arbitrary expression we cannot place it inside
|
||||
@ -262,7 +262,7 @@
|
||||
//! }
|
||||
//! // We again create a `DropGuard`.
|
||||
//! let __x_guard = unsafe {
|
||||
//! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).x))
|
||||
//! ::pin_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).x))
|
||||
//! };
|
||||
//! // Since initialization has successfully completed, we can now forget
|
||||
//! // the guards. This is not `mem::forget`, since we only have
|
||||
@ -303,7 +303,7 @@
|
||||
//! };
|
||||
//! // Construct the initializer.
|
||||
//! let init = unsafe {
|
||||
//! ::kernel::init::pin_init_from_closure::<
|
||||
//! ::pin_init::pin_init_from_closure::<
|
||||
//! _,
|
||||
//! ::core::convert::Infallible,
|
||||
//! >(init)
|
||||
@ -350,19 +350,19 @@
|
||||
//! unsafe fn b<E>(
|
||||
//! self,
|
||||
//! slot: *mut Bar<u32>,
|
||||
//! init: impl ::kernel::init::PinInit<Bar<u32>, E>,
|
||||
//! init: impl ::pin_init::PinInit<Bar<u32>, E>,
|
||||
//! ) -> ::core::result::Result<(), E> {
|
||||
//! unsafe { ::kernel::init::PinInit::__pinned_init(init, slot) }
|
||||
//! unsafe { ::pin_init::PinInit::__pinned_init(init, slot) }
|
||||
//! }
|
||||
//! unsafe fn a<E>(
|
||||
//! self,
|
||||
//! slot: *mut usize,
|
||||
//! init: impl ::kernel::init::Init<usize, E>,
|
||||
//! init: impl ::pin_init::Init<usize, E>,
|
||||
//! ) -> ::core::result::Result<(), E> {
|
||||
//! unsafe { ::kernel::init::Init::__init(init, slot) }
|
||||
//! unsafe { ::pin_init::Init::__init(init, slot) }
|
||||
//! }
|
||||
//! }
|
||||
//! unsafe impl ::kernel::init::__internal::HasPinData for Foo {
|
||||
//! unsafe impl ::pin_init::__internal::HasPinData for Foo {
|
||||
//! type PinData = __ThePinData;
|
||||
//! unsafe fn __pin_data() -> Self::PinData {
|
||||
//! __ThePinData {
|
||||
@ -370,7 +370,7 @@
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! unsafe impl ::kernel::init::__internal::PinData for __ThePinData {
|
||||
//! unsafe impl ::pin_init::__internal::PinData for __ThePinData {
|
||||
//! type Datee = Foo;
|
||||
//! }
|
||||
//! #[allow(dead_code)]
|
||||
@ -394,8 +394,8 @@
|
||||
//! let pinned = unsafe { ::core::pin::Pin::new_unchecked(self) };
|
||||
//! // Create the unsafe token that proves that we are inside of a destructor, this
|
||||
//! // type is only allowed to be created in a destructor.
|
||||
//! let token = unsafe { ::kernel::init::__internal::OnlyCallFromDrop::new() };
|
||||
//! ::kernel::init::PinnedDrop::drop(pinned, token);
|
||||
//! let token = unsafe { ::pin_init::__internal::OnlyCallFromDrop::new() };
|
||||
//! ::pin_init::PinnedDrop::drop(pinned, token);
|
||||
//! }
|
||||
//! }
|
||||
//! };
|
||||
@ -412,7 +412,7 @@
|
||||
//! #[pinned_drop]
|
||||
//! impl PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>) {
|
||||
//! pr_info!("{self:p} is getting dropped.\n");
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
@ -421,9 +421,9 @@
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! // `unsafe`, full path and the token parameter are added, everything else stays the same.
|
||||
//! unsafe impl ::kernel::init::PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>, _: ::kernel::init::__internal::OnlyCallFromDrop) {
|
||||
//! pr_info!("{self:p} is getting dropped.\n");
|
||||
//! unsafe impl ::pin_init::PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>, _: ::pin_init::__internal::OnlyCallFromDrop) {
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
@ -448,10 +448,10 @@
|
||||
//! let initializer = {
|
||||
//! struct __InitOk;
|
||||
//! let data = unsafe {
|
||||
//! use ::kernel::init::__internal::HasPinData;
|
||||
//! use ::pin_init::__internal::HasPinData;
|
||||
//! Foo::__pin_data()
|
||||
//! };
|
||||
//! let init = ::kernel::init::__internal::PinData::make_closure::<
|
||||
//! let init = ::pin_init::__internal::PinData::make_closure::<
|
||||
//! _,
|
||||
//! __InitOk,
|
||||
//! ::core::convert::Infallible,
|
||||
@ -462,12 +462,12 @@
|
||||
//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) };
|
||||
//! }
|
||||
//! let __a_guard = unsafe {
|
||||
//! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).a))
|
||||
//! ::pin_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).a))
|
||||
//! };
|
||||
//! let init = Bar::new(36);
|
||||
//! unsafe { data.b(::core::addr_of_mut!((*slot).b), b)? };
|
||||
//! let __b_guard = unsafe {
|
||||
//! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).b))
|
||||
//! ::pin_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).b))
|
||||
//! };
|
||||
//! ::core::mem::forget(__b_guard);
|
||||
//! ::core::mem::forget(__a_guard);
|
||||
@ -492,12 +492,17 @@
|
||||
//! init(slot).map(|__InitOk| ())
|
||||
//! };
|
||||
//! let init = unsafe {
|
||||
//! ::kernel::init::pin_init_from_closure::<_, ::core::convert::Infallible>(init)
|
||||
//! ::pin_init::pin_init_from_closure::<_, ::core::convert::Infallible>(init)
|
||||
//! };
|
||||
//! init
|
||||
//! };
|
||||
//! ```
|
||||
|
||||
#[cfg(kernel)]
|
||||
pub use ::macros::paste;
|
||||
#[cfg(not(kernel))]
|
||||
pub use ::paste::paste;
|
||||
|
||||
/// Creates a `unsafe impl<...> PinnedDrop for $type` block.
|
||||
///
|
||||
/// See [`PinnedDrop`] for more information.
|
||||
@ -517,7 +522,7 @@ macro_rules! __pinned_drop {
|
||||
unsafe $($impl_sig)* {
|
||||
// Inherit all attributes and the type/ident tokens for the signature.
|
||||
$(#[$($attr)*])*
|
||||
fn drop($($sig)*, _: $crate::init::__internal::OnlyCallFromDrop) {
|
||||
fn drop($($sig)*, _: $crate::__internal::OnlyCallFromDrop) {
|
||||
$($inner)*
|
||||
}
|
||||
}
|
||||
@ -863,7 +868,7 @@ macro_rules! __pin_data {
|
||||
// SAFETY: We have added the correct projection functions above to `__ThePinData` and
|
||||
// we also use the least restrictive generics possible.
|
||||
unsafe impl<$($impl_generics)*>
|
||||
$crate::init::__internal::HasPinData for $name<$($ty_generics)*>
|
||||
$crate::__internal::HasPinData for $name<$($ty_generics)*>
|
||||
where $($whr)*
|
||||
{
|
||||
type PinData = __ThePinData<$($ty_generics)*>;
|
||||
@ -875,7 +880,7 @@ macro_rules! __pin_data {
|
||||
|
||||
// SAFETY: TODO.
|
||||
unsafe impl<$($impl_generics)*>
|
||||
$crate::init::__internal::PinData for __ThePinData<$($ty_generics)*>
|
||||
$crate::__internal::PinData for __ThePinData<$($ty_generics)*>
|
||||
where $($whr)*
|
||||
{
|
||||
type Datee = $name<$($ty_generics)*>;
|
||||
@ -934,7 +939,7 @@ macro_rules! __pin_data {
|
||||
// `PinnedDrop` as the parameter to `#[pin_data]`.
|
||||
#[expect(non_camel_case_types)]
|
||||
trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
|
||||
impl<T: $crate::init::PinnedDrop>
|
||||
impl<T: $crate::PinnedDrop>
|
||||
UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
|
||||
impl<$($impl_generics)*>
|
||||
UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for $name<$($ty_generics)*>
|
||||
@ -957,8 +962,8 @@ macro_rules! __pin_data {
|
||||
let pinned = unsafe { ::core::pin::Pin::new_unchecked(self) };
|
||||
// SAFETY: Since this is a drop function, we can create this token to call the
|
||||
// pinned destructor of this type.
|
||||
let token = unsafe { $crate::init::__internal::OnlyCallFromDrop::new() };
|
||||
$crate::init::PinnedDrop::drop(pinned, token);
|
||||
let token = unsafe { $crate::__internal::OnlyCallFromDrop::new() };
|
||||
$crate::PinnedDrop::drop(pinned, token);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -998,10 +1003,10 @@ macro_rules! __pin_data {
|
||||
$pvis unsafe fn $p_field<E>(
|
||||
self,
|
||||
slot: *mut $p_type,
|
||||
init: impl $crate::init::PinInit<$p_type, E>,
|
||||
init: impl $crate::PinInit<$p_type, E>,
|
||||
) -> ::core::result::Result<(), E> {
|
||||
// SAFETY: TODO.
|
||||
unsafe { $crate::init::PinInit::__pinned_init(init, slot) }
|
||||
unsafe { $crate::PinInit::__pinned_init(init, slot) }
|
||||
}
|
||||
)*
|
||||
$(
|
||||
@ -1009,10 +1014,10 @@ macro_rules! __pin_data {
|
||||
$fvis unsafe fn $field<E>(
|
||||
self,
|
||||
slot: *mut $type,
|
||||
init: impl $crate::init::Init<$type, E>,
|
||||
init: impl $crate::Init<$type, E>,
|
||||
) -> ::core::result::Result<(), E> {
|
||||
// SAFETY: TODO.
|
||||
unsafe { $crate::init::Init::__init(init, slot) }
|
||||
unsafe { $crate::Init::__init(init, slot) }
|
||||
}
|
||||
)*
|
||||
}
|
||||
@ -1129,15 +1134,15 @@ macro_rules! __init_internal {
|
||||
//
|
||||
// SAFETY: TODO.
|
||||
let data = unsafe {
|
||||
use $crate::init::__internal::$has_data;
|
||||
use $crate::__internal::$has_data;
|
||||
// Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal
|
||||
// information that is associated to already parsed fragments, so a path fragment
|
||||
// cannot be used in this position. Doing the retokenization results in valid rust
|
||||
// code.
|
||||
::kernel::macros::paste!($t::$get_data())
|
||||
$crate::macros::paste!($t::$get_data())
|
||||
};
|
||||
// Ensure that `data` really is of type `$data` and help with type inference:
|
||||
let init = $crate::init::__internal::$data::make_closure::<_, __InitOk, $err>(
|
||||
let init = $crate::__internal::$data::make_closure::<_, __InitOk, $err>(
|
||||
data,
|
||||
move |slot| {
|
||||
{
|
||||
@ -1147,7 +1152,7 @@ macro_rules! __init_internal {
|
||||
// error when fields are missing (since they will be zeroed). We also have to
|
||||
// check that the type actually implements `Zeroable`.
|
||||
$({
|
||||
fn assert_zeroable<T: $crate::init::Zeroable>(_: *mut T) {}
|
||||
fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
|
||||
// Ensure that the struct is indeed `Zeroable`.
|
||||
assert_zeroable(slot);
|
||||
// SAFETY: The type implements `Zeroable` by the check above.
|
||||
@ -1184,7 +1189,7 @@ macro_rules! __init_internal {
|
||||
init(slot).map(|__InitOk| ())
|
||||
};
|
||||
// SAFETY: TODO.
|
||||
let init = unsafe { $crate::init::$construct_closure::<_, $err>(init) };
|
||||
let init = unsafe { $crate::$construct_closure::<_, $err>(init) };
|
||||
init
|
||||
}};
|
||||
(init_slot($($use_data:ident)?):
|
||||
@ -1215,10 +1220,10 @@ macro_rules! __init_internal {
|
||||
//
|
||||
// We rely on macro hygiene to make it impossible for users to access this local variable.
|
||||
// We use `paste!` to create new hygiene for `$field`.
|
||||
::kernel::macros::paste! {
|
||||
$crate::macros::paste! {
|
||||
// SAFETY: We forget the guard later when initialization has succeeded.
|
||||
let [< __ $field _guard >] = unsafe {
|
||||
$crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
|
||||
$crate::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
|
||||
};
|
||||
|
||||
$crate::__init_internal!(init_slot($use_data):
|
||||
@ -1241,15 +1246,15 @@ macro_rules! __init_internal {
|
||||
//
|
||||
// SAFETY: `slot` is valid, because we are inside of an initializer closure, we
|
||||
// return when an error/panic occurs.
|
||||
unsafe { $crate::init::Init::__init(init, ::core::ptr::addr_of_mut!((*$slot).$field))? };
|
||||
unsafe { $crate::Init::__init(init, ::core::ptr::addr_of_mut!((*$slot).$field))? };
|
||||
// Create the drop guard:
|
||||
//
|
||||
// We rely on macro hygiene to make it impossible for users to access this local variable.
|
||||
// We use `paste!` to create new hygiene for `$field`.
|
||||
::kernel::macros::paste! {
|
||||
$crate::macros::paste! {
|
||||
// SAFETY: We forget the guard later when initialization has succeeded.
|
||||
let [< __ $field _guard >] = unsafe {
|
||||
$crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
|
||||
$crate::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
|
||||
};
|
||||
|
||||
$crate::__init_internal!(init_slot():
|
||||
@ -1278,10 +1283,10 @@ macro_rules! __init_internal {
|
||||
//
|
||||
// We rely on macro hygiene to make it impossible for users to access this local variable.
|
||||
// We use `paste!` to create new hygiene for `$field`.
|
||||
::kernel::macros::paste! {
|
||||
$crate::macros::paste! {
|
||||
// SAFETY: We forget the guard later when initialization has succeeded.
|
||||
let [< __ $field _guard >] = unsafe {
|
||||
$crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
|
||||
$crate::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
|
||||
};
|
||||
|
||||
$crate::__init_internal!(init_slot($($use_data)?):
|
||||
@ -1315,7 +1320,7 @@ macro_rules! __init_internal {
|
||||
// information that is associated to already parsed fragments, so a path fragment
|
||||
// cannot be used in this position. Doing the retokenization results in valid rust
|
||||
// code.
|
||||
::kernel::macros::paste!(
|
||||
$crate::macros::paste!(
|
||||
::core::ptr::write($slot, $t {
|
||||
$($acc)*
|
||||
..zeroed
|
||||
@ -1339,7 +1344,7 @@ macro_rules! __init_internal {
|
||||
// information that is associated to already parsed fragments, so a path fragment
|
||||
// cannot be used in this position. Doing the retokenization results in valid rust
|
||||
// code.
|
||||
::kernel::macros::paste!(
|
||||
$crate::macros::paste!(
|
||||
::core::ptr::write($slot, $t {
|
||||
$($acc)*
|
||||
});
|
||||
@ -1394,12 +1399,12 @@ macro_rules! __derive_zeroable {
|
||||
) => {
|
||||
// SAFETY: Every field type implements `Zeroable` and padding bytes may be zero.
|
||||
#[automatically_derived]
|
||||
unsafe impl<$($impl_generics)*> $crate::init::Zeroable for $name<$($ty_generics)*>
|
||||
unsafe impl<$($impl_generics)*> $crate::Zeroable for $name<$($ty_generics)*>
|
||||
where
|
||||
$($($whr)*)?
|
||||
{}
|
||||
const _: () = {
|
||||
fn assert_zeroable<T: ?::core::marker::Sized + $crate::init::Zeroable>() {}
|
||||
fn assert_zeroable<T: ?::core::marker::Sized + $crate::Zeroable>() {}
|
||||
fn ensure_zeroable<$($impl_generics)*>()
|
||||
where $($($whr)*)?
|
||||
{
|
@ -40,6 +40,17 @@ config SAMPLE_RUST_PRINT
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SAMPLE_RUST_DMA
|
||||
tristate "DMA Test Driver"
|
||||
depends on PCI
|
||||
help
|
||||
This option builds the Rust DMA Test driver sample.
|
||||
|
||||
To compile this as a module, choose M here:
|
||||
the module will be called rust_dma.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SAMPLE_RUST_DRIVER_PCI
|
||||
tristate "PCI Driver"
|
||||
depends on PCI
|
||||
|
@ -4,6 +4,7 @@ ccflags-y += -I$(src) # needed for trace events
|
||||
obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o
|
||||
obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o
|
||||
obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o
|
||||
obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o
|
||||
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o
|
||||
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o
|
||||
obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) += rust_driver_faux.o
|
||||
|
97
samples/rust/rust_dma.rs
Normal file
97
samples/rust/rust_dma.rs
Normal file
@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! Rust DMA api test (based on QEMU's `pci-testdev`).
|
||||
//!
|
||||
//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
|
||||
|
||||
use kernel::{bindings, dma::CoherentAllocation, pci, prelude::*};
|
||||
|
||||
struct DmaSampleDriver {
|
||||
pdev: pci::Device,
|
||||
ca: CoherentAllocation<MyStruct>,
|
||||
}
|
||||
|
||||
const TEST_VALUES: [(u32, u32); 5] = [
|
||||
(0xa, 0xb),
|
||||
(0xc, 0xd),
|
||||
(0xe, 0xf),
|
||||
(0xab, 0xba),
|
||||
(0xcd, 0xef),
|
||||
];
|
||||
|
||||
struct MyStruct {
|
||||
h: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
impl MyStruct {
|
||||
fn new(h: u32, b: u32) -> Self {
|
||||
Self { h, b }
|
||||
}
|
||||
}
|
||||
// SAFETY: All bit patterns are acceptable values for `MyStruct`.
|
||||
unsafe impl kernel::transmute::AsBytes for MyStruct {}
|
||||
// SAFETY: Instances of `MyStruct` have no uninitialized portions.
|
||||
unsafe impl kernel::transmute::FromBytes for MyStruct {}
|
||||
|
||||
kernel::pci_device_table!(
|
||||
PCI_TABLE,
|
||||
MODULE_PCI_TABLE,
|
||||
<DmaSampleDriver as pci::Driver>::IdInfo,
|
||||
[(
|
||||
pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
|
||||
()
|
||||
)]
|
||||
);
|
||||
|
||||
impl pci::Driver for DmaSampleDriver {
|
||||
type IdInfo = ();
|
||||
const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
|
||||
|
||||
fn probe(pdev: &mut pci::Device, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
|
||||
dev_info!(pdev.as_ref(), "Probe DMA test driver.\n");
|
||||
|
||||
let ca: CoherentAllocation<MyStruct> =
|
||||
CoherentAllocation::alloc_coherent(pdev.as_ref(), TEST_VALUES.len(), GFP_KERNEL)?;
|
||||
|
||||
|| -> Result {
|
||||
for (i, value) in TEST_VALUES.into_iter().enumerate() {
|
||||
kernel::dma_write!(ca[i] = MyStruct::new(value.0, value.1));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}()?;
|
||||
|
||||
let drvdata = KBox::new(
|
||||
Self {
|
||||
pdev: pdev.clone(),
|
||||
ca,
|
||||
},
|
||||
GFP_KERNEL,
|
||||
)?;
|
||||
|
||||
Ok(drvdata.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DmaSampleDriver {
|
||||
fn drop(&mut self) {
|
||||
dev_info!(self.pdev.as_ref(), "Unload DMA test driver.\n");
|
||||
|
||||
let _ = || -> Result {
|
||||
for (i, value) in TEST_VALUES.into_iter().enumerate() {
|
||||
assert_eq!(kernel::dma_read!(self.ca[i].h), value.0);
|
||||
assert_eq!(kernel::dma_read!(self.ca[i].b), value.1);
|
||||
}
|
||||
Ok(())
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
kernel::module_pci_driver! {
|
||||
type: DmaSampleDriver,
|
||||
name: "rust_dma",
|
||||
authors: ["Abdiel Janulgue"],
|
||||
description: "Rust DMA test",
|
||||
license: "GPL v2",
|
||||
}
|
@ -7,7 +7,7 @@ use kernel::{c_str, faux, prelude::*, Module};
|
||||
module! {
|
||||
type: SampleModule,
|
||||
name: "rust_faux_driver",
|
||||
author: "Lyude Paul",
|
||||
authors: ["Lyude Paul"],
|
||||
description: "Rust faux device sample",
|
||||
license: "GPL",
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ impl Drop for SampleDriver {
|
||||
kernel::module_pci_driver! {
|
||||
type: SampleDriver,
|
||||
name: "rust_driver_pci",
|
||||
author: "Danilo Krummrich",
|
||||
authors: ["Danilo Krummrich"],
|
||||
description: "Rust PCI driver",
|
||||
license: "GPL v2",
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ impl Drop for SampleDriver {
|
||||
kernel::module_platform_driver! {
|
||||
type: SampleDriver,
|
||||
name: "rust_driver_platform",
|
||||
author: "Danilo Krummrich",
|
||||
authors: ["Danilo Krummrich"],
|
||||
description: "Rust Platform driver",
|
||||
license: "GPL v2",
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use kernel::prelude::*;
|
||||
module! {
|
||||
type: RustMinimal,
|
||||
name: "rust_minimal",
|
||||
author: "Rust for Linux Contributors",
|
||||
authors: ["Rust for Linux Contributors"],
|
||||
description: "Rust minimal sample",
|
||||
license: "GPL",
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ const RUST_MISC_DEV_SET_VALUE: u32 = _IOW::<i32>('|' as u32, 0x82);
|
||||
module! {
|
||||
type: RustMiscDeviceModule,
|
||||
name: "rust_misc_device",
|
||||
author: "Lee Jones",
|
||||
authors: ["Lee Jones"],
|
||||
description: "Rust misc device sample",
|
||||
license: "GPL",
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use kernel::prelude::*;
|
||||
module! {
|
||||
type: RustPrint,
|
||||
name: "rust_print",
|
||||
author: "Rust for Linux Contributors",
|
||||
authors: ["Rust for Linux Contributors"],
|
||||
description: "Rust printing macros sample",
|
||||
license: "GPL",
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE
|
||||
# Compile Rust sources (.rs)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons
|
||||
rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,raw_ref_op
|
||||
|
||||
# `--out-dir` is required to avoid temporaries being created by `rustc` in the
|
||||
# current working directory, which may be not accessible in the out-of-tree
|
||||
@ -237,7 +237,7 @@ rust_common_cmd = \
|
||||
-Zallow-features=$(rust_allowed_features) \
|
||||
-Zcrate-attr=no_std \
|
||||
-Zcrate-attr='feature($(rust_allowed_features))' \
|
||||
-Zunstable-options --extern kernel \
|
||||
-Zunstable-options --extern pin_init --extern kernel \
|
||||
--crate-type rlib -L $(objtree)/rust/ \
|
||||
--crate-name $(basename $(notdir $@)) \
|
||||
--sysroot=/dev/null \
|
||||
|
@ -97,6 +97,21 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
|
||||
["core", "compiler_builtins"],
|
||||
)
|
||||
|
||||
append_crate(
|
||||
"pin_init_internal",
|
||||
srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs",
|
||||
[],
|
||||
cfg=["kernel"],
|
||||
is_proc_macro=True,
|
||||
)
|
||||
|
||||
append_crate(
|
||||
"pin_init",
|
||||
srctree / "rust" / "pin-init" / "src" / "lib.rs",
|
||||
["core", "pin_init_internal", "macros"],
|
||||
cfg=["kernel"],
|
||||
)
|
||||
|
||||
def append_crate_with_generated(
|
||||
display_name,
|
||||
deps,
|
||||
@ -118,7 +133,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
|
||||
|
||||
append_crate_with_generated("bindings", ["core"])
|
||||
append_crate_with_generated("uapi", ["core"])
|
||||
append_crate_with_generated("kernel", ["core", "macros", "build_error", "bindings", "uapi"])
|
||||
append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin-init", "bindings", "uapi"])
|
||||
|
||||
def is_root_crate(build_file, target):
|
||||
try:
|
||||
|
@ -87,8 +87,8 @@ fn find_real_path<'a>(srctree: &Path, valid_paths: &'a mut Vec<PathBuf>, file: &
|
||||
|
||||
assert!(
|
||||
valid_paths.len() > 0,
|
||||
"No path candidates found. This is likely a bug in the build system, or some files went \
|
||||
away while compiling."
|
||||
"No path candidates found for `{file}`. This is likely a bug in the build system, or some \
|
||||
files went away while compiling."
|
||||
);
|
||||
|
||||
if valid_paths.len() > 1 {
|
||||
@ -97,8 +97,8 @@ fn find_real_path<'a>(srctree: &Path, valid_paths: &'a mut Vec<PathBuf>, file: &
|
||||
eprintln!(" {path:?}");
|
||||
}
|
||||
panic!(
|
||||
"Several path candidates found, please resolve the ambiguity by renaming a file or \
|
||||
folder."
|
||||
"Several path candidates found for `{file}`, please resolve the ambiguity by renaming \
|
||||
a file or folder."
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user