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>18pub 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<()>39pub 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