mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
linux-kselftest-kunit-6.6-rc1
This kunit update for Linux 6.6.rc1 consists of: -- Adds support for running Rust documentation tests as KUnit tests -- Makes init, str, sync, types doctests compilable/testable -- Adds support for attributes API which include speed, modules attributes, ability to filter and report attributes. -- Adds support for marking tests slow using attributes API. -- Adds attributes API documentation -- Fixes to wild-memory-access bug in kunit_filter_suites() and a possible memory leak in kunit_filter_suites() -- Adds support for counting number of test suites in a module, list action to kunit test modules, and test filtering on module tests. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmTsxL8ACgkQCwJExA0N Qxwt6BAA5FgF7nUeGRZCnot4MQCNGRThxsns2k3CKjM1Iokp8tstTDoNHXzk2veS WlRYOHFQqQOVTVRP+laXyjjMMHnlnhFxqbv93UKsen4JIUJDLFLq9x+0i+0bZh97 N1rE5cKUnqjAOL6MIJuomW9IzEIrbMcqdljm6SOCZp90NLvq1+I4pDGLgx2bxcow Y/7dkx+dnlEsoACZ19CL1L2TaR21GpKdpOudpHNCShsbE0aOAlyHAVcmH64FTqCy Z1LtrA0odS71q0yxDVCk5X3cIkeVfGBMz6aMZBRzS9k5jU4H1EN1eG1rGdGErIe5 YduwX3KMikYJB2stT64T1vgldIpT/emxqkBigmxQ37g3Flgopz4bI1snMBry+nKb ViD/WQNjsf2iL8MooCgYBzH7yjmX6lXXQTZXROogBj4lP2/0gHiQVZyXZEAjtoO3 uNzUbfHQGnvtTphBHV4nNGaO+7kU9Y/oX8TYFcSYJQzcH5UVx16uBwevZjT1bii/ q89bRAQLnJpzkR93SGpnmsRgoDcYJSYsEA1o/f9Eqq8j3guOS2idpJvkheXq8+A2 MqTSOCJHENKZ3v0UGKlvZUPStaMaqN58z/VjlWug5EaB83LLfPcXJrGjz/EHk967 hYDHcwPoamTegr1zlg3ckOLiWEhga2tv6aHPkshkcFphpnhRU/c= =Nsb8 -----END PGP SIGNATURE----- Merge tag 'linux-kselftest-kunit-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest Pull kunit updates from Shuah Khan: - add support for running Rust documentation tests as KUnit tests - make init, str, sync, types doctests compilable/testable - add support for attributes API which include speed, modules attributes, ability to filter and report attributes - add support for marking tests slow using attributes API - add attributes API documentation - fix a wild-memory-access bug in kunit_filter_suites() and a possible memory leak in kunit_filter_suites() - add support for counting number of test suites in a module, list action to kunit test modules, and test filtering on module tests * tag 'linux-kselftest-kunit-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (25 commits) kunit: fix struct kunit_attr header kunit: replace KUNIT_TRIGGER_STATIC_STUB maro with KUNIT_STATIC_STUB_REDIRECT kunit: Allow kunit test modules to use test filtering kunit: Make 'list' action available to kunit test modules kunit: Report the count of test suites in a module kunit: fix uninitialized variables bug in attributes filtering kunit: fix possible memory leak in kunit_filter_suites() kunit: fix wild-memory-access bug in kunit_filter_suites() kunit: Add documentation of KUnit test attributes kunit: add tests for filtering attributes kunit: time: Mark test as slow using test attributes kunit: memcpy: Mark tests as slow using test attributes kunit: tool: Add command line interface to filter and report attributes kunit: Add ability to filter attributes kunit: Add module attribute kunit: Add speed attribute kunit: Add test attributes API structure MAINTAINERS: add Rust KUnit files to the KUnit entry rust: support running Rust documentation tests as KUnit ones rust: types: make doctests compilable/testable ...
This commit is contained in:
commit
815c24a085
38 changed files with 1808 additions and 151 deletions
2
rust/.gitignore
vendored
2
rust/.gitignore
vendored
|
@ -2,6 +2,8 @@
|
|||
|
||||
bindings_generated.rs
|
||||
bindings_helpers_generated.rs
|
||||
doctests_kernel_generated.rs
|
||||
doctests_kernel_generated_kunit.c
|
||||
uapi_generated.rs
|
||||
exports_*_generated.h
|
||||
doc/
|
||||
|
|
|
@ -27,6 +27,12 @@ endif
|
|||
|
||||
obj-$(CONFIG_RUST) += exports.o
|
||||
|
||||
always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs
|
||||
always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
|
||||
|
||||
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
|
||||
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
|
||||
|
||||
# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
|
||||
ifdef CONFIG_RUST
|
||||
|
||||
|
@ -39,9 +45,11 @@ ifeq ($(quiet),silent_)
|
|||
cargo_quiet=-q
|
||||
rust_test_quiet=-q
|
||||
rustdoc_test_quiet=--test-args -q
|
||||
rustdoc_test_kernel_quiet=>/dev/null
|
||||
else ifeq ($(quiet),quiet_)
|
||||
rust_test_quiet=-q
|
||||
rustdoc_test_quiet=--test-args -q
|
||||
rustdoc_test_kernel_quiet=>/dev/null
|
||||
else
|
||||
cargo_quiet=--verbose
|
||||
endif
|
||||
|
@ -157,6 +165,27 @@ quiet_cmd_rustdoc_test = RUSTDOC T $<
|
|||
-L$(objtree)/$(obj)/test --output $(objtree)/$(obj)/doc \
|
||||
--crate-name $(subst rusttest-,,$@) $<
|
||||
|
||||
quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
|
||||
cmd_rustdoc_test_kernel = \
|
||||
rm -rf $(objtree)/$(obj)/test/doctests/kernel; \
|
||||
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
|
||||
OBJTREE=$(abspath $(objtree)) \
|
||||
$(RUSTDOC) --test $(rust_flags) \
|
||||
@$(objtree)/include/generated/rustc_cfg \
|
||||
-L$(objtree)/$(obj) --extern alloc --extern kernel \
|
||||
--extern build_error --extern macros \
|
||||
--extern bindings --extern uapi \
|
||||
--no-run --crate-name kernel -Zunstable-options \
|
||||
--test-builder $(objtree)/scripts/rustdoc_test_builder \
|
||||
$< $(rustdoc_test_kernel_quiet); \
|
||||
$(objtree)/scripts/rustdoc_test_gen
|
||||
|
||||
%/doctests_kernel_generated.rs %/doctests_kernel_generated_kunit.c: \
|
||||
$(src)/kernel/lib.rs $(obj)/kernel.o \
|
||||
$(objtree)/scripts/rustdoc_test_builder \
|
||||
$(objtree)/scripts/rustdoc_test_gen FORCE
|
||||
$(call if_changed,rustdoc_test_kernel)
|
||||
|
||||
# We cannot use `-Zpanic-abort-tests` because some tests are dynamic,
|
||||
# so for the moment we skip `-Cpanic=abort`.
|
||||
quiet_cmd_rustc_test = RUSTC T $<
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Sorted alphabetically.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/errname.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/refcount.h>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* accidentally exposed.
|
||||
*/
|
||||
|
||||
#include <kunit/test-bug.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/err.h>
|
||||
|
@ -135,6 +136,12 @@ void rust_helper_put_task_struct(struct task_struct *t)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rust_helper_put_task_struct);
|
||||
|
||||
struct kunit *rust_helper_kunit_get_current_test(void)
|
||||
{
|
||||
return kunit_get_current_test();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rust_helper_kunit_get_current_test);
|
||||
|
||||
/*
|
||||
* We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type
|
||||
* as the Rust `usize` type, so we can use it in contexts where Rust
|
||||
|
|
|
@ -120,14 +120,24 @@
|
|||
//! `slot` gets called.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use kernel::{prelude::*, init};
|
||||
//! # #![allow(unreachable_pub, clippy::disallowed_names)]
|
||||
//! use kernel::{prelude::*, init, types::Opaque};
|
||||
//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin};
|
||||
//! # mod bindings {
|
||||
//! # #![allow(non_camel_case_types)]
|
||||
//! # pub struct foo;
|
||||
//! # pub unsafe fn init_foo(_ptr: *mut foo) {}
|
||||
//! # pub unsafe fn destroy_foo(_ptr: *mut foo) {}
|
||||
//! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 }
|
||||
//! # }
|
||||
//! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround.
|
||||
//! # trait FromErrno {
|
||||
//! # fn from_errno(errno: core::ffi::c_int) -> Error {
|
||||
//! # // Dummy error that can be constructed outside the `kernel` crate.
|
||||
//! # Error::from(core::fmt::Error)
|
||||
//! # }
|
||||
//! # }
|
||||
//! # impl FromErrno for Error {}
|
||||
//! /// # Invariants
|
||||
//! ///
|
||||
//! /// `foo` is always initialized
|
||||
|
@ -158,7 +168,7 @@
|
|||
//! if err != 0 {
|
||||
//! // Enabling has failed, first clean up the foo and then return the error.
|
||||
//! bindings::destroy_foo(Opaque::raw_get(foo));
|
||||
//! return Err(Error::from_kernel_errno(err));
|
||||
//! return Err(Error::from_errno(err));
|
||||
//! }
|
||||
//!
|
||||
//! // All fields of `RawFoo` have been initialized, since `_p` is a ZST.
|
||||
|
@ -226,8 +236,7 @@ pub mod macros;
|
|||
///
|
||||
/// ```rust
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # use kernel::{init, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex};
|
||||
/// # use macros::pin_data;
|
||||
/// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex};
|
||||
/// # use core::pin::Pin;
|
||||
/// #[pin_data]
|
||||
/// struct Foo {
|
||||
|
@ -277,7 +286,7 @@ macro_rules! stack_pin_init {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
|
||||
/// # use macros::pin_data;
|
||||
|
@ -303,7 +312,7 @@ macro_rules! stack_pin_init {
|
|||
/// pr_info!("a: {}", &*foo.a.lock());
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
|
||||
/// # use macros::pin_data;
|
||||
|
@ -513,8 +522,7 @@ macro_rules! stack_try_pin_init {
|
|||
/// For instance:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use kernel::pin_init;
|
||||
/// # use macros::pin_data;
|
||||
/// # use kernel::{macros::pin_data, pin_init};
|
||||
/// # use core::{ptr::addr_of_mut, marker::PhantomPinned};
|
||||
/// #[pin_data]
|
||||
/// struct Buf {
|
||||
|
@ -841,7 +849,7 @@ macro_rules! init {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use kernel::{init::PinInit, error::Error, InPlaceInit};
|
||||
/// use kernel::{init::{PinInit, zeroed}, error::Error};
|
||||
/// struct BigBuf {
|
||||
/// big: Box<[u8; 1024 * 1024 * 1024]>,
|
||||
/// small: [u8; 1024 * 1024],
|
||||
|
|
163
rust/kernel/kunit.rs
Normal file
163
rust/kernel/kunit.rs
Normal file
|
@ -0,0 +1,163 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! KUnit-based macros for Rust unit tests.
|
||||
//!
|
||||
//! C header: [`include/kunit/test.h`](../../../../../include/kunit/test.h)
|
||||
//!
|
||||
//! Reference: <https://docs.kernel.org/dev-tools/kunit/index.html>
|
||||
|
||||
use core::{ffi::c_void, fmt};
|
||||
|
||||
/// Prints a KUnit error-level message.
|
||||
///
|
||||
/// Public but hidden since it should only be used from KUnit generated code.
|
||||
#[doc(hidden)]
|
||||
pub fn err(args: fmt::Arguments<'_>) {
|
||||
// SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
|
||||
// are passing.
|
||||
#[cfg(CONFIG_PRINTK)]
|
||||
unsafe {
|
||||
bindings::_printk(
|
||||
b"\x013%pA\0".as_ptr() as _,
|
||||
&args as *const _ as *const c_void,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a KUnit info-level message.
|
||||
///
|
||||
/// Public but hidden since it should only be used from KUnit generated code.
|
||||
#[doc(hidden)]
|
||||
pub fn info(args: fmt::Arguments<'_>) {
|
||||
// SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
|
||||
// are passing.
|
||||
#[cfg(CONFIG_PRINTK)]
|
||||
unsafe {
|
||||
bindings::_printk(
|
||||
b"\x016%pA\0".as_ptr() as _,
|
||||
&args as *const _ as *const c_void,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts that a boolean expression is `true` at runtime.
|
||||
///
|
||||
/// Public but hidden since it should only be used from generated tests.
|
||||
///
|
||||
/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
|
||||
/// facilities. See [`assert!`] for more details.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! kunit_assert {
|
||||
($name:literal, $file:literal, $diff:expr, $condition:expr $(,)?) => {
|
||||
'out: {
|
||||
// Do nothing if the condition is `true`.
|
||||
if $condition {
|
||||
break 'out;
|
||||
}
|
||||
|
||||
static FILE: &'static $crate::str::CStr = $crate::c_str!($file);
|
||||
static LINE: i32 = core::line!() as i32 - $diff;
|
||||
static CONDITION: &'static $crate::str::CStr = $crate::c_str!(stringify!($condition));
|
||||
|
||||
// SAFETY: FFI call without safety requirements.
|
||||
let kunit_test = unsafe { $crate::bindings::kunit_get_current_test() };
|
||||
if kunit_test.is_null() {
|
||||
// The assertion failed but this task is not running a KUnit test, so we cannot call
|
||||
// KUnit, but at least print an error to the kernel log. This may happen if this
|
||||
// macro is called from an spawned thread in a test (see
|
||||
// `scripts/rustdoc_test_gen.rs`) or if some non-test code calls this macro by
|
||||
// mistake (it is hidden to prevent that).
|
||||
//
|
||||
// This mimics KUnit's failed assertion format.
|
||||
$crate::kunit::err(format_args!(
|
||||
" # {}: ASSERTION FAILED at {FILE}:{LINE}\n",
|
||||
$name
|
||||
));
|
||||
$crate::kunit::err(format_args!(
|
||||
" Expected {CONDITION} to be true, but is false\n"
|
||||
));
|
||||
$crate::kunit::err(format_args!(
|
||||
" Failure not reported to KUnit since this is a non-KUnit task\n"
|
||||
));
|
||||
break 'out;
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Location($crate::bindings::kunit_loc);
|
||||
|
||||
#[repr(transparent)]
|
||||
struct UnaryAssert($crate::bindings::kunit_unary_assert);
|
||||
|
||||
// SAFETY: There is only a static instance and in that one the pointer field points to
|
||||
// an immutable C string.
|
||||
unsafe impl Sync for Location {}
|
||||
|
||||
// SAFETY: There is only a static instance and in that one the pointer field points to
|
||||
// an immutable C string.
|
||||
unsafe impl Sync for UnaryAssert {}
|
||||
|
||||
static LOCATION: Location = Location($crate::bindings::kunit_loc {
|
||||
file: FILE.as_char_ptr(),
|
||||
line: LINE,
|
||||
});
|
||||
static ASSERTION: UnaryAssert = UnaryAssert($crate::bindings::kunit_unary_assert {
|
||||
assert: $crate::bindings::kunit_assert {},
|
||||
condition: CONDITION.as_char_ptr(),
|
||||
expected_true: true,
|
||||
});
|
||||
|
||||
// SAFETY:
|
||||
// - FFI call.
|
||||
// - The `kunit_test` pointer is valid because we got it from
|
||||
// `kunit_get_current_test()` and it was not null. This means we are in a KUnit
|
||||
// test, and that the pointer can be passed to KUnit functions and assertions.
|
||||
// - The string pointers (`file` and `condition` above) point to null-terminated
|
||||
// strings since they are `CStr`s.
|
||||
// - The function pointer (`format`) points to the proper function.
|
||||
// - The pointers passed will remain valid since they point to `static`s.
|
||||
// - The format string is allowed to be null.
|
||||
// - There are, however, problems with this: first of all, this will end up stopping
|
||||
// the thread, without running destructors. While that is problematic in itself,
|
||||
// it is considered UB to have what is effectively a forced foreign unwind
|
||||
// with `extern "C"` ABI. One could observe the stack that is now gone from
|
||||
// another thread. We should avoid pinning stack variables to prevent library UB,
|
||||
// too. For the moment, given that test failures are reported immediately before the
|
||||
// next test runs, that test failures should be fixed and that KUnit is explicitly
|
||||
// documented as not suitable for production environments, we feel it is reasonable.
|
||||
unsafe {
|
||||
$crate::bindings::__kunit_do_failed_assertion(
|
||||
kunit_test,
|
||||
core::ptr::addr_of!(LOCATION.0),
|
||||
$crate::bindings::kunit_assert_type_KUNIT_ASSERTION,
|
||||
core::ptr::addr_of!(ASSERTION.0.assert),
|
||||
Some($crate::bindings::kunit_unary_assert_format),
|
||||
core::ptr::null(),
|
||||
);
|
||||
}
|
||||
|
||||
// SAFETY: FFI call; the `test` pointer is valid because this hidden macro should only
|
||||
// be called by the generated documentation tests which forward the test pointer given
|
||||
// by KUnit.
|
||||
unsafe {
|
||||
$crate::bindings::__kunit_abort(kunit_test);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
|
||||
///
|
||||
/// Public but hidden since it should only be used from generated tests.
|
||||
///
|
||||
/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
|
||||
/// facilities. See [`assert!`] for more details.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! kunit_assert_eq {
|
||||
($name:literal, $file:literal, $diff:expr, $left:expr, $right:expr $(,)?) => {{
|
||||
// For the moment, we just forward to the expression assert because, for binary asserts,
|
||||
// KUnit supports only a few types (e.g. integers).
|
||||
$crate::kunit_assert!($name, $file, $diff, $left == $right);
|
||||
}};
|
||||
}
|
|
@ -34,6 +34,8 @@ mod build_assert;
|
|||
pub mod error;
|
||||
pub mod init;
|
||||
pub mod ioctl;
|
||||
#[cfg(CONFIG_KUNIT)]
|
||||
pub mod kunit;
|
||||
pub mod prelude;
|
||||
pub mod print;
|
||||
mod static_assert;
|
||||
|
|
|
@ -213,6 +213,7 @@ impl fmt::Display for CStr {
|
|||
///
|
||||
/// ```
|
||||
/// # use kernel::c_str;
|
||||
/// # use kernel::fmt;
|
||||
/// # use kernel::str::CStr;
|
||||
/// # use kernel::str::CString;
|
||||
/// let penguin = c_str!("🐧");
|
||||
|
@ -241,6 +242,7 @@ impl fmt::Debug for CStr {
|
|||
///
|
||||
/// ```
|
||||
/// # use kernel::c_str;
|
||||
/// # use kernel::fmt;
|
||||
/// # use kernel::str::CStr;
|
||||
/// # use kernel::str::CString;
|
||||
/// let penguin = c_str!("🐧");
|
||||
|
@ -529,7 +531,7 @@ impl fmt::Write for Formatter {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::str::CString;
|
||||
/// use kernel::{str::CString, fmt};
|
||||
///
|
||||
/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap();
|
||||
/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
|
||||
|
|
|
@ -73,6 +73,7 @@ mod std_vendor;
|
|||
/// assert_eq!(cloned.b, 20);
|
||||
///
|
||||
/// // The refcount drops to zero when `cloned` goes out of scope, and the memory is freed.
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// Using `Arc<T>` as the type of `self`:
|
||||
|
@ -98,6 +99,7 @@ mod std_vendor;
|
|||
/// let obj = Arc::try_new(Example { a: 10, b: 20 })?;
|
||||
/// obj.use_reference();
|
||||
/// obj.take_over();
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// Coercion from `Arc<Example>` to `Arc<dyn MyTrait>`:
|
||||
|
@ -121,6 +123,7 @@ mod std_vendor;
|
|||
///
|
||||
/// // `coerced` has type `Arc<dyn MyTrait>`.
|
||||
/// let coerced: Arc<dyn MyTrait> = obj;
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
pub struct Arc<T: ?Sized> {
|
||||
ptr: NonNull<ArcInner<T>>,
|
||||
|
@ -336,7 +339,7 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use crate::sync::{Arc, ArcBorrow};
|
||||
/// use kernel::sync::{Arc, ArcBorrow};
|
||||
///
|
||||
/// struct Example;
|
||||
///
|
||||
|
@ -349,12 +352,13 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
|
|||
///
|
||||
/// // Assert that both `obj` and `cloned` point to the same underlying object.
|
||||
/// assert!(core::ptr::eq(&*obj, &*cloned));
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// Using `ArcBorrow<T>` as the type of `self`:
|
||||
///
|
||||
/// ```
|
||||
/// use crate::sync::{Arc, ArcBorrow};
|
||||
/// use kernel::sync::{Arc, ArcBorrow};
|
||||
///
|
||||
/// struct Example {
|
||||
/// a: u32,
|
||||
|
@ -369,6 +373,7 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
|
|||
///
|
||||
/// let obj = Arc::try_new(Example { a: 10, b: 20 })?;
|
||||
/// obj.as_arc_borrow().use_reference();
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
pub struct ArcBorrow<'a, T: ?Sized + 'a> {
|
||||
inner: NonNull<ArcInner<T>>,
|
||||
|
|
|
@ -63,6 +63,7 @@ macro_rules! new_mutex {
|
|||
/// assert_eq!(e.c, 10);
|
||||
/// assert_eq!(e.d.lock().a, 20);
|
||||
/// assert_eq!(e.d.lock().b, 30);
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// The following example shows how to use interior mutability to modify the contents of a struct
|
||||
|
|
|
@ -61,6 +61,7 @@ macro_rules! new_spinlock {
|
|||
/// assert_eq!(e.c, 10);
|
||||
/// assert_eq!(e.d.lock().a, 20);
|
||||
/// assert_eq!(e.d.lock().b, 30);
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// The following example shows how to use interior mutability to modify the contents of a struct
|
||||
|
|
|
@ -91,7 +91,7 @@ impl ForeignOwnable for () {
|
|||
/// In the example below, we have multiple exit paths and we want to log regardless of which one is
|
||||
/// taken:
|
||||
/// ```
|
||||
/// # use kernel::ScopeGuard;
|
||||
/// # use kernel::types::ScopeGuard;
|
||||
/// fn example1(arg: bool) {
|
||||
/// let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
|
||||
///
|
||||
|
@ -109,7 +109,7 @@ impl ForeignOwnable for () {
|
|||
/// In the example below, we want to log the same message on all early exits but a different one on
|
||||
/// the main exit path:
|
||||
/// ```
|
||||
/// # use kernel::ScopeGuard;
|
||||
/// # use kernel::types::ScopeGuard;
|
||||
/// fn example2(arg: bool) {
|
||||
/// let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
|
||||
///
|
||||
|
@ -130,7 +130,7 @@ impl ForeignOwnable for () {
|
|||
/// In the example below, we need a mutable object (the vector) to be accessible within the log
|
||||
/// function, so we wrap it in the [`ScopeGuard`]:
|
||||
/// ```
|
||||
/// # use kernel::ScopeGuard;
|
||||
/// # use kernel::types::ScopeGuard;
|
||||
/// fn example3(arg: bool) -> Result {
|
||||
/// let mut vec =
|
||||
/// ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue