wasmer_wasix/state/handles/
thread_local.rs

1#![cfg_attr(any(feature = "sys", feature = "sys-minimal"), allow(unused))]
2use std::cell::{Ref, RefCell, RefMut};
3use std::ops::{Deref, DerefMut};
4use std::{
5    collections::HashMap,
6    rc::Rc,
7    sync::atomic::{AtomicU64, Ordering},
8};
9
10use wasmer::Memory;
11
12use crate::WasiModuleTreeHandles;
13
14static LOCAL_INSTANCE_SEED: AtomicU64 = AtomicU64::new(1);
15thread_local! {
16    static THREAD_LOCAL_INSTANCE_HANDLES: RefCell<HashMap<u64, Rc<RefCell<WasiModuleTreeHandles>>>>
17        = RefCell::new(HashMap::new());
18}
19
20/// This non-sendable guard provides memory safe access
21/// to the WasiInstance object but only when it is
22/// constructed with certain constraints
23pub(crate) struct WasiInstanceGuard<'a> {
24    // the order is very important as the first value is
25    // dropped before the reference count is dropped
26    borrow: Ref<'static, WasiModuleTreeHandles>,
27    _pointer: &'a WasiInstanceHandlesPointer,
28    _inner: Rc<RefCell<WasiModuleTreeHandles>>,
29}
30impl Deref for WasiInstanceGuard<'_> {
31    type Target = WasiModuleTreeHandles;
32    fn deref(&self) -> &Self::Target {
33        self.borrow.deref()
34    }
35}
36
37/// This non-sendable guard provides memory safe access
38/// to the WasiInstance object but only when it is
39/// constructed with certain constraints. This one provides
40/// mutable access
41pub(crate) struct WasiInstanceGuardMut<'a> {
42    // the order is very important as the first value is
43    // dropped before the reference count is dropped
44    borrow: RefMut<'static, WasiModuleTreeHandles>,
45    _pointer: &'a WasiInstanceHandlesPointer,
46    _inner: Rc<RefCell<WasiModuleTreeHandles>>,
47}
48impl Deref for WasiInstanceGuardMut<'_> {
49    type Target = WasiModuleTreeHandles;
50
51    fn deref(&self) -> &Self::Target {
52        self.borrow.deref()
53    }
54}
55impl DerefMut for WasiInstanceGuardMut<'_> {
56    fn deref_mut(&mut self) -> &mut Self::Target {
57        self.borrow.deref_mut()
58    }
59}
60
61/// This handle protects the WasiInstance and makes it
62/// accessible only when you are in the current thread
63/// otherwise it will return None. This means it becomes
64/// possible to make WasiEnv send without unsafe code
65/// however it means that access to the must be checked
66#[derive(Debug, Default, Clone)]
67pub(crate) struct WasiInstanceHandlesPointer {
68    /// Inner functions and references that are loaded before the environment starts
69    id: Option<u64>,
70}
71impl Drop for WasiInstanceHandlesPointer {
72    fn drop(&mut self) {
73        self.clear();
74    }
75}
76impl WasiInstanceHandlesPointer {
77    pub fn get(&self) -> Option<WasiInstanceGuard<'_>> {
78        self.id
79            .iter()
80            .filter_map(|id| {
81                THREAD_LOCAL_INSTANCE_HANDLES.with(|map| {
82                    let map = map.borrow();
83                    if let Some(inner) = map.get(id) {
84                        let borrow: Ref<WasiModuleTreeHandles> = inner.borrow();
85                        let borrow: Ref<'static, WasiModuleTreeHandles> =
86                            unsafe { std::mem::transmute(borrow) };
87                        Some(WasiInstanceGuard {
88                            borrow,
89                            _pointer: self,
90                            _inner: inner.clone(),
91                        })
92                    } else {
93                        None
94                    }
95                })
96            })
97            .next()
98    }
99    pub fn get_mut(&self) -> Option<WasiInstanceGuardMut<'_>> {
100        self.id
101            .into_iter()
102            .filter_map(|id| {
103                THREAD_LOCAL_INSTANCE_HANDLES.with(|map| {
104                    let map = map.borrow_mut();
105                    if let Some(inner) = map.get(&id) {
106                        let borrow: RefMut<WasiModuleTreeHandles> = inner.borrow_mut();
107                        let borrow: RefMut<'static, WasiModuleTreeHandles> =
108                            unsafe { std::mem::transmute(borrow) };
109                        Some(WasiInstanceGuardMut {
110                            borrow,
111                            _pointer: self,
112                            _inner: inner.clone(),
113                        })
114                    } else {
115                        None
116                    }
117                })
118            })
119            .next()
120    }
121    pub fn set(&mut self, val: WasiModuleTreeHandles) {
122        self.clear();
123
124        let id = LOCAL_INSTANCE_SEED.fetch_add(1, Ordering::SeqCst);
125        THREAD_LOCAL_INSTANCE_HANDLES.with(|map| {
126            let mut map = map.borrow_mut();
127            map.insert(id, Rc::new(RefCell::new(val)));
128        });
129        if let Some(old_id) = self.id.replace(id) {
130            Self::destroy(old_id)
131        }
132    }
133    #[allow(dead_code)]
134    pub fn clear(&mut self) {
135        if let Some(id) = self.id.take() {
136            Self::destroy(id)
137        }
138    }
139    fn destroy(id: u64) {
140        THREAD_LOCAL_INSTANCE_HANDLES.with(|map| {
141            let mut map = map.borrow_mut();
142            map.remove(&id);
143        })
144    }
145}
146
147/// This provides access to the memory inside the instance
148pub(crate) struct WasiInstanceGuardMemory<'a> {
149    // the order is very important as the first value is
150    // dropped before the reference count is dropped
151    borrow: &'a Memory,
152    _guard: WasiInstanceGuard<'a>,
153}
154impl Deref for WasiInstanceGuardMemory<'_> {
155    type Target = Memory;
156    fn deref(&self) -> &Self::Target {
157        self.borrow
158    }
159}
160impl<'a> WasiInstanceGuard<'a> {
161    pub fn memory(self) -> WasiInstanceGuardMemory<'a> {
162        let borrow: &Memory = (*self).memory();
163        let borrow: &'a Memory = unsafe { std::mem::transmute(borrow) };
164        WasiInstanceGuardMemory {
165            borrow,
166            _guard: self,
167        }
168    }
169}