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