1use super::ffi;
4#[cfg(all(feature = "async", target_os = "linux"))]
5use crate::r#async::fiber::{AsyncState, FiberFuture};
6
7#[cfg(all(feature = "async", target_os = "linux", not(target_env = "musl")))]
8use crate::r#async::fiber::TimeoutFiberFuture;
9
10use crate::{
11 instance::{function::AsFunc, module::InnerInstance},
12 store::Store,
13 types::WasmEdgeString,
14 utils::check,
15 AsInstance, Config, Function, Instance, Module, Statistics, WasmEdgeResult, WasmValue,
16};
17#[cfg(all(target_os = "linux", not(target_env = "musl")))]
18use std::os::raw::c_void;
19use wasmedge_types::error::WasmEdgeError;
20
21#[cfg(all(target_os = "linux", not(target_env = "musl")))]
22pub(crate) struct JmpState {
23 pub(crate) sigjmp_buf: *mut setjmp::sigjmp_buf,
24}
25
26#[cfg(all(target_os = "linux", not(target_env = "musl")))]
27scoped_tls::scoped_thread_local!(pub(crate) static JMP_BUF: JmpState);
28
29#[cfg(all(target_os = "linux", not(target_env = "musl")))]
30unsafe extern "C" fn sync_timeout(sig: i32, info: *mut libc::siginfo_t) {
31 if let Some(info) = info.as_mut() {
32 let si_value = info.si_value();
33 let value: *mut libc::pthread_t = si_value.sival_ptr.cast();
34 let dist_pthread = *value;
35 let self_pthread = libc::pthread_self();
36 if self_pthread == dist_pthread {
37 if JMP_BUF.is_set() {
38 let env = JMP_BUF.with(|s| s.sigjmp_buf);
39 setjmp::siglongjmp(env, 1);
40 }
41 } else {
42 libc::pthread_sigqueue(dist_pthread, sig, si_value);
43 }
44 }
45}
46#[cfg(all(target_os = "linux", not(target_env = "musl")))]
47unsafe extern "C" fn pre_host_func(_: *mut c_void) {
48 use libc::SIG_BLOCK;
49
50 let mut set = std::mem::zeroed();
51 libc::sigemptyset(&mut set);
52 libc::sigaddset(&mut set, timeout_signo());
53 libc::pthread_sigmask(SIG_BLOCK, &set, std::ptr::null_mut());
54}
55#[cfg(all(target_os = "linux", not(target_env = "musl")))]
56unsafe extern "C" fn post_host_func(_: *mut c_void) {
57 use libc::SIG_UNBLOCK;
58
59 let mut set = std::mem::zeroed();
60 libc::sigemptyset(&mut set);
61 libc::sigaddset(&mut set, timeout_signo());
62 libc::pthread_sigmask(SIG_UNBLOCK, &set, std::ptr::null_mut());
63}
64
65#[inline]
66#[cfg(all(target_os = "linux", not(target_env = "musl")))]
67pub(crate) fn timeout_signo() -> i32 {
68 option_env!("SIG_OFFSET")
69 .and_then(|s| s.parse().ok())
70 .unwrap_or(0)
71 + libc::SIGRTMIN()
72}
73
74#[cfg(all(target_os = "linux", not(target_env = "musl")))]
75static INIT_SIGNAL_LISTEN: std::sync::Once = std::sync::Once::new();
76
77#[inline(always)]
78#[cfg(all(target_os = "linux", not(target_env = "musl")))]
79pub(crate) unsafe fn init_signal_listen() {
80 INIT_SIGNAL_LISTEN.call_once(|| {
81 let mut new_act: libc::sigaction = std::mem::zeroed();
82 new_act.sa_sigaction = sync_timeout as *const () as usize;
83 new_act.sa_flags = libc::SA_RESTART | libc::SA_SIGINFO;
84 libc::sigaction(timeout_signo(), &new_act, std::ptr::null_mut());
85 });
86}
87
88#[derive(Debug)]
90pub struct Executor {
91 pub(crate) inner: InnerExecutor,
92}
93
94impl Drop for Executor {
95 fn drop(&mut self) {
96 unsafe { ffi::WasmEdge_ExecutorDelete(self.inner.0) }
97 }
98}
99
100impl Executor {
101 pub fn create(config: Option<&Config>, stat: Option<Statistics>) -> WasmEdgeResult<Self> {
113 let conf_ctx = config
114 .map(|cfg| cfg.inner.0)
115 .unwrap_or(std::ptr::null_mut());
116 let stat_ctx = stat
117 .map(|stat| stat.inner.0)
118 .unwrap_or(std::ptr::null_mut());
119
120 let ctx = unsafe { ffi::WasmEdge_ExecutorCreate(conf_ctx, stat_ctx) };
121
122 if ctx.is_null() {
123 Err(Box::new(WasmEdgeError::ExecutorCreate))
124 } else {
125 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
126 unsafe {
127 ffi::WasmEdge_ExecutorExperimentalRegisterPreHostFunction(
128 ctx,
129 std::ptr::null_mut(),
130 Some(pre_host_func),
131 );
132 ffi::WasmEdge_ExecutorExperimentalRegisterPostHostFunction(
133 ctx,
134 std::ptr::null_mut(),
135 Some(post_host_func),
136 );
137 }
138
139 Ok(Executor {
140 inner: InnerExecutor(ctx),
141 })
142 }
143 }
144}
145
146impl Executor {
147 pub fn call_func(
159 &mut self,
160 func: &mut Function,
161 params: impl IntoIterator<Item = WasmValue>,
162 ) -> WasmEdgeResult<Vec<WasmValue>> {
163 let raw_params = params.into_iter().map(|x| x.as_raw()).collect::<Vec<_>>();
164
165 let func_ty = func
167 .ty()
168 .ok_or(WasmEdgeError::Func(wasmedge_types::error::FuncError::Type))?;
169 let returns_len = func_ty.returns_len();
170 let mut returns = Vec::with_capacity(returns_len);
171
172 unsafe {
173 check(ffi::WasmEdge_ExecutorInvoke(
174 self.inner.0,
175 func.get_func_raw(),
176 raw_params.as_ptr(),
177 raw_params.len() as u32,
178 returns.as_mut_ptr(),
179 returns_len as u32,
180 ))?;
181
182 returns.set_len(returns_len);
183 }
184
185 Ok(returns.into_iter().map(Into::into).collect::<Vec<_>>())
186 }
187
188 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
202 #[cfg_attr(docsrs, doc(cfg(all(target_os = "linux", not(target_env = "musl")))))]
203 pub fn call_func_with_timeout(
204 &self,
205 func: &mut Function,
206 params: impl IntoIterator<Item = WasmValue>,
207 timeout: std::time::Duration,
208 ) -> WasmEdgeResult<Vec<WasmValue>> {
209 use wasmedge_types::error;
210
211 let raw_params = params.into_iter().map(|x| x.as_raw()).collect::<Vec<_>>();
212 let func_ty = func
214 .ty()
215 .ok_or(WasmEdgeError::Func(wasmedge_types::error::FuncError::Type))?;
216 let returns_len = func_ty.returns_len();
217 let mut returns = Vec::with_capacity(returns_len);
218
219 unsafe {
220 init_signal_listen();
221 let mut self_thread = libc::pthread_self();
222 let mut sigjmp_buf: setjmp::sigjmp_buf = std::mem::zeroed();
223 let env = &mut sigjmp_buf as *mut _;
224
225 let mut timerid: libc::timer_t = std::mem::zeroed();
226 let mut sev: libc::sigevent = std::mem::zeroed();
227 sev.sigev_notify = libc::SIGEV_SIGNAL;
228 sev.sigev_signo = timeout_signo();
229 sev.sigev_value.sival_ptr = &mut self_thread as *mut _ as *mut libc::c_void;
230
231 if libc::timer_create(libc::CLOCK_REALTIME, &mut sev, &mut timerid) < 0 {
232 return Err(Box::new(error::WasmEdgeError::Operation(
233 "timer_create error".into(),
234 )));
235 }
236 let mut value: libc::itimerspec = std::mem::zeroed();
237 value.it_value.tv_sec = timeout.as_secs() as _;
238 value.it_value.tv_nsec = timeout.subsec_nanos() as _;
239 if libc::timer_settime(timerid, 0, &value, std::ptr::null_mut()) < 0 {
240 libc::timer_delete(timerid);
241 return Err(Box::new(error::WasmEdgeError::Operation(
242 "timer_settime error".into(),
243 )));
244 }
245 let jmp_state = JmpState { sigjmp_buf: env };
246
247 JMP_BUF.set(&jmp_state, || {
248 if setjmp::sigsetjmp(env, 1) == 0 {
249 let r = check(ffi::WasmEdge_ExecutorInvoke(
250 self.inner.0,
251 func.get_func_raw(),
252 raw_params.as_ptr(),
253 raw_params.len() as u32,
254 returns.as_mut_ptr(),
255 returns_len as u32,
256 ));
257 libc::timer_delete(timerid);
258 r
259 } else {
260 libc::timer_delete(timerid);
261 Err(Box::new(error::WasmEdgeError::ExecuteTimeout))
262 }
263 })?;
264
265 returns.set_len(returns_len);
266 Ok(returns.into_iter().map(Into::into).collect::<Vec<_>>())
267 }
268 }
269
270 #[cfg(all(feature = "async", target_os = "linux"))]
284 #[cfg_attr(docsrs, doc(cfg(all(feature = "async", target_os = "linux"))))]
285 pub async fn call_func_async(
286 &mut self,
287 async_state: &AsyncState,
288 func: &mut Function,
289 params: impl IntoIterator<Item = WasmValue> + Send,
290 ) -> WasmEdgeResult<Vec<WasmValue>> {
291 FiberFuture::on_fiber(async_state, || self.call_func(func, params))
292 .await
293 .unwrap()
294 }
295
296 #[cfg(all(feature = "async", target_os = "linux", not(target_env = "musl")))]
312 #[cfg_attr(
313 docsrs,
314 doc(cfg(all(feature = "async", target_os = "linux", not(target_env = "musl"))))
315 )]
316 pub async fn call_func_async_with_timeout(
317 &mut self,
318 async_state: &AsyncState,
319 func: &mut Function,
320 params: impl IntoIterator<Item = WasmValue> + Send,
321 timeout: std::time::Duration,
322 ) -> WasmEdgeResult<Vec<WasmValue>> {
323 use wasmedge_types::error;
324 let ldd = std::time::SystemTime::now() + timeout;
325 TimeoutFiberFuture::on_fiber(async_state, || self.call_func(func, params), ldd)
326 .await
327 .map_err(|_| Box::new(error::WasmEdgeError::ExecuteTimeout))?
328 }
329
330 pub fn call_func_ref<FuncRef: AsFunc>(
342 &mut self,
343 func_ref: &mut FuncRef,
344 params: impl IntoIterator<Item = WasmValue>,
345 ) -> WasmEdgeResult<Vec<WasmValue>> {
346 let raw_params = params.into_iter().map(|x| x.as_raw()).collect::<Vec<_>>();
347
348 let func_ty = func_ref.ty().unwrap();
350 let returns_len = func_ty.returns_len();
351 let mut returns = Vec::with_capacity(returns_len);
352
353 unsafe {
354 check(ffi::WasmEdge_ExecutorInvoke(
355 self.inner.0,
356 func_ref.get_func_raw(),
357 raw_params.as_ptr(),
358 raw_params.len() as u32,
359 returns.as_mut_ptr(),
360 returns_len as u32,
361 ))?;
362 returns.set_len(returns_len);
363 }
364
365 Ok(returns.into_iter().map(Into::into).collect::<Vec<_>>())
366 }
367
368 #[cfg(all(feature = "async", target_os = "linux"))]
382 #[cfg_attr(docsrs, doc(cfg(all(feature = "async", target_os = "linux"))))]
383 pub async fn call_func_ref_async<FuncRef: AsFunc + Send>(
384 &mut self,
385 async_state: &AsyncState,
386 func_ref: &mut FuncRef,
387 params: impl IntoIterator<Item = WasmValue> + Send,
388 ) -> WasmEdgeResult<Vec<WasmValue>> {
389 FiberFuture::on_fiber(async_state, || self.call_func_ref(func_ref, params))
390 .await
391 .unwrap()
392 }
393}
394
395impl Executor {
396 pub fn register_import_module<T: AsInstance + ?Sized>(
408 &mut self,
409 store: &mut Store,
410 import: &T,
411 ) -> WasmEdgeResult<()> {
412 unsafe {
413 check(ffi::WasmEdge_ExecutorRegisterImport(
414 self.inner.0,
415 store.inner.0,
416 import.as_ptr(),
417 ))?;
418 }
419
420 Ok(())
421 }
422
423 pub fn register_named_module(
439 &mut self,
440 store: &mut Store,
441 module: &Module,
442 name: impl AsRef<str>,
443 ) -> WasmEdgeResult<Instance> {
444 let mut instance_ctx = std::ptr::null_mut();
445 let mod_name: WasmEdgeString = name.as_ref().into();
446 unsafe {
447 check(ffi::WasmEdge_ExecutorRegister(
448 self.inner.0,
449 &mut instance_ctx,
450 store.inner.0,
451 module.inner.0 as *const _,
452 mod_name.as_raw(),
453 ))?;
454
455 let inst = Instance {
456 inner: InnerInstance(instance_ctx),
457 };
458
459 Ok(inst)
460 }
461 }
462
463 pub fn register_active_module(
478 &mut self,
479 store: &mut Store,
480 module: &Module,
481 ) -> WasmEdgeResult<Instance> {
482 let mut instance_ctx = std::ptr::null_mut();
483 unsafe {
484 check(ffi::WasmEdge_ExecutorInstantiate(
485 self.inner.0,
486 &mut instance_ctx,
487 store.inner.0,
488 module.inner.0 as *const _,
489 ))?;
490
491 let inst = Instance {
492 inner: InnerInstance(instance_ctx),
493 };
494
495 Ok(inst)
496 }
497 }
498}
499
500#[derive(Debug, Clone)]
501pub(crate) struct InnerExecutor(pub(crate) *mut ffi::WasmEdge_ExecutorContext);
502unsafe impl Send for InnerExecutor {}
503unsafe impl Sync for InnerExecutor {}