@@ -22,14 +22,96 @@ long innerPtr() {
2222 /// By default this option is `false`.
2323 public native Config debugInfo (boolean enable );
2424
25- /// Configures whether functions and loops will be interruptable via the
26- /// [`Store::interruptHandle`] method.
27- ///
28- /// For more information see the documentation on
29- /// [`Store::interruptHandle`].
30- ///
31- /// By default this option is `false`.
32- public native Config interruptable (boolean enable );
25+ /// Enables epoch-based interruption.
26+ ///
27+ /// When executing code in async mode, we sometimes want to
28+ /// implement a form of cooperative timeslicing: long-running Wasm
29+ /// guest code should periodically yield to the executor
30+ /// loop. This yielding could be implemented by using "fuel" (see
31+ /// [`consume_fuel`](Config::consume_fuel)). However, fuel
32+ /// instrumentation is somewhat expensive: it modifies the
33+ /// compiled form of the Wasm code so that it maintains a precise
34+ /// instruction count, frequently checking this count against the
35+ /// remaining fuel. If one does not need this precise count or
36+ /// deterministic interruptions, and only needs a periodic
37+ /// interrupt of some form, then It would be better to have a more
38+ /// lightweight mechanism.
39+ ///
40+ /// Epoch-based interruption is that mechanism. There is a global
41+ /// "epoch", which is a counter that divides time into arbitrary
42+ /// periods (or epochs). This counter lives on the
43+ /// [`Engine`](crate::Engine) and can be incremented by calling
44+ /// [`Engine::increment_epoch`](crate::Engine::increment_epoch).
45+ /// Epoch-based instrumentation works by setting a "deadline
46+ /// epoch". The compiled code knows the deadline, and at certain
47+ /// points, checks the current epoch against that deadline. It
48+ /// will yield if the deadline has been reached.
49+ ///
50+ /// The idea is that checking an infrequently-changing counter is
51+ /// cheaper than counting and frequently storing a precise metric
52+ /// (instructions executed) locally. The interruptions are not
53+ /// deterministic, but if the embedder increments the epoch in a
54+ /// periodic way (say, every regular timer tick by a thread or
55+ /// signal handler), then we can ensure that all async code will
56+ /// yield to the executor within a bounded time.
57+ ///
58+ /// The deadline check cannot be avoided by malicious wasm code. It is safe
59+ /// to use epoch deadlines to limit the execution time of untrusted
60+ /// code.
61+ ///
62+ /// The [`Store`](crate::Store) tracks the deadline, and controls
63+ /// what happens when the deadline is reached during
64+ /// execution. Several behaviors are possible:
65+ ///
66+ /// - Trap if code is executing when the epoch deadline is
67+ /// met. See
68+ /// [`Store::epoch_deadline_trap`](crate::Store::epoch_deadline_trap).
69+ ///
70+ /// - Call an arbitrary function. This function may chose to trap or
71+ /// increment the epoch. See
72+ /// [`Store::epoch_deadline_callback`](crate::Store::epoch_deadline_callback).
73+ ///
74+ /// - Yield to the executor loop, then resume when the future is
75+ /// next polled. See
76+ /// [`Store::epoch_deadline_async_yield_and_update`](crate::Store::epoch_deadline_async_yield_and_update).
77+ ///
78+ /// Trapping is the default. The yielding behaviour may be used for
79+ /// the timeslicing behavior described above.
80+ ///
81+ /// This feature is available with or without async support.
82+ /// However, without async support, the timeslicing behaviour is
83+ /// not available. This means epoch-based interruption can only
84+ /// serve as a simple external-interruption mechanism.
85+ ///
86+ /// An initial deadline must be set before executing code by calling
87+ /// [`Store::set_epoch_deadline`](crate::Store::set_epoch_deadline). If this
88+ /// deadline is not configured then wasm will immediately trap.
89+ ///
90+ /// ## When to use fuel vs. epochs
91+ ///
92+ /// In general, epoch-based interruption results in faster
93+ /// execution. This difference is sometimes significant: in some
94+ /// measurements, up to 2-3x. This is because epoch-based
95+ /// interruption does less work: it only watches for a global
96+ /// rarely-changing counter to increment, rather than keeping a
97+ /// local frequently-changing counter and comparing it to a
98+ /// deadline.
99+ ///
100+ /// Fuel, in contrast, should be used when *deterministic*
101+ /// yielding or trapping is needed. For example, if it is required
102+ /// that the same function call with the same starting state will
103+ /// always either complete or trap with an out-of-fuel error,
104+ /// deterministically, then fuel with a fixed bound should be
105+ /// used.
106+ ///
107+ /// # See Also
108+ ///
109+ /// - [`Engine::increment_epoch`](crate::Engine::increment_epoch)
110+ /// - [`Store::set_epoch_deadline`](crate::Store::set_epoch_deadline)
111+ /// - [`Store::epoch_deadline_trap`](crate::Store::epoch_deadline_trap)
112+ /// - [`Store::epoch_deadline_callback`](crate::Store::epoch_deadline_callback)
113+ /// - [`Store::epoch_deadline_async_yield_and_update`](crate::Store::epoch_deadline_async_yield_and_update)
114+ public native Config epochInterruption (boolean enable );
33115
34116 /// Configures the maximum amount of native stack space available to
35117 /// executing WebAssembly code.
0 commit comments