Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/fiber/src/windows.rs
1692 views
1
use crate::{RunResult, RuntimeFiberStack};
2
use alloc::boxed::Box;
3
use std::cell::Cell;
4
use std::ffi::c_void;
5
use std::io;
6
use std::ops::Range;
7
use std::ptr;
8
use windows_sys::Win32::Foundation::*;
9
use windows_sys::Win32::System::Threading::*;
10
11
pub type Error = io::Error;
12
13
#[derive(Debug)]
14
pub struct FiberStack(usize);
15
16
impl FiberStack {
17
pub fn new(size: usize, zeroed: bool) -> io::Result<Self> {
18
// We don't support fiber stack zeroing on windows.
19
let _ = zeroed;
20
21
Ok(Self(size))
22
}
23
24
pub unsafe fn from_raw_parts(
25
_base: *mut u8,
26
_guard_size: usize,
27
_len: usize,
28
) -> io::Result<Self> {
29
Err(io::Error::from_raw_os_error(ERROR_NOT_SUPPORTED as i32))
30
}
31
32
pub fn is_from_raw_parts(&self) -> bool {
33
false
34
}
35
36
pub fn from_custom(_custom: Box<dyn RuntimeFiberStack>) -> io::Result<Self> {
37
Err(io::Error::from_raw_os_error(ERROR_NOT_SUPPORTED as i32))
38
}
39
40
pub fn top(&self) -> Option<*mut u8> {
41
None
42
}
43
44
pub fn range(&self) -> Option<Range<usize>> {
45
None
46
}
47
48
pub fn guard_range(&self) -> Option<Range<*mut u8>> {
49
None
50
}
51
}
52
53
pub struct Fiber {
54
fiber: *mut c_void,
55
state: Box<StartState>,
56
}
57
58
pub struct Suspend {
59
state: *const StartState,
60
}
61
62
struct StartState {
63
parent: Cell<*mut c_void>,
64
initial_closure: Cell<*mut u8>,
65
result_location: Cell<*const u8>,
66
}
67
68
const FIBER_FLAG_FLOAT_SWITCH: u32 = 1;
69
70
unsafe extern "C" {
71
#[wasmtime_versioned_export_macros::versioned_link]
72
fn wasmtime_fiber_get_current() -> *mut c_void;
73
}
74
75
unsafe extern "system" fn fiber_start<F, A, B, C>(data: *mut c_void)
76
where
77
F: FnOnce(A, &mut super::Suspend<A, B, C>) -> C,
78
{
79
unsafe {
80
// Set the stack guarantee to be consistent with what Rust expects for threads
81
// This value is taken from:
82
// https://github.com/rust-lang/rust/blob/0d97f7a96877a96015d70ece41ad08bb7af12377/library/std/src/sys/windows/stack_overflow.rs
83
if SetThreadStackGuarantee(&mut 0x5000) == 0 {
84
panic!("failed to set fiber stack guarantee");
85
}
86
87
let state = data.cast::<StartState>();
88
let func = Box::from_raw((*state).initial_closure.get().cast::<F>());
89
(*state).initial_closure.set(ptr::null_mut());
90
let suspend = Suspend { state };
91
let initial = suspend.take_resume::<A, B, C>();
92
super::Suspend::<A, B, C>::execute(suspend, initial, *func);
93
}
94
}
95
96
impl Fiber {
97
pub fn new<F, A, B, C>(stack: &FiberStack, func: F) -> io::Result<Self>
98
where
99
F: FnOnce(A, &mut super::Suspend<A, B, C>) -> C,
100
{
101
unsafe {
102
let state = Box::new(StartState {
103
initial_closure: Cell::new(Box::into_raw(Box::new(func)).cast()),
104
parent: Cell::new(ptr::null_mut()),
105
result_location: Cell::new(ptr::null()),
106
});
107
108
let fiber = CreateFiberEx(
109
0,
110
stack.0,
111
FIBER_FLAG_FLOAT_SWITCH,
112
Some(fiber_start::<F, A, B, C>),
113
&*state as *const StartState as *mut _,
114
);
115
116
if fiber.is_null() {
117
drop(Box::from_raw(state.initial_closure.get().cast::<F>()));
118
return Err(io::Error::last_os_error());
119
}
120
121
Ok(Self { fiber, state })
122
}
123
}
124
125
pub(crate) fn resume<A, B, C>(&self, _stack: &FiberStack, result: &Cell<RunResult<A, B, C>>) {
126
unsafe {
127
let is_fiber = IsThreadAFiber() != 0;
128
let parent_fiber = if is_fiber {
129
wasmtime_fiber_get_current()
130
} else {
131
ConvertThreadToFiber(ptr::null_mut())
132
};
133
assert!(
134
!parent_fiber.is_null(),
135
"failed to make current thread a fiber"
136
);
137
self.state
138
.result_location
139
.set(result as *const _ as *const _);
140
self.state.parent.set(parent_fiber);
141
SwitchToFiber(self.fiber);
142
self.state.parent.set(ptr::null_mut());
143
self.state.result_location.set(ptr::null());
144
if !is_fiber {
145
let res = ConvertFiberToThread();
146
assert!(res != 0, "failed to convert main thread back");
147
}
148
}
149
}
150
151
pub(crate) unsafe fn drop<A, B, C>(&mut self) {}
152
}
153
154
impl Drop for Fiber {
155
fn drop(&mut self) {
156
unsafe {
157
DeleteFiber(self.fiber);
158
}
159
}
160
}
161
162
impl Suspend {
163
pub(crate) fn switch<A, B, C>(&self, result: RunResult<A, B, C>) -> A {
164
unsafe {
165
(*self.result_location::<A, B, C>()).set(result);
166
debug_assert!(IsThreadAFiber() != 0);
167
let parent = (*self.state).parent.get();
168
debug_assert!(!parent.is_null());
169
SwitchToFiber(parent);
170
self.take_resume::<A, B, C>()
171
}
172
}
173
174
pub(crate) fn exit<A, B, C>(&mut self, result: RunResult<A, B, C>) {
175
self.switch(result);
176
unreachable!()
177
}
178
179
unsafe fn take_resume<A, B, C>(&self) -> A {
180
unsafe {
181
match (*self.result_location::<A, B, C>()).replace(RunResult::Executing) {
182
RunResult::Resuming(val) => val,
183
_ => panic!("not in resuming state"),
184
}
185
}
186
}
187
188
unsafe fn result_location<A, B, C>(&self) -> *const Cell<RunResult<A, B, C>> {
189
unsafe {
190
let ret = (*self.state)
191
.result_location
192
.get()
193
.cast::<Cell<RunResult<A, B, C>>>();
194
assert!(!ret.is_null());
195
return ret;
196
}
197
}
198
}
199
200