• 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 // Defines Windows-specific submodules of sys_util
6 
7 // Modules ported to windows
8 pub mod syslog;
9 
10 mod platform_timer_utils;
11 pub use platform_timer_utils::*;
12 
13 mod file_util;
14 use std::fs::File;
15 use std::fs::OpenOptions;
16 use std::path::Path;
17 use std::ptr::null_mut;
18 
19 pub use file_util::*;
20 use serde::Deserialize;
21 use serde::Serialize;
22 use winapi::shared::minwindef::DWORD;
23 use winapi::shared::winerror::WAIT_TIMEOUT;
24 use winapi::um::handleapi::INVALID_HANDLE_VALUE;
25 use winapi::um::processthreadsapi::GetCurrentProcessId;
26 use winapi::um::synchapi::CreateMutexA;
27 use winapi::um::synchapi::ReleaseMutex;
28 use winapi::um::synchapi::WaitForSingleObject;
29 use winapi::um::winbase::INFINITE;
30 use winapi::um::winbase::WAIT_ABANDONED;
31 use winapi::um::winbase::WAIT_OBJECT_0;
32 use winapi::um::winuser::AllowSetForegroundWindow;
33 
34 use super::errno_result;
35 use super::pid_t;
36 use super::Error;
37 use super::Result;
38 use crate::descriptor::AsRawDescriptor;
39 use crate::descriptor::FromRawDescriptor;
40 use crate::descriptor::SafeDescriptor;
41 
42 #[inline(always)]
pagesize() -> usize43 pub fn pagesize() -> usize {
44     win_util::pagesize()
45 }
46 
47 /// Cross-platform wrapper around getting the current process id.
48 #[inline(always)]
getpid() -> pid_t49 pub fn getpid() -> pid_t {
50     // Safe because we only use the return value. ProcessId can safely be converted from DWORD to i32.
51     unsafe { GetCurrentProcessId() as pid_t }
52 }
53 
54 /// A Mutex (no data) that works across processes on Windows.
55 #[derive(Serialize, Deserialize, Debug)]
56 pub struct MultiProcessMutex {
57     lock: SafeDescriptor,
58 }
59 
60 impl MultiProcessMutex {
new() -> Result<Self>61     pub fn new() -> Result<Self> {
62         // Trivially safe (no memory passed, error checked).
63         //
64         // Note that we intentionally make this handle uninheritable by default via the mutex attrs.
65         let lock_handle = unsafe {
66             CreateMutexA(
67                 /* lpMutexAttributes= */ null_mut(),
68                 false as i32,
69                 null_mut(),
70             )
71         };
72 
73         if lock_handle == INVALID_HANDLE_VALUE {
74             Err(Error::last())
75         } else {
76             Ok(Self {
77                 // Safe because the handle is valid & we own it exclusively.
78                 lock: unsafe { SafeDescriptor::from_raw_descriptor(lock_handle) },
79             })
80         }
81     }
82 
83     /// Locks the mutex, returning a RAII guard similar to std::sync::Mutex.
lock(&self) -> MultiProcessMutexGuard84     pub fn lock(&self) -> MultiProcessMutexGuard {
85         if let Some(guard) = self.try_lock(INFINITE) {
86             guard
87         } else {
88             // This should *never* happen.
89             panic!("Timed out locking mutex with an infinite timeout. This should never happen.");
90         }
91     }
92 
93     /// Tries to lock the mutex, returning a RAII guard similar to std::sync::Mutex if we obtained
94     /// the lock within the timeout.
try_lock(&self, timeout_ms: u32) -> Option<MultiProcessMutexGuard>95     pub fn try_lock(&self, timeout_ms: u32) -> Option<MultiProcessMutexGuard> {
96         // Safe because the mutex handle is guaranteed to exist.
97         match unsafe { WaitForSingleObject(self.lock.as_raw_descriptor(), timeout_ms) } {
98             WAIT_OBJECT_0 => Some(MultiProcessMutexGuard { lock: &self.lock }),
99             WAIT_TIMEOUT => None,
100             WAIT_ABANDONED => panic!(
101                 "The thread holding the mutex exited without releasing the mutex.\
102                  Protected data may be corrupt."
103             ),
104             _ => {
105                 // This should *never* happen.
106                 panic!("Failed to lock mutex {:?}", Error::last())
107             }
108         }
109     }
110 
111     /// Creates a new reference to the mutex.
try_clone(&self) -> Result<Self>112     pub fn try_clone(&self) -> Result<Self> {
113         Ok(Self {
114             lock: self.lock.try_clone()?,
115         })
116     }
117 }
118 
119 /// RAII guard for MultiProcessMutex.
120 pub struct MultiProcessMutexGuard<'a> {
121     lock: &'a SafeDescriptor,
122 }
123 
124 impl<'a> Drop for MultiProcessMutexGuard<'a> {
drop(&mut self)125     fn drop(&mut self) {
126         if unsafe { ReleaseMutex(self.lock.as_raw_descriptor()) } == 0 {
127             panic!("Failed to unlock mutex: {:?}.", Error::last())
128         }
129     }
130 }
131 
132 /// Open the file with the given path.
133 ///
134 /// Note that on POSIX< this wrapper handles opening existing FDs via /proc/self/fd/N. On Windows,
135 /// this functionality doesn't exist, but we preserve this seemingly not very useful function to
136 /// simplify cross platform code.
open_file<P: AsRef<Path>>(path: P, options: &OpenOptions) -> Result<File>137 pub fn open_file<P: AsRef<Path>>(path: P, options: &OpenOptions) -> Result<File> {
138     Ok(options.open(path)?)
139 }
140 
141 /// Grants the given process id temporary permission to foreground another window. This succeeds
142 /// only when the emulator is in the foreground, and will persist only until the next user
143 /// interaction with the window
give_foregrounding_permission(process_id: DWORD) -> Result<()>144 pub fn give_foregrounding_permission(process_id: DWORD) -> Result<()> {
145     // Safe because this API does not modify memory, and process_id remains in scope for
146     // the duration of the call.
147     match unsafe { AllowSetForegroundWindow(process_id) } {
148         0 => errno_result(),
149         _ => Ok(()),
150     }
151 }
152