Skip to content

Commit

Permalink
Merge pull request torvalds#158 from wedsonaf/container_of
Browse files Browse the repository at this point in the history
Add `container_of` and `offset_of` macros.
  • Loading branch information
ojeda authored Apr 1, 2021
2 parents a553727 + 94d4038 commit de33f8a
Showing 1 changed file with 65 additions and 0 deletions.
65 changes: 65 additions & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,70 @@ fn panic(_info: &PanicInfo) -> ! {
}
}

/// Calculates the offset of a field from the beginning of the struct it belongs to.
///
/// # Example
///
///```
/// struct Test {
/// a: u64,
/// b: u32,
/// }
///
/// fn test() {
/// // This prints `8`.
/// println!("{}", offset_of!(Test, b));
/// }
///```
#[macro_export]
macro_rules! offset_of {
($type:ty, $($f:tt)*) => {{
let tmp = core::mem::MaybeUninit::<$type>::uninit();
let outer = tmp.as_ptr();
// To avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
// we don't actually read from `outer` (which would be UB) nor create an intermediate
// reference.
let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
// To avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// SAFETY: The two pointers are within the same allocation block.
unsafe { inner.offset_from(outer as *const u8) }
}}
}

/// Produces a pointer to an object from a pointer to one of its fields.
///
/// # Safety
///
/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
/// as opposed to a pointer to another object of the same type.
///
/// # Example
///
///```
/// struct Test {
/// a: u64,
/// b: u32,
/// }
///
/// fn test() {
/// let test = Test{a: 10, b: 20};
/// let b_ptr = &test.b;
/// let test_alias = unsafe { container_of!(b_ptr, Test, b) };
/// // This prints `true`.
/// println!("{}", core::ptr::eq(&test, test_alias));
/// }
///```
///
#[macro_export]
macro_rules! container_of {
($ptr:expr, $type:ty, $($f:tt)*) => {{
let offset = $crate::offset_of!($type, $($f)*);
($ptr as *const _ as *const u8).offset(-offset) as *const $type
}}
}

#[global_allocator]
static ALLOCATOR: allocator::KernelAllocator = allocator::KernelAllocator;

0 comments on commit de33f8a

Please sign in to comment.