• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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::os::windows::raw::HANDLE;
6 
7 use log::warn;
8 use winapi::shared::minwindef::FALSE;
9 use winapi::um::avrt::AvRevertMmThreadCharacteristics;
10 use winapi::um::avrt::AvSetMmThreadCharacteristicsA;
11 use winapi::um::errhandlingapi::GetLastError;
12 use winapi::um::processthreadsapi::GetCurrentThread;
13 use winapi::um::processthreadsapi::SetThreadPriority;
14 
15 use super::errno_result;
16 use super::Result;
17 
set_audio_thread_priorities() -> Result<SafeMultimediaHandle>18 pub fn set_audio_thread_priorities() -> Result<SafeMultimediaHandle> {
19     // Safe because we know Pro Audio is part of windows and we down task_index.
20     let multimedia_handle = unsafe {
21         let mut task_index: u32 = 0;
22         // "Pro Audio" is defined in:
23         // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks\Pro Audio
24         let pro_audio = std::ffi::CString::new("Pro Audio").unwrap();
25         AvSetMmThreadCharacteristicsA(pro_audio.as_ptr(), &mut task_index)
26     };
27 
28     if multimedia_handle.is_null() {
29         warn!(
30             "Failed to set audio thread to Pro Audio. Error: {}",
31             unsafe { GetLastError() }
32         );
33         errno_result()
34     } else {
35         Ok(SafeMultimediaHandle { multimedia_handle })
36     }
37 }
38 
set_thread_priority(thread_priority: i32) -> Result<()>39 pub fn set_thread_priority(thread_priority: i32) -> Result<()> {
40     let res =
41         // Safe because priority level value is valid and a valid thread handle will be passed in
42         unsafe { SetThreadPriority(GetCurrentThread(), thread_priority) };
43     if res == 0 {
44         errno_result()
45     } else {
46         Ok(())
47     }
48 }
49 
50 pub struct SafeMultimediaHandle {
51     multimedia_handle: HANDLE,
52 }
53 
54 impl Drop for SafeMultimediaHandle {
drop(&mut self)55     fn drop(&mut self) {
56         // Safe because we `multimedia_handle` is defined in the same thread and is created in the
57         // function above. `multimedia_handle` needs be created from `AvSetMmThreadCharacteristicsA`.
58         // This will also drop the `mulitmedia_handle`.
59         if unsafe { AvRevertMmThreadCharacteristics(self.multimedia_handle) } == FALSE {
60             warn!("Failed to revert audio thread. Error: {}", unsafe {
61                 GetLastError()
62             });
63         }
64     }
65 }
66 
67 #[cfg(test)]
68 mod test {
69     use winapi::um::processthreadsapi::GetCurrentThread;
70     use winapi::um::processthreadsapi::GetThreadPriority;
71     use winapi::um::winbase::THREAD_PRIORITY_NORMAL;
72     use winapi::um::winbase::THREAD_PRIORITY_TIME_CRITICAL;
73 
74     use super::*;
75 
76     // TODO(b/223733375): Enable ignored flaky tests.
77     #[test]
78     #[ignore]
test_mm_handle_is_dropped()79     fn test_mm_handle_is_dropped() {
80         // Safe because the only the only unsafe functions called are to get the thread
81         // priority.
82         unsafe {
83             let thread_priority = GetThreadPriority(GetCurrentThread());
84             assert_eq!(thread_priority, THREAD_PRIORITY_NORMAL as i32);
85             {
86                 let _handle = set_audio_thread_priorities();
87                 let thread_priority = GetThreadPriority(GetCurrentThread());
88                 assert_eq!(thread_priority, THREAD_PRIORITY_TIME_CRITICAL as i32);
89             }
90             let thread_priority = GetThreadPriority(GetCurrentThread());
91             assert_eq!(thread_priority, THREAD_PRIORITY_NORMAL as i32);
92         }
93     }
94 }
95