Skip to main content

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:

  1. Call SetEpochDeadline(the_deadline) on the store.
  2. Get an EpochHandle from the EngineConfig.
  3. Start the job.
  4. While the job is running call SetEpoch on the EpochHandle (for example every frame).
  5. 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.

danger

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;
}
});