WASM In Jobs
The wrapper code which Wasmbox automatically generates is designed to work within the Unity Job safety system. A wrapper requires write access for every operation, so it can only be used within one single job.
1. Define a Job
Create a new IJob
struct:
public struct DemoJob
: IJob
{
private AutogeneratedScriptName _wrapper;
public WasmWrapperJob(AutogeneratedScriptName wrapper)
{
_wrapper = wrapper;
}
public void Execute()
{
_wrapper.CallSomeWasmFunction();
}
}
2. Schedule Job
Schedule the Job with the Unity safety system. Once the Job has completed call handle.Complete()
to be able to use the wrapper in the main thread again.
var handle = new DemoJob(the_wrapper).Schedule();
// Wait a while
// Do other work...
// You **must** call `handle.Complete()` before accessing the wrapper
handle.Complete();
// You may now use the wrapper in non-job code
the_wrapper.CallSomeWasmFunction();
3. Epochs (Optional)
You may want to put a limit on how long WASM code can run for in a job. This can be done with Epoch Interruption
.
To setup epoch interruption:
- Call
SetEpochDeadline(the_deadline)
on the store. - Get an
EpochHandle
from theEngineConfig
. - Start the job.
- While the job is running call
SetEpoch
on theEpochHandle
(for example every frame). - If the epoch you set is higher than the deadline the code will immediately terminate execution.
Thread Safety
By using the Linker
it is easy to accidentally bypass the safety system through WASM code. For example this code keeps a counter in a non-threadsafe way:
int counter = 1;
linker.DefineFunction("this_is_bad", "accumulate_not_threadsafe", (int a) => {
counter += a;
return counter;
});
If this same Linker
is used to create two WASM instances and those instances are both scheduled to run in Jobs simultaneously it would be possible to corrupt this counter.
If you are going to schedule WASM code to run in jobs everything defined in the Linker
must be threadsafe.
A simple modification to the above code which makes it threadsafe is to add a lock:
var safety = new object();
int counter = 1;
linker.DefineFunction("this_is_ok", "accumulate_safe", (int a) => {
lock (safety)
{
counter += a;
return counter;
}
});