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