• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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