1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 use std::convert::TryFrom;
5 use std::io;
6 use std::mem;
7 use std::os::unix::io::{AsRawFd, RawFd};
8 use std::ptr;
9 use std::ptr::NonNull;
10 use std::slice;
11 use std::sync::atomic::{self, Ordering};
12 use std::thread;
13
14 use cras_sys::gen::{
15 audio_dev_debug_info, audio_stream_debug_info, cras_audio_shm_header, cras_iodev_info,
16 cras_ionode_info, cras_server_state, CRAS_MAX_IODEVS, CRAS_MAX_IONODES, CRAS_NUM_SHM_BUFFERS,
17 CRAS_SERVER_STATE_VERSION, CRAS_SHM_BUFFERS_MASK, MAX_DEBUG_DEVS, MAX_DEBUG_STREAMS,
18 };
19 use cras_sys::{
20 AudioDebugInfo, AudioDevDebugInfo, AudioStreamDebugInfo, CrasIodevInfo, CrasIonodeInfo,
21 };
22 use data_model::{VolatileRef, VolatileSlice};
23 use sys_util::warn;
24
25 /// A structure wrapping a fd which contains a shared `cras_audio_shm_header`.
26 /// * `shm_fd` - A shared memory fd contains a `cras_audio_shm_header`
27 pub struct CrasAudioShmHeaderFd {
28 fd: CrasShmFd,
29 }
30
31 impl CrasAudioShmHeaderFd {
32 /// Creates a `CrasAudioShmHeaderFd` by shared memory fd
33 /// # Arguments
34 /// * `fd` - A shared memory file descriptor, which will be owned by the resulting structure and
35 /// the fd will be closed on drop.
36 ///
37 /// # Returns
38 /// A structure wrapping a `CrasShmFd` with the input fd and `size` which equals to
39 /// the size of `cras_audio_shm_header`.
40 ///
41 /// To use this function safely, we need to make sure
42 /// - The input fd is a valid shared memory fd.
43 /// - The input shared memory fd won't be used by others.
44 /// - The shared memory area in the input fd contains a `cras_audio_shm_header`.
new(fd: libc::c_int) -> Self45 pub unsafe fn new(fd: libc::c_int) -> Self {
46 Self {
47 fd: CrasShmFd::new(fd, mem::size_of::<cras_audio_shm_header>()),
48 }
49 }
50 }
51
52 /// A wrapper for the raw structure `cras_audio_shm_header` with
53 /// size information for the separate audio samples shm area and several
54 /// `VolatileRef` to sub fields for safe access to the header.
55 pub struct CrasAudioHeader<'a> {
56 addr: *mut libc::c_void,
57 /// Size of the buffer for samples in CrasAudioBuffer
58 samples_len: usize,
59 used_size: VolatileRef<'a, u32>,
60 frame_size: VolatileRef<'a, u32>,
61 read_buf_idx: VolatileRef<'a, u32>,
62 write_buf_idx: VolatileRef<'a, u32>,
63 read_offset: [VolatileRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
64 write_offset: [VolatileRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
65 buffer_offset: [VolatileRef<'a, u64>; CRAS_NUM_SHM_BUFFERS as usize],
66 }
67
68 // It is safe to send audio buffers between threads as this struct has exclusive ownership of the
69 // pointers contained in it.
70 unsafe impl<'a> Send for CrasAudioHeader<'a> {}
71
72 /// An unsafe macro for getting `VolatileRef` for a field from a given NonNull pointer.
73 /// It Supports
74 /// - Nested sub-field
75 /// - Element of an array field
76 ///
77 /// To use this macro safely, we need to
78 /// - Make sure the pointer address is readable and writable for its structure.
79 /// - Make sure all `VolatileRef`s generated from this macro have exclusive ownership for the same
80 /// pointer.
81 #[macro_export]
82 macro_rules! vref_from_addr {
83 ($addr:ident, $($field:ident).*) => {
84 VolatileRef::new(&mut $addr.as_mut().$($field).* as *mut _)
85 };
86
87 ($addr:ident, $field:ident[$idx:tt]) => {
88 VolatileRef::new(&mut $addr.as_mut().$field[$idx] as *mut _)
89 };
90 }
91
92 // Generates error when an index is out of range.
index_out_of_range() -> io::Error93 fn index_out_of_range() -> io::Error {
94 io::Error::new(io::ErrorKind::InvalidInput, "Index out of range.")
95 }
96
97 impl<'a> CrasAudioHeader<'a> {
98 // Creates a `CrasAudioHeader` with given `CrasAudioShmHeaderFd` and `samples_len`
new(header_fd: CrasAudioShmHeaderFd, samples_len: usize) -> io::Result<Self>99 fn new(header_fd: CrasAudioShmHeaderFd, samples_len: usize) -> io::Result<Self> {
100 // Safe because the creator of CrasAudioShmHeaderFd already
101 // ensured that header_fd contains a cras_audio_shm_header.
102 let mmap_addr = unsafe {
103 cras_mmap(
104 header_fd.fd.size,
105 libc::PROT_READ | libc::PROT_WRITE,
106 header_fd.fd.as_raw_fd(),
107 )?
108 };
109
110 let mut addr = NonNull::new(mmap_addr as *mut cras_audio_shm_header)
111 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to create header."))?;
112
113 // Safe because we know that mmap_addr (contained in addr) contains a
114 // cras_audio_shm_header, and the mapped area will be exclusively
115 // owned by this struct.
116 unsafe {
117 Ok(CrasAudioHeader {
118 addr: addr.as_ptr() as *mut libc::c_void,
119 samples_len,
120 used_size: vref_from_addr!(addr, config.used_size),
121 frame_size: vref_from_addr!(addr, config.frame_bytes),
122 read_buf_idx: vref_from_addr!(addr, read_buf_idx),
123 write_buf_idx: vref_from_addr!(addr, write_buf_idx),
124 read_offset: [
125 vref_from_addr!(addr, read_offset[0]),
126 vref_from_addr!(addr, read_offset[1]),
127 ],
128 write_offset: [
129 vref_from_addr!(addr, write_offset[0]),
130 vref_from_addr!(addr, write_offset[1]),
131 ],
132 buffer_offset: [
133 vref_from_addr!(addr, buffer_offset[0]),
134 vref_from_addr!(addr, buffer_offset[1]),
135 ],
136 })
137 }
138 }
139
140 /// Calculates the length of a buffer with the given offset. This length will
141 /// be `used_size`, unless the offset is closer than `used_size` to the end
142 /// of samples, in which case the length will be as long as possible.
143 ///
144 /// If that buffer length is invalid (too small to hold a frame of audio data),
145 /// then returns an error.
146 /// The returned buffer length will be rounded down to a multiple of `frame_size`.
buffer_len_from_offset(&self, offset: usize) -> io::Result<usize>147 fn buffer_len_from_offset(&self, offset: usize) -> io::Result<usize> {
148 if offset > self.samples_len {
149 return Err(io::Error::new(
150 io::ErrorKind::InvalidInput,
151 format!(
152 "Buffer offset {} exceeds the length of samples area ({}).",
153 offset, self.samples_len
154 ),
155 ));
156 }
157
158 let used_size = self.get_used_size();
159 let frame_size = self.get_frame_size();
160
161 // We explicitly allow a buffer shorter than used_size, but only
162 // at the end of the samples area.
163 // This is useful if we're playing a file where the number of samples is
164 // not a multiple of used_size (meaning the length of the samples area
165 // won't be either). Then, the last buffer played will be smaller than
166 // used_size.
167 let mut buffer_length = used_size.min(self.samples_len - offset);
168 if buffer_length < frame_size {
169 return Err(io::Error::new(
170 io::ErrorKind::InvalidInput,
171 format!(
172 "Buffer offset {} gives buffer length {} smaller than frame size {}.",
173 offset, buffer_length, frame_size
174 ),
175 ));
176 }
177
178 // Round buffer_length down to a multiple of frame size
179 buffer_length = buffer_length / frame_size * frame_size;
180 Ok(buffer_length)
181 }
182
183 /// Gets the base of the write buffer and the writable length (rounded to `frame_size`).
184 /// Does not take into account the write offset.
185 ///
186 /// # Returns
187 ///
188 /// * (`usize`, `usize`) - write buffer base as an offset from the start of
189 /// the samples area and buffer length in bytes.
get_write_offset_and_len(&self) -> io::Result<(usize, usize)>190 pub fn get_write_offset_and_len(&self) -> io::Result<(usize, usize)> {
191 let idx = self.get_write_buf_idx() as usize;
192 let offset = self.get_buffer_offset(idx)?;
193 let len = self.buffer_len_from_offset(offset)?;
194
195 Ok((offset, len))
196 }
197
198 /// Gets the buffer offset of the read buffer.
199 ///
200 /// # Returns
201 ///
202 /// * `usize` - read offset in bytes
get_read_buffer_offset(&self) -> io::Result<usize>203 pub fn get_read_buffer_offset(&self) -> io::Result<usize> {
204 let idx = self.get_read_buf_idx() as usize;
205 self.get_buffer_offset(idx)
206 }
207
208 /// Gets the offset of a buffer from the start of samples.
209 ///
210 /// # Arguments
211 /// `index` - 0 <= `index` < `CRAS_NUM_SHM_BUFFERS`. The index of the buffer
212 /// for which we want the `buffer_offset`.
213 ///
214 /// # Returns
215 /// * `usize` - buffer offset in bytes
get_buffer_offset(&self, idx: usize) -> io::Result<usize>216 fn get_buffer_offset(&self, idx: usize) -> io::Result<usize> {
217 let buffer_offset = self
218 .buffer_offset
219 .get(idx)
220 .ok_or_else(index_out_of_range)?
221 .load() as usize;
222 self.check_buffer_offset(idx, buffer_offset)?;
223 Ok(buffer_offset)
224 }
225
226 /// Gets the number of bytes per frame from the shared memory structure.
227 ///
228 /// # Returns
229 ///
230 /// * `usize` - Number of bytes per frame
get_frame_size(&self) -> usize231 pub fn get_frame_size(&self) -> usize {
232 self.frame_size.load() as usize
233 }
234
235 /// Gets the max size in bytes of each shared memory buffer within
236 /// the samples area.
237 ///
238 /// # Returns
239 ///
240 /// * `usize` - Value of `used_size` fetched from the shared memory header.
get_used_size(&self) -> usize241 pub fn get_used_size(&self) -> usize {
242 self.used_size.load() as usize
243 }
244
245 /// Gets the index of the current written buffer.
246 ///
247 /// # Returns
248 /// `u32` - the returned index is less than `CRAS_NUM_SHM_BUFFERS`.
get_write_buf_idx(&self) -> u32249 fn get_write_buf_idx(&self) -> u32 {
250 self.write_buf_idx.load() & CRAS_SHM_BUFFERS_MASK
251 }
252
get_read_buf_idx(&self) -> u32253 fn get_read_buf_idx(&self) -> u32 {
254 self.read_buf_idx.load() & CRAS_SHM_BUFFERS_MASK
255 }
256
257 /// Switches the written buffer.
switch_write_buf_idx(&mut self)258 fn switch_write_buf_idx(&mut self) {
259 self.write_buf_idx
260 .store(self.get_write_buf_idx() as u32 ^ 1u32)
261 }
262
263 /// Switches the buffer to read.
switch_read_buf_idx(&mut self)264 fn switch_read_buf_idx(&mut self) {
265 self.read_buf_idx
266 .store(self.get_read_buf_idx() as u32 ^ 1u32)
267 }
268
269 /// Checks if the offset value for setting write_offset or read_offset is
270 /// out of range or not.
271 ///
272 /// # Arguments
273 /// `idx` - The index of the buffer for which we're checking the offset.
274 /// `offset` - 0 <= `offset` <= `used_size` && `buffer_offset[idx]` + `offset` <=
275 /// `samples_len`. Writable or readable size equals to 0 when offset equals
276 /// to `used_size`.
277 ///
278 /// # Errors
279 /// Returns an error if `offset` is out of range or if idx is not a valid
280 /// buffer idx.
check_rw_offset(&self, idx: usize, offset: u32) -> io::Result<()>281 fn check_rw_offset(&self, idx: usize, offset: u32) -> io::Result<()> {
282 let buffer_len = self.buffer_len_from_offset(self.get_buffer_offset(idx)?)?;
283 if offset as usize > buffer_len {
284 return Err(io::Error::new(
285 io::ErrorKind::InvalidInput,
286 format!(
287 "Offset {} is larger than buffer size {}.",
288 offset, buffer_len
289 ),
290 ));
291 }
292
293 Ok(())
294 }
295
296 /// Sets `write_offset[idx]` to the count of written bytes.
297 ///
298 /// # Arguments
299 /// `idx` - 0 <= `idx` < `CRAS_NUM_SHM_BUFFERS`
300 /// `offset` - 0 <= `offset` <= `used_size` && `offset` + `used_size` <=
301 /// `samples_len`. Writable size equals to 0 when offset equals to
302 /// `used_size`.
303 ///
304 /// # Errors
305 /// Returns an error if `offset` is out of range.
set_write_offset(&mut self, idx: usize, offset: u32) -> io::Result<()>306 fn set_write_offset(&mut self, idx: usize, offset: u32) -> io::Result<()> {
307 self.check_rw_offset(idx, offset)?;
308 let write_offset = self.write_offset.get(idx).ok_or_else(index_out_of_range)?;
309 write_offset.store(offset);
310 Ok(())
311 }
312
313 /// Sets `read_offset[idx]` to count of written bytes.
314 ///
315 /// # Arguments
316 /// `idx` - 0 <= `idx` < `CRAS_NUM_SHM_BUFFERS`
317 /// `offset` - 0 <= `offset` <= `used_size` && `offset` + `used_size` <=
318 /// `samples_len`. Readable size equals to 0 when offset equals to
319 /// `used_size`.
320 ///
321 /// # Errors
322 /// Returns error if index out of range.
set_read_offset(&mut self, idx: usize, offset: u32) -> io::Result<()>323 fn set_read_offset(&mut self, idx: usize, offset: u32) -> io::Result<()> {
324 self.check_rw_offset(idx, offset)?;
325 let read_offset = self.read_offset.get(idx).ok_or_else(index_out_of_range)?;
326 read_offset.store(offset);
327 Ok(())
328 }
329
330 /// Check that `offset` is a valid buffer offset for the buffer at `idx`
331 /// An offset is not valid if it is
332 /// * outside of the samples area
333 /// * overlaps some other buffer `[other_offset, other_offset + used_size)`
334 /// * is close enough to the end of the samples area that the buffer would
335 /// be shorter than `frame_size`.
check_buffer_offset(&self, idx: usize, offset: usize) -> io::Result<()>336 fn check_buffer_offset(&self, idx: usize, offset: usize) -> io::Result<()> {
337 let start = offset;
338 let end = start + self.buffer_len_from_offset(start)?;
339
340 let other_idx = (idx ^ 1) as usize;
341 let other_start = self
342 .buffer_offset
343 .get(other_idx)
344 .ok_or_else(index_out_of_range)?
345 .load() as usize;
346 let other_end = other_start + self.buffer_len_from_offset(other_start)?;
347 if start < other_end && other_start < end {
348 // Special case: occasionally we get the same buffer offset twice
349 // from the intel8x0 kernel driver in crosvm's AC97 device, and we
350 // don't want to crash in that case.
351 if start == other_start && end == other_end {
352 warn!(
353 "Setting buffer {} to same index/offset as buffer {}, [{}, {})",
354 idx, other_idx, other_start, other_end
355 );
356 } else {
357 return Err(io::Error::new(
358 io::ErrorKind::InvalidInput,
359 format!(
360 "Setting buffer {} to [{}, {}) overlaps buffer {} at [{}, {})",
361 idx, start, end, other_idx, other_start, other_end,
362 ),
363 ));
364 }
365 }
366 Ok(())
367 }
368
369 /// Sets the location of the audio buffer `idx` within the samples area to
370 /// `offset`, so that CRAS will read/write samples for that buffer from that
371 /// offset.
372 ///
373 /// # Arguments
374 /// `idx` - 0 <= `idx` < `CRAS_NUM_SHM_BUFFERS`
375 /// `offset` - 0 <= `offset` && `offset` + `frame_size` <= `samples_len`
376 ///
377 /// # Errors
378 /// If `idx` is out of range
379 /// If the offset is invalid, which can happen if `offset` is
380 /// * outside of the samples area
381 /// * overlaps some other buffer `[other_offset, other_offset + used_size)`
382 /// * is close enough to the end of the samples area that the buffer would
383 /// be shorter than `frame_size`.
set_buffer_offset(&mut self, idx: usize, offset: usize) -> io::Result<()>384 pub fn set_buffer_offset(&mut self, idx: usize, offset: usize) -> io::Result<()> {
385 self.check_buffer_offset(idx, offset)?;
386
387 let buffer_offset = self.buffer_offset.get(idx).ok_or_else(index_out_of_range)?;
388 buffer_offset.store(offset as u64);
389 Ok(())
390 }
391
392 /// Commits written frames by switching the current buffer to the other one
393 /// after samples are ready and indexes of current buffer are all set.
394 /// - Sets `write_offset` of current buffer to `frame_count * frame_size`
395 /// - Sets `read_offset` of current buffer to `0`.
396 ///
397 /// # Arguments
398 ///
399 /// * `frame_count` - Number of frames written to the current buffer
400 ///
401 /// # Errors
402 ///
403 /// * Returns error if `frame_count` is larger than buffer size
404 ///
405 /// This function is safe because we switch `write_buf_idx` after letting
406 /// `write_offset` and `read_offset` ready and we read / write shared memory
407 /// variables with volatile operations.
commit_written_frames(&mut self, frame_count: u32) -> io::Result<()>408 pub fn commit_written_frames(&mut self, frame_count: u32) -> io::Result<()> {
409 // Uses `u64` to prevent possible overflow
410 let byte_count = frame_count as u64 * self.get_frame_size() as u64;
411 if byte_count > self.get_used_size() as u64 {
412 Err(io::Error::new(
413 io::ErrorKind::InvalidInput,
414 "frame_count * frame_size is larger than used_size",
415 ))
416 } else {
417 let idx = self.get_write_buf_idx() as usize;
418 // Sets `write_offset` of current buffer to frame_count * frame_size
419 self.set_write_offset(idx, byte_count as u32)?;
420 // Sets `read_offset` of current buffer to `0`.
421 self.set_read_offset(idx, 0)?;
422 // Switch to the other buffer
423 self.switch_write_buf_idx();
424 Ok(())
425 }
426 }
427
428 /// Get readable frames in current buffer.
429 ///
430 /// # Returns
431 ///
432 /// * `usize` - number of readable frames.
433 ///
434 /// # Errors
435 ///
436 /// Returns error if index out of range.
get_readable_frames(&self) -> io::Result<usize>437 pub fn get_readable_frames(&self) -> io::Result<usize> {
438 let idx = self.get_read_buf_idx() as usize;
439 let read_offset = self.read_offset.get(idx).ok_or_else(index_out_of_range)?;
440 let write_offset = self.write_offset.get(idx).ok_or_else(index_out_of_range)?;
441 let nframes =
442 (write_offset.load() as i32 - read_offset.load() as i32) / self.get_frame_size() as i32;
443 if nframes < 0 {
444 Ok(0)
445 } else {
446 Ok(nframes as usize)
447 }
448 }
449
450 /// Commit read frames from reader, .
451 /// - Sets `read_offset` of current buffer to `read_offset + frame_count * frame_size`.
452 /// If `read_offset` is larger than or equal to `write_offset`, then
453 /// - Sets `read_offset` and `write_offset` to `0` and switch `read_buf_idx`.
454 ///
455 /// # Arguments
456 ///
457 /// * `frame_count` - Read frames in current read buffer.
458 ///
459 /// # Errors
460 ///
461 /// Returns error if index out of range.
commit_read_frames(&mut self, frame_count: u32) -> io::Result<()>462 pub fn commit_read_frames(&mut self, frame_count: u32) -> io::Result<()> {
463 let idx = self.get_read_buf_idx() as usize;
464 let read_offset = self.read_offset.get(idx).ok_or_else(index_out_of_range)?;
465 let write_offset = self.write_offset.get(idx).ok_or_else(index_out_of_range)?;
466 read_offset.store(read_offset.load() + frame_count * self.get_frame_size() as u32);
467 if read_offset.load() >= write_offset.load() {
468 read_offset.store(0);
469 write_offset.store(0);
470 self.switch_read_buf_idx();
471 }
472 Ok(())
473 }
474 }
475
476 impl<'a> Drop for CrasAudioHeader<'a> {
drop(&mut self)477 fn drop(&mut self) {
478 // Safe because all references must be gone by the time drop is called.
479 unsafe {
480 libc::munmap(self.addr as *mut _, mem::size_of::<cras_audio_shm_header>());
481 }
482 }
483 }
484
485 // To use this safely, we need to make sure
486 // - The given fd contains valid space which is larger than `len` + `offset`
cras_mmap_offset( len: usize, prot: libc::c_int, fd: libc::c_int, offset: usize, ) -> io::Result<*mut libc::c_void>487 unsafe fn cras_mmap_offset(
488 len: usize,
489 prot: libc::c_int,
490 fd: libc::c_int,
491 offset: usize,
492 ) -> io::Result<*mut libc::c_void> {
493 if offset > libc::off_t::max_value() as usize {
494 return Err(io::Error::new(
495 io::ErrorKind::InvalidInput,
496 "Requested offset is out of range of `libc::off_t`.",
497 ));
498 }
499 // It's safe because we handle its returned results.
500 match libc::mmap(
501 ptr::null_mut(),
502 len,
503 prot,
504 libc::MAP_SHARED,
505 fd,
506 offset as libc::off_t,
507 ) {
508 libc::MAP_FAILED => Err(io::Error::last_os_error()),
509 shm_ptr => Ok(shm_ptr),
510 }
511 }
512
513 // To use this safely, we need to make sure
514 // - The given fd contains valid space which is larger than `len`
cras_mmap( len: usize, prot: libc::c_int, fd: libc::c_int, ) -> io::Result<*mut libc::c_void>515 unsafe fn cras_mmap(
516 len: usize,
517 prot: libc::c_int,
518 fd: libc::c_int,
519 ) -> io::Result<*mut libc::c_void> {
520 cras_mmap_offset(len, prot, fd, 0)
521 }
522
523 /// An unsafe macro for getting a `VolatileSlice` representing an entire array
524 /// field from a given NonNull pointer.
525 ///
526 /// To use this macro safely, we need to
527 /// - Make sure the pointer address is readable and writeable for its struct.
528 /// - Make sure all `VolatileSlice`s generated from this macro have exclusive ownership for the same
529 /// pointer.
530 /// - Make sure the length of the array field is non-zero.
531 #[macro_export]
532 macro_rules! vslice_from_addr {
533 ($addr:ident, $($field:ident).*) => {{
534 let ptr = &mut $addr.as_mut().$($field).* as *mut _ as *mut u8;
535 let size = std::mem::size_of_val(&$addr.as_mut().$($field).*);
536 VolatileSlice::from_raw_parts(ptr, size)
537 }};
538 }
539
540 /// A structure that points to RO shared memory area - `cras_server_state`
541 /// The structure is created from a shared memory fd which contains the structure.
542 #[derive(Debug)]
543 pub struct CrasServerState<'a> {
544 addr: *mut libc::c_void,
545 volume: VolatileRef<'a, u32>,
546 mute: VolatileRef<'a, i32>,
547 num_output_devs: VolatileRef<'a, u32>,
548 output_devs: VolatileSlice<'a>,
549 num_input_devs: VolatileRef<'a, u32>,
550 input_devs: VolatileSlice<'a>,
551 num_output_nodes: VolatileRef<'a, u32>,
552 num_input_nodes: VolatileRef<'a, u32>,
553 output_nodes: VolatileSlice<'a>,
554 input_nodes: VolatileSlice<'a>,
555 update_count: VolatileRef<'a, u32>,
556 debug_info_num_devs: VolatileRef<'a, u32>,
557 debug_info_devs: VolatileSlice<'a>,
558 debug_info_num_streams: VolatileRef<'a, u32>,
559 debug_info_streams: VolatileSlice<'a>,
560 }
561
562 // It is safe to send server_state between threads as this struct has exclusive
563 // ownership of the shared memory area contained in it.
564 unsafe impl<'a> Send for CrasServerState<'a> {}
565
566 impl<'a> CrasServerState<'a> {
567 /// Create a CrasServerState
try_new(state_fd: CrasServerStateShmFd) -> io::Result<Self>568 pub fn try_new(state_fd: CrasServerStateShmFd) -> io::Result<Self> {
569 // Safe because the creator of CrasServerStateShmFd already
570 // ensured that state_fd contains a cras_server_state.
571 let mmap_addr =
572 unsafe { cras_mmap(state_fd.fd.size, libc::PROT_READ, state_fd.fd.as_raw_fd())? };
573
574 let mut addr = NonNull::new(mmap_addr as *mut cras_server_state).ok_or_else(|| {
575 io::Error::new(io::ErrorKind::Other, "Failed to create CrasServerState.")
576 })?;
577
578 // Safe because we know that addr is a non-null pointer to cras_server_state.
579 let state_version = unsafe { vref_from_addr!(addr, state_version) };
580 if state_version.load() != CRAS_SERVER_STATE_VERSION {
581 return Err(io::Error::new(
582 io::ErrorKind::Other,
583 format!(
584 "CrasServerState version {} does not match expected version {}",
585 state_version.load(),
586 CRAS_SERVER_STATE_VERSION
587 ),
588 ));
589 }
590
591 // Safe because we know that mmap_addr (contained in addr) contains a
592 // cras_server_state, and the mapped area will be exclusively
593 // owned by this struct.
594 unsafe {
595 Ok(CrasServerState {
596 addr: addr.as_ptr() as *mut libc::c_void,
597 volume: vref_from_addr!(addr, volume),
598 mute: vref_from_addr!(addr, mute),
599 num_output_devs: vref_from_addr!(addr, num_output_devs),
600 num_input_devs: vref_from_addr!(addr, num_input_devs),
601 output_devs: vslice_from_addr!(addr, output_devs),
602 input_devs: vslice_from_addr!(addr, input_devs),
603 num_output_nodes: vref_from_addr!(addr, num_output_nodes),
604 num_input_nodes: vref_from_addr!(addr, num_input_nodes),
605 output_nodes: vslice_from_addr!(addr, output_nodes),
606 input_nodes: vslice_from_addr!(addr, input_nodes),
607 update_count: vref_from_addr!(addr, update_count),
608 debug_info_num_devs: vref_from_addr!(addr, audio_debug_info.num_devs),
609 debug_info_devs: vslice_from_addr!(addr, audio_debug_info.devs),
610 debug_info_num_streams: vref_from_addr!(addr, audio_debug_info.num_streams),
611 debug_info_streams: vslice_from_addr!(addr, audio_debug_info.streams),
612 })
613 }
614 }
615
616 /// Gets the system volume.
617 ///
618 /// Read the current value for system volume from shared memory.
get_system_volume(&self) -> u32619 pub fn get_system_volume(&self) -> u32 {
620 self.volume.load()
621 }
622
623 /// Gets the system mute.
624 ///
625 /// Read the current value for system mute from shared memory.
get_system_mute(&self) -> bool626 pub fn get_system_mute(&self) -> bool {
627 self.mute.load() != 0
628 }
629
630 /// Runs a closure safely such that it can be sure that the server state
631 /// was not updated during the read.
632 /// This can be used for an "atomic" read of non-atomic data from the
633 /// state shared memory.
synchronized_state_read<F, T>(&self, mut func: F) -> T where F: FnMut() -> T,634 fn synchronized_state_read<F, T>(&self, mut func: F) -> T
635 where
636 F: FnMut() -> T,
637 {
638 // Waits until the server has completed a state update before returning
639 // the current update count.
640 let begin_server_state_read = || -> u32 {
641 loop {
642 let update_count = self.update_count.load();
643 if update_count % 2 == 0 {
644 atomic::fence(Ordering::Acquire);
645 return update_count;
646 } else {
647 thread::yield_now();
648 }
649 }
650 };
651
652 // Checks that the update count has not changed since the start
653 // of the server state read.
654 let end_server_state_read = |count: u32| -> bool {
655 let result = count == self.update_count.load();
656 atomic::fence(Ordering::Release);
657 result
658 };
659
660 // Get the state's update count and run the provided closure.
661 // If the update count has not changed once the closure is finished,
662 // return the result, otherwise repeat the process.
663 loop {
664 let update_count = begin_server_state_read();
665 let result = func();
666 if end_server_state_read(update_count) {
667 return result;
668 }
669 }
670 }
671
672 /// Gets a list of output devices
673 ///
674 /// Read a list of the currently attached output devices from shared memory.
output_devices(&self) -> impl Iterator<Item = CrasIodevInfo>675 pub fn output_devices(&self) -> impl Iterator<Item = CrasIodevInfo> {
676 let mut devs: Vec<cras_iodev_info> = vec![Default::default(); CRAS_MAX_IODEVS as usize];
677 let num_devs = self.synchronized_state_read(|| {
678 self.output_devs.copy_to(&mut devs);
679 self.num_output_devs.load()
680 });
681 devs.into_iter()
682 .take(num_devs as usize)
683 .map(CrasIodevInfo::from)
684 }
685
686 /// Gets a list of input devices
687 ///
688 /// Read a list of the currently attached input devices from shared memory.
input_devices(&self) -> impl Iterator<Item = CrasIodevInfo>689 pub fn input_devices(&self) -> impl Iterator<Item = CrasIodevInfo> {
690 let mut devs: Vec<cras_iodev_info> = vec![Default::default(); CRAS_MAX_IODEVS as usize];
691 let num_devs = self.synchronized_state_read(|| {
692 self.input_devs.copy_to(&mut devs);
693 self.num_input_devs.load()
694 });
695 devs.into_iter()
696 .take(num_devs as usize)
697 .map(CrasIodevInfo::from)
698 }
699
700 /// Gets a list of output nodes
701 ///
702 /// Read a list of the currently attached output nodes from shared memory.
output_nodes(&self) -> impl Iterator<Item = CrasIonodeInfo>703 pub fn output_nodes(&self) -> impl Iterator<Item = CrasIonodeInfo> {
704 let mut nodes: Vec<cras_ionode_info> = vec![Default::default(); CRAS_MAX_IONODES as usize];
705 let num_nodes = self.synchronized_state_read(|| {
706 self.output_nodes.copy_to(&mut nodes);
707 self.num_output_nodes.load()
708 });
709 nodes
710 .into_iter()
711 .take(num_nodes as usize)
712 .map(CrasIonodeInfo::from)
713 }
714
715 /// Gets a list of input nodes
716 ///
717 /// Read a list of the currently attached input nodes from shared memory.
input_nodes(&self) -> impl Iterator<Item = CrasIonodeInfo>718 pub fn input_nodes(&self) -> impl Iterator<Item = CrasIonodeInfo> {
719 let mut nodes: Vec<cras_ionode_info> = vec![Default::default(); CRAS_MAX_IONODES as usize];
720 let num_nodes = self.synchronized_state_read(|| {
721 self.input_nodes.copy_to(&mut nodes);
722 self.num_input_nodes.load()
723 });
724 nodes
725 .into_iter()
726 .take(num_nodes as usize)
727 .map(CrasIonodeInfo::from)
728 }
729
730 /// Get audio debug info
731 ///
732 /// Loads the server's audio_debug_info struct and converts it into an
733 /// idiomatic rust representation.
734 ///
735 /// # Errors
736 /// * If any of the stream debug information structs are invalid.
get_audio_debug_info(&self) -> Result<AudioDebugInfo, cras_sys::Error>737 pub fn get_audio_debug_info(&self) -> Result<AudioDebugInfo, cras_sys::Error> {
738 let mut devs: Vec<audio_dev_debug_info> = vec![Default::default(); MAX_DEBUG_DEVS as usize];
739 let mut streams: Vec<audio_stream_debug_info> =
740 vec![Default::default(); MAX_DEBUG_STREAMS as usize];
741 let (num_devs, num_streams) = self.synchronized_state_read(|| {
742 self.debug_info_devs.copy_to(&mut devs);
743 self.debug_info_streams.copy_to(&mut streams);
744 (
745 self.debug_info_num_devs.load(),
746 self.debug_info_num_streams.load(),
747 )
748 });
749 let dev_info = devs
750 .into_iter()
751 .take(num_devs as usize)
752 .map(AudioDevDebugInfo::from)
753 .collect();
754 let stream_info = streams
755 .into_iter()
756 .take(num_streams as usize)
757 .map(AudioStreamDebugInfo::try_from)
758 .collect::<Result<Vec<_>, _>>()?;
759 Ok(AudioDebugInfo::new(dev_info, stream_info))
760 }
761 }
762
763 impl<'a> Drop for CrasServerState<'a> {
764 /// Call `munmap` for `addr`.
drop(&mut self)765 fn drop(&mut self) {
766 unsafe {
767 // Safe because all references must be gone by the time drop is called.
768 libc::munmap(self.addr, mem::size_of::<cras_server_state>());
769 }
770 }
771 }
772
773 /// A structure holding the mapped shared memory area used to exchange
774 /// samples with CRAS. The shared memory is owned exclusively by this structure,
775 /// and will be cleaned up on drop.
776 /// * `addr` - The address of the mapped shared memory.
777 /// * `len` - Length of the mapped shared memory in bytes.
778 pub struct CrasAudioBuffer {
779 addr: *mut u8,
780 len: usize,
781 }
782
783 // It is safe to send audio buffers between threads as this struct has exclusive ownership of the
784 // shared memory area contained in it.
785 unsafe impl Send for CrasAudioBuffer {}
786
787 impl CrasAudioBuffer {
new(samples_fd: CrasShmFd) -> io::Result<Self>788 fn new(samples_fd: CrasShmFd) -> io::Result<Self> {
789 // This is safe because we checked that the size of the shm in samples_fd
790 // was at least samples_fd.size when it was created.
791 let addr = unsafe {
792 cras_mmap(
793 samples_fd.size,
794 libc::PROT_READ | libc::PROT_WRITE,
795 samples_fd.as_raw_fd(),
796 )? as *mut u8
797 };
798 Ok(Self {
799 addr,
800 len: samples_fd.size,
801 })
802 }
803
804 /// Provides a mutable slice to be filled with audio samples.
get_buffer(&mut self) -> &mut [u8]805 pub fn get_buffer(&mut self) -> &mut [u8] {
806 // This is safe because it takes a mutable reference to self, and there can only be one
807 // taken at a time. Although this is shared memory, the reader side must have it mapped as
808 // read only.
809 unsafe { slice::from_raw_parts_mut(self.addr, self.len) }
810 }
811 }
812
813 impl Drop for CrasAudioBuffer {
drop(&mut self)814 fn drop(&mut self) {
815 // Safe because all references must be gone by the time drop is called.
816 unsafe {
817 libc::munmap(self.addr as *mut _, self.len);
818 }
819 }
820 }
821
822 /// Creates header and buffer from given shared memory fds.
create_header_and_buffers<'a>( header_fd: CrasAudioShmHeaderFd, samples_fd: CrasShmFd, ) -> io::Result<(CrasAudioHeader<'a>, CrasAudioBuffer)>823 pub fn create_header_and_buffers<'a>(
824 header_fd: CrasAudioShmHeaderFd,
825 samples_fd: CrasShmFd,
826 ) -> io::Result<(CrasAudioHeader<'a>, CrasAudioBuffer)> {
827 let header = CrasAudioHeader::new(header_fd, samples_fd.size)?;
828 let buffer = CrasAudioBuffer::new(samples_fd)?;
829
830 Ok((header, buffer))
831 }
832
833 /// Creates header from header shared memory fds. Use this function
834 /// when mapping the samples shm is not necessary, for instance with a
835 /// client-provided shm stream.
create_header<'a>( header_fd: CrasAudioShmHeaderFd, samples_len: usize, ) -> io::Result<CrasAudioHeader<'a>>836 pub fn create_header<'a>(
837 header_fd: CrasAudioShmHeaderFd,
838 samples_len: usize,
839 ) -> io::Result<CrasAudioHeader<'a>> {
840 Ok(CrasAudioHeader::new(header_fd, samples_len)?)
841 }
842
843 /// A structure wrapping a fd which contains a shared memory area and its size.
844 /// * `fd` - The shared memory file descriptor, a `libc::c_int`.
845 /// * `size` - Size of the shared memory area.
846 pub struct CrasShmFd {
847 fd: libc::c_int,
848 size: usize,
849 }
850
851 impl CrasShmFd {
852 /// Creates a `CrasShmFd` by shared memory fd and size
853 /// # Arguments
854 /// * `fd` - A shared memory file descriptor, which will be owned by the resulting structure and
855 /// the fd will be closed on drop.
856 /// * `size` - Size of the shared memory.
857 ///
858 /// # Returns
859 /// * `CrasShmFd` - Wrap the input arguments without doing anything.
860 ///
861 /// To use this function safely, we need to make sure
862 /// - The input fd is a valid shared memory fd.
863 /// - The input shared memory fd won't be used by others.
864 /// - The input fd contains memory size larger than `size`.
new(fd: libc::c_int, size: usize) -> CrasShmFd865 pub unsafe fn new(fd: libc::c_int, size: usize) -> CrasShmFd {
866 CrasShmFd { fd, size }
867 }
868 }
869
870 impl AsRawFd for CrasShmFd {
as_raw_fd(&self) -> RawFd871 fn as_raw_fd(&self) -> RawFd {
872 self.fd
873 }
874 }
875
876 impl Drop for CrasShmFd {
drop(&mut self)877 fn drop(&mut self) {
878 // It's safe here if we make sure
879 // - the input fd is valid and
880 // - `CrasShmFd` is the only owner
881 // in `new` function
882 unsafe {
883 libc::close(self.fd);
884 }
885 }
886 }
887
888 /// A structure wrapping a fd which contains a shared `cras_server_state`.
889 /// * `shm_fd` - A shared memory fd contains a `cras_server_state`
890 pub struct CrasServerStateShmFd {
891 fd: CrasShmFd,
892 }
893
894 impl CrasServerStateShmFd {
895 /// Creates a `CrasServerStateShmFd` by shared memory fd
896 /// # Arguments
897 /// * `fd` - A shared memory file descriptor, which will be owned by the resulting structure and
898 /// the fd will be closed on drop.
899 ///
900 /// # Returns
901 /// A structure wrapping a `CrasShmFd` with the input fd and `size` which equals to
902 /// the size of `cras_server_sate`.
903 ///
904 /// To use this function safely, we need to make sure
905 /// - The input fd is a valid shared memory fd.
906 /// - The input shared memory fd won't be used by others.
907 /// - The shared memory area in the input fd contains a `cras_server_state`.
new(fd: libc::c_int) -> Self908 pub unsafe fn new(fd: libc::c_int) -> Self {
909 Self {
910 fd: CrasShmFd::new(fd, mem::size_of::<cras_server_state>()),
911 }
912 }
913 }
914
915 #[cfg(test)]
916 mod tests {
917 use super::*;
918 use std::fs::File;
919 use std::os::unix::io::IntoRawFd;
920 use std::sync::{Arc, Mutex};
921 use std::thread;
922 use sys_util::{kernel_has_memfd, SharedMemory};
923
924 #[test]
cras_audio_header_switch_test()925 fn cras_audio_header_switch_test() {
926 if !kernel_has_memfd() {
927 return;
928 }
929 let mut header = create_cras_audio_header(20);
930 assert_eq!(0, header.get_write_buf_idx());
931 header.switch_write_buf_idx();
932 assert_eq!(1, header.get_write_buf_idx());
933 }
934
935 #[test]
cras_audio_header_write_offset_test()936 fn cras_audio_header_write_offset_test() {
937 if !kernel_has_memfd() {
938 return;
939 }
940 let mut header = create_cras_audio_header(20);
941 header.frame_size.store(2);
942 header.used_size.store(5);
943 header.set_buffer_offset(0, 12).unwrap();
944
945 assert_eq!(0, header.write_offset[0].load());
946 // Index out of bound
947 assert!(header.set_write_offset(2, 5).is_err());
948 // Offset out of bound
949 // Buffer length is 4, since that's the largest multiple of frame_size
950 // less than used_size.
951 assert!(header.set_write_offset(0, 6).is_err());
952 assert_eq!(0, header.write_offset[0].load());
953 assert!(header.set_write_offset(0, 5).is_err());
954 assert_eq!(0, header.write_offset[0].load());
955 assert!(header.set_write_offset(0, 4).is_ok());
956 assert_eq!(4, header.write_offset[0].load());
957 }
958
959 #[test]
cras_audio_header_read_offset_test()960 fn cras_audio_header_read_offset_test() {
961 if !kernel_has_memfd() {
962 return;
963 }
964 let mut header = create_cras_audio_header(20);
965 header.frame_size.store(2);
966 header.used_size.store(5);
967 header.set_buffer_offset(0, 12).unwrap();
968
969 assert_eq!(0, header.read_offset[0].load());
970 // Index out of bound
971 assert!(header.set_read_offset(2, 5).is_err());
972 // Offset out of bound
973 // Buffer length is 4, since that's the largest multiple of frame_size
974 // less than used_size.
975 assert!(header.set_read_offset(0, 6).is_err());
976 assert_eq!(0, header.read_offset[0].load());
977 assert!(header.set_read_offset(0, 5).is_err());
978 assert_eq!(0, header.read_offset[0].load());
979 assert!(header.set_read_offset(0, 4).is_ok());
980 assert_eq!(4, header.read_offset[0].load());
981 }
982
983 #[test]
cras_audio_header_commit_written_frame_test()984 fn cras_audio_header_commit_written_frame_test() {
985 if !kernel_has_memfd() {
986 return;
987 }
988 let mut header = create_cras_audio_header(20);
989 header.frame_size.store(2);
990 header.used_size.store(10);
991 header.read_offset[0].store(10);
992 header.set_buffer_offset(0, 10).unwrap();
993
994 assert!(header.commit_written_frames(5).is_ok());
995 assert_eq!(header.write_offset[0].load(), 10);
996 assert_eq!(header.read_offset[0].load(), 0);
997 assert_eq!(header.write_buf_idx.load(), 1);
998 }
999
1000 #[test]
cras_audio_header_get_readable_frames_test()1001 fn cras_audio_header_get_readable_frames_test() {
1002 if !kernel_has_memfd() {
1003 return;
1004 }
1005 let header = create_cras_audio_header(20);
1006 header.frame_size.store(2);
1007 header.used_size.store(10);
1008 header.read_offset[0].store(2);
1009 header.write_offset[0].store(10);
1010 let frames = header
1011 .get_readable_frames()
1012 .expect("Failed to get readable frames.");
1013 assert_eq!(frames, 4);
1014 }
1015
1016 #[test]
cras_audio_header_commit_read_frames_test()1017 fn cras_audio_header_commit_read_frames_test() {
1018 if !kernel_has_memfd() {
1019 return;
1020 }
1021 let mut header = create_cras_audio_header(20);
1022 header.frame_size.store(2);
1023 header.used_size.store(10);
1024 header.read_offset[0].store(2);
1025 header.write_offset[0].store(10);
1026 header
1027 .commit_read_frames(3)
1028 .expect("Failed to commit read frames.");
1029 assert_eq!(header.get_read_buf_idx(), 0);
1030 assert_eq!(header.read_offset[0].load(), 8);
1031
1032 header
1033 .commit_read_frames(1)
1034 .expect("Failed to commit read frames.");
1035 // Read buffer should be switched
1036 assert_eq!(header.get_read_buf_idx(), 1);
1037 assert_eq!(header.read_offset[0].load(), 0);
1038 assert_eq!(header.read_offset[0].load(), 0);
1039 }
1040
1041 #[test]
cras_audio_header_get_write_offset_and_len()1042 fn cras_audio_header_get_write_offset_and_len() {
1043 if !kernel_has_memfd() {
1044 return;
1045 }
1046 let header = create_cras_audio_header(30);
1047 header.frame_size.store(2);
1048 header.used_size.store(10);
1049 header.write_buf_idx.store(0);
1050 header.read_offset[0].store(0);
1051 header.write_offset[0].store(0);
1052 header.buffer_offset[0].store(0);
1053
1054 header.read_buf_idx.store(1);
1055 header.read_offset[1].store(0);
1056 header.write_offset[1].store(0);
1057 header.buffer_offset[1].store(10);
1058
1059 // standard offsets and lens
1060 let (offset, len) = header.get_write_offset_and_len().unwrap();
1061 assert_eq!(offset, 0);
1062 assert_eq!(len, 10);
1063
1064 header.write_buf_idx.store(1);
1065 header.read_buf_idx.store(0);
1066 let (offset, len) = header.get_write_offset_and_len().unwrap();
1067 assert_eq!(offset, 10);
1068 assert_eq!(len, 10);
1069
1070 // relocate buffer offsets
1071 header.buffer_offset[1].store(16);
1072 let (offset, len) = header.get_write_offset_and_len().unwrap();
1073 assert_eq!(offset, 16);
1074 assert_eq!(len, 10);
1075
1076 header.buffer_offset[0].store(5);
1077 header.write_buf_idx.store(0);
1078 let (offset, len) = header.get_write_offset_and_len().unwrap();
1079 assert_eq!(offset, 5);
1080 assert_eq!(len, 10);
1081
1082 header.write_buf_idx.store(0);
1083 header.buffer_offset[0].store(2);
1084 header.read_buf_idx.store(1);
1085 header.buffer_offset[1].store(10);
1086 let result = header.get_write_offset_and_len();
1087 // Should be an error as write buffer would overrun into other buffer.
1088 assert!(result.is_err());
1089
1090 header.buffer_offset[0].store(24);
1091 header.buffer_offset[1].store(10);
1092 let (offset, len) = header.get_write_offset_and_len().unwrap();
1093 // Should be ok since we're only running up against the end of samples.
1094 assert_eq!(offset, 24);
1095 assert_eq!(len, 6);
1096
1097 header.buffer_offset[0].store(25);
1098 let (offset, len) = header.get_write_offset_and_len().unwrap();
1099 // Should be ok, but we'll truncate len to frame_size.
1100 assert_eq!(offset, 25);
1101 assert_eq!(len, 4);
1102
1103 header.buffer_offset[0].store(29);
1104 let result = header.get_write_offset_and_len();
1105 // Should be an error as buffer is smaller than frame_size.
1106 assert!(result.is_err());
1107 }
1108
1109 #[test]
cras_audio_header_set_buffer_offset()1110 fn cras_audio_header_set_buffer_offset() {
1111 if !kernel_has_memfd() {
1112 return;
1113 }
1114 let mut header = create_cras_audio_header(30);
1115 header.frame_size.store(2);
1116 header.used_size.store(10);
1117 header.write_buf_idx.store(0);
1118 header.read_offset[0].store(0);
1119 header.write_offset[0].store(0);
1120 header.buffer_offset[0].store(0);
1121
1122 header.read_buf_idx.store(1);
1123 header.read_offset[1].store(0);
1124 header.write_offset[1].store(0);
1125 header.buffer_offset[1].store(10);
1126
1127 // Setting buffer_offset to exactly overlap with other buffer is okay
1128 assert!(header.set_buffer_offset(0, 10).is_ok());
1129
1130 // Setting buffer_offset to partially overlap other buffer is not okay
1131 assert!(header.set_buffer_offset(0, 9).is_err());
1132
1133 header.buffer_offset[0].store(0);
1134 header.write_offset[1].store(8);
1135 // With samples, it's still an error.
1136 assert!(header.set_buffer_offset(0, 9).is_err());
1137
1138 // Setting the offset past the end of the other buffer is okay
1139 assert!(header.set_buffer_offset(0, 20).is_ok());
1140
1141 // Setting buffer offset such that buffer length is less than used_size
1142 // is okay, but only at the end of the samples area.
1143 assert!(header.set_buffer_offset(0, 21).is_ok());
1144 assert!(header.set_buffer_offset(0, 27).is_ok());
1145
1146 // It's not okay if we get a buffer with length less than frame_size.
1147 assert!(header.set_buffer_offset(0, 29).is_err());
1148 assert!(header.set_buffer_offset(0, 30).is_err());
1149
1150 // If we try to overlap another buffer with that other buffer at the end,
1151 // it's not okay, unless it's the exact same index.
1152 assert!(header.set_buffer_offset(1, 25).is_err());
1153 assert!(header.set_buffer_offset(1, 27).is_ok());
1154 assert!(header.set_buffer_offset(1, 28).is_err());
1155
1156 // Setting buffer offset past the end of samples is an error.
1157 assert!(header.set_buffer_offset(0, 33).is_err());
1158 }
1159
1160 #[test]
create_header_and_buffers_test()1161 fn create_header_and_buffers_test() {
1162 if !kernel_has_memfd() {
1163 return;
1164 }
1165 let header_fd = cras_audio_header_fd();
1166 let samples_fd = cras_audio_samples_fd(20);
1167 let res = create_header_and_buffers(header_fd, samples_fd);
1168 res.expect("Failed to create header and buffer.");
1169 }
1170
create_shm(size: usize) -> File1171 fn create_shm(size: usize) -> File {
1172 let mut shm = SharedMemory::new(None).expect("failed to create shm");
1173 shm.set_size(size as u64).expect("failed to set shm size");
1174 shm.into()
1175 }
1176
create_cras_audio_header<'a>(samples_len: usize) -> CrasAudioHeader<'a>1177 fn create_cras_audio_header<'a>(samples_len: usize) -> CrasAudioHeader<'a> {
1178 CrasAudioHeader::new(cras_audio_header_fd(), samples_len).unwrap()
1179 }
1180
cras_audio_header_fd() -> CrasAudioShmHeaderFd1181 fn cras_audio_header_fd() -> CrasAudioShmHeaderFd {
1182 let size = mem::size_of::<cras_audio_shm_header>();
1183 let shm = create_shm(size);
1184 unsafe { CrasAudioShmHeaderFd::new(shm.into_raw_fd()) }
1185 }
1186
cras_audio_samples_fd(size: usize) -> CrasShmFd1187 fn cras_audio_samples_fd(size: usize) -> CrasShmFd {
1188 let shm = create_shm(size);
1189 unsafe { CrasShmFd::new(shm.into_raw_fd(), size) }
1190 }
1191
1192 #[test]
cras_mmap_pass()1193 fn cras_mmap_pass() {
1194 if !kernel_has_memfd() {
1195 return;
1196 }
1197 let shm = create_shm(100);
1198 let rc = unsafe { cras_mmap(10, libc::PROT_READ, shm.as_raw_fd()) };
1199 assert!(rc.is_ok());
1200 unsafe { libc::munmap(rc.unwrap(), 10) };
1201 }
1202
1203 #[test]
cras_mmap_failed()1204 fn cras_mmap_failed() {
1205 if !kernel_has_memfd() {
1206 return;
1207 }
1208 let rc = unsafe { cras_mmap(10, libc::PROT_READ, -1) };
1209 assert!(rc.is_err());
1210 }
1211
1212 #[test]
cras_server_state()1213 fn cras_server_state() {
1214 let size = mem::size_of::<cras_server_state>();
1215 let shm = create_shm(size);
1216 unsafe {
1217 let addr = cras_mmap(size, libc::PROT_WRITE, shm.as_raw_fd())
1218 .expect("failed to mmap state shm");
1219 {
1220 let state: &mut cras_server_state = &mut *(addr as *mut cras_server_state);
1221 state.state_version = CRAS_SERVER_STATE_VERSION;
1222 state.volume = 47;
1223 state.mute = 1;
1224 }
1225 libc::munmap(addr, size);
1226 };
1227 let state_fd = unsafe { CrasServerStateShmFd::new(shm.into_raw_fd()) };
1228 let state =
1229 CrasServerState::try_new(state_fd).expect("try_new failed for valid server_state fd");
1230 assert_eq!(state.get_system_volume(), 47);
1231 assert_eq!(state.get_system_mute(), true);
1232 }
1233
1234 #[test]
cras_server_state_old_version()1235 fn cras_server_state_old_version() {
1236 let size = mem::size_of::<cras_server_state>();
1237 let shm = create_shm(size);
1238 unsafe {
1239 let addr = cras_mmap(size, libc::PROT_WRITE, shm.as_raw_fd())
1240 .expect("failed to mmap state shm");
1241 {
1242 let state: &mut cras_server_state = &mut *(addr as *mut cras_server_state);
1243 state.state_version = CRAS_SERVER_STATE_VERSION - 1;
1244 state.volume = 29;
1245 state.mute = 0;
1246 }
1247 libc::munmap(addr, size);
1248 };
1249 let state_fd = unsafe { CrasServerStateShmFd::new(shm.into_raw_fd()) };
1250 CrasServerState::try_new(state_fd)
1251 .expect_err("try_new succeeded for invalid state version");
1252 }
1253
1254 #[test]
cras_server_sync_state_read()1255 fn cras_server_sync_state_read() {
1256 let size = mem::size_of::<cras_server_state>();
1257 let shm = create_shm(size);
1258 let addr = unsafe { cras_mmap(size, libc::PROT_WRITE, shm.as_raw_fd()).unwrap() };
1259 let state: &mut cras_server_state = unsafe { &mut *(addr as *mut cras_server_state) };
1260 state.state_version = CRAS_SERVER_STATE_VERSION;
1261 state.update_count = 14;
1262 state.volume = 12;
1263
1264 let state_fd = unsafe { CrasServerStateShmFd::new(shm.into_raw_fd()) };
1265 let state_struct = CrasServerState::try_new(state_fd).unwrap();
1266
1267 // Create a lock so that we can block the reader while we change the
1268 // update_count;
1269 let lock = Arc::new(Mutex::new(()));
1270 let thread_lock = lock.clone();
1271 let reader_thread = {
1272 let _guard = lock.lock().unwrap();
1273
1274 // Create reader thread that will get the value of volume. Since we
1275 // hold the lock currently, this will block until we release the lock.
1276 let reader_thread = thread::spawn(move || {
1277 state_struct.synchronized_state_read(|| {
1278 let _guard = thread_lock.lock().unwrap();
1279 state_struct.volume.load()
1280 })
1281 });
1282
1283 // Update volume and change update count so that the synchronized read
1284 // will not return (odd update count means update in progress).
1285 state.volume = 27;
1286 state.update_count = 15;
1287
1288 reader_thread
1289 };
1290
1291 // The lock has been released, but the reader thread should still not
1292 // terminate, because of the update in progress.
1293
1294 // Yield thread to give reader_thread a chance to get scheduled.
1295 thread::yield_now();
1296 {
1297 let _guard = lock.lock().unwrap();
1298
1299 // Update volume and change update count to indicate the write has
1300 // finished.
1301 state.volume = 42;
1302 state.update_count = 16;
1303 }
1304
1305 let read_value = reader_thread.join().unwrap();
1306 assert_eq!(read_value, 42);
1307 }
1308 }
1309