Skip to content

Commit 362357f

Browse files
b92paulChromeos LUCI
authored and
Chromeos LUCI
committed
libcras: Implement UnalignedRef for unaligned memory access
Add UnaglinedRef struct, which is similar to the VolatileRef struct but it uses {read, write}_unaligned instead. BUG=b:239850356 BUG=b:284938484 TEST=cargo test Change-Id: Icc0479b14ff751f146b6096c16f3bb2f62031700 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/adhd/+/4574167 Tested-by: Chih-Yang Hsia <[email protected]> Reviewed-by: Li-Yu Yu <[email protected]> Commit-Queue: Chih-Yang Hsia <[email protected]> Tested-by: ChromeOS Audio Quick Verifier <[email protected]> Tested-by: [email protected] <[email protected]>
1 parent 063899b commit 362357f

File tree

3 files changed

+101
-25
lines changed

3 files changed

+101
-25
lines changed

cras/client/libcras/src/cras_shm.rs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ use cras_sys::gen::{
2020
use cras_sys::{
2121
AudioDebugInfo, AudioDevDebugInfo, AudioStreamDebugInfo, CrasIodevInfo, CrasIonodeInfo,
2222
};
23-
use data_model::{VolatileRef, VolatileSlice};
23+
use data_model::VolatileSlice;
2424
use libchromeos::sys::warn;
2525

26+
use crate::unaligned_memory::UnalignedRef;
27+
2628
/// A structure wrapping a fd which contains a shared `cras_audio_shm_header`.
2729
/// * `shm_fd` - A shared memory fd contains a `cras_audio_shm_header`
2830
pub struct CrasAudioShmHeaderFd {
@@ -52,46 +54,46 @@ impl CrasAudioShmHeaderFd {
5254

5355
/// A wrapper for the raw structure `cras_audio_shm_header` with
5456
/// size information for the separate audio samples shm area and several
55-
/// `VolatileRef` to sub fields for safe access to the header.
57+
/// `UnalignedRef` to sub fields for safe access to the header.
5658
pub struct CrasAudioHeader<'a> {
5759
addr: *mut libc::c_void,
5860
/// Size of the buffer for samples in CrasAudioBuffer
5961
samples_len: usize,
60-
used_size: VolatileRef<'a, u32>,
61-
frame_size: VolatileRef<'a, u32>,
62-
read_buf_idx: VolatileRef<'a, u32>,
63-
write_buf_idx: VolatileRef<'a, u32>,
64-
read_offset: [VolatileRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
65-
write_offset: [VolatileRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
66-
buffer_offset: [VolatileRef<'a, u64>; CRAS_NUM_SHM_BUFFERS as usize],
67-
ts_sec: VolatileRef<'a, i64>,
68-
ts_nsec: VolatileRef<'a, i64>,
62+
used_size: UnalignedRef<'a, u32>,
63+
frame_size: UnalignedRef<'a, u32>,
64+
read_buf_idx: UnalignedRef<'a, u32>,
65+
write_buf_idx: UnalignedRef<'a, u32>,
66+
read_offset: [UnalignedRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
67+
write_offset: [UnalignedRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
68+
buffer_offset: [UnalignedRef<'a, u64>; CRAS_NUM_SHM_BUFFERS as usize],
69+
ts_sec: UnalignedRef<'a, i64>,
70+
ts_nsec: UnalignedRef<'a, i64>,
6971
}
7072

7173
// It is safe to send audio buffers between threads as this struct has exclusive ownership of the
7274
// pointers contained in it.
7375
unsafe impl<'a> Send for CrasAudioHeader<'a> {}
7476

75-
/// An unsafe macro for getting `VolatileRef` for a field from a given NonNull pointer.
77+
/// An unsafe macro for getting `UnalignedRef` for a field from a given NonNull pointer.
7678
/// It Supports
7779
/// - Nested sub-field
7880
/// - Element of an array field
7981
///
8082
/// To use this macro safely, we need to
8183
/// - Make sure the pointer address is readable and writable for its structure.
82-
/// - Make sure all `VolatileRef`s generated from this macro have exclusive ownership for the same
84+
/// - Make sure all `UnalignedRef`s generated from this macro have exclusive ownership for the same
8385
/// pointer.
8486
///
85-
/// TODO(b/239850356): Use self-implemented `VolatileRef` implemetation
87+
/// TODO(b/239850356): Use self-implemented `UnalignedRef` implemetation
8688
/// with [`ptr::read_unaligned`] and [`ptr::write_unaligned`].
8789
#[macro_export]
8890
macro_rules! vref_from_addr {
8991
($addr:ident, $($field:ident).*) => {
90-
VolatileRef::new(ptr::addr_of_mut!($addr.as_mut().$($field).*))
92+
UnalignedRef::new(ptr::addr_of_mut!($addr.as_mut().$($field).*))
9193
};
9294

9395
($addr:ident, $field:ident[$idx:tt]) => {
94-
VolatileRef::new(ptr::addr_of_mut!($addr.as_mut().$field[$idx]))
96+
UnalignedRef::new(ptr::addr_of_mut!($addr.as_mut().$field[$idx]))
9597
};
9698
}
9799

@@ -553,20 +555,20 @@ macro_rules! vslice_from_addr {
553555
#[derive(Debug)]
554556
pub struct CrasServerState<'a> {
555557
addr: *mut libc::c_void,
556-
volume: VolatileRef<'a, u32>,
557-
mute: VolatileRef<'a, i32>,
558-
num_output_devs: VolatileRef<'a, u32>,
558+
volume: UnalignedRef<'a, u32>,
559+
mute: UnalignedRef<'a, i32>,
560+
num_output_devs: UnalignedRef<'a, u32>,
559561
output_devs: VolatileSlice<'a>,
560-
num_input_devs: VolatileRef<'a, u32>,
562+
num_input_devs: UnalignedRef<'a, u32>,
561563
input_devs: VolatileSlice<'a>,
562-
num_output_nodes: VolatileRef<'a, u32>,
563-
num_input_nodes: VolatileRef<'a, u32>,
564+
num_output_nodes: UnalignedRef<'a, u32>,
565+
num_input_nodes: UnalignedRef<'a, u32>,
564566
output_nodes: VolatileSlice<'a>,
565567
input_nodes: VolatileSlice<'a>,
566-
update_count: VolatileRef<'a, u32>,
567-
debug_info_num_devs: VolatileRef<'a, u32>,
568+
update_count: UnalignedRef<'a, u32>,
569+
debug_info_num_devs: UnalignedRef<'a, u32>,
568570
debug_info_devs: VolatileSlice<'a>,
569-
debug_info_num_streams: VolatileRef<'a, u32>,
571+
debug_info_num_streams: UnalignedRef<'a, u32>,
570572
debug_info_streams: VolatileSlice<'a>,
571573
}
572574

cras/client/libcras/src/libcras.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ mod cras_stream;
161161
use crate::cras_stream::{CrasCaptureData, CrasPlaybackData, CrasStream, CrasStreamData};
162162
mod cras_client_message;
163163
use crate::cras_client_message::*;
164+
mod unaligned_memory;
164165

165166
#[derive(Debug)]
166167
pub enum Error {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2023 The ChromiumOS Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
use std::marker::PhantomData;
6+
7+
use data_model::DataInit;
8+
9+
/// A memory location that supports unaligned access of a `T`.
10+
#[derive(Debug)]
11+
pub struct UnalignedRef<'a, T: DataInit>
12+
where
13+
T: 'a,
14+
{
15+
addr: *mut T,
16+
phantom: PhantomData<&'a T>,
17+
}
18+
19+
impl<'a, T: DataInit> UnalignedRef<'a, T> {
20+
/// Creates a reference to raw unaligned memory that must support unaligned access of `T`
21+
/// sized chunks.
22+
///
23+
/// # Safety
24+
/// To use this safely, the caller must guarantee that the memory at `addr` is big enough for a
25+
/// `T` and is available for the duration of the lifetime of the new `UnalignedRef`. The caller
26+
/// must also guarantee that all other users of the given chunk of memory are using unaligned
27+
/// accesses.
28+
///
29+
/// # Caveat
30+
/// Caller should make sure the lifetime of [`UnalignedRef`] and `addr` are matched.
31+
pub unsafe fn new(addr: *mut T) -> UnalignedRef<'a, T> {
32+
UnalignedRef {
33+
addr,
34+
phantom: PhantomData,
35+
}
36+
}
37+
38+
/// Does a unaligned write of the value `v` to the address of this ref.
39+
#[inline(always)]
40+
pub fn store(&self, v: T) {
41+
// Safety: Assume we have a valid unaligned address with type T
42+
unsafe { self.addr.write_unaligned(v) };
43+
}
44+
45+
/// Does a unaligned read of the value at the address of this ref.
46+
#[inline(always)]
47+
pub fn load(&self) -> T {
48+
// Safety: Assume we have a valid unaligned address with type T
49+
unsafe { self.addr.read_unaligned() }
50+
}
51+
}
52+
53+
#[cfg(test)]
54+
mod tests {
55+
use super::*;
56+
use std::ptr;
57+
58+
#[repr(packed)]
59+
#[derive(Copy, Clone, Debug, PartialEq)]
60+
struct Packed {
61+
f1: u8,
62+
f2: u16,
63+
}
64+
65+
#[test]
66+
fn unaligned_memory_test() {
67+
let mut p = Packed { f1: 1, f2: 2 };
68+
let unaligned_ref = unsafe { UnalignedRef::new(ptr::addr_of_mut!(p.f2)) };
69+
assert_eq!(unaligned_ref.load(), 2);
70+
unaligned_ref.store(500);
71+
assert_eq!(p, Packed { f1: 1, f2: 500 });
72+
}
73+
}

0 commit comments

Comments
 (0)