Difference between revisions of "WebAssembly/Threads"

From Lazarus wiki
Jump to navigationJump to search
(→‎Atomic instructions: - there's now a new compiler option to enable WASM threads: -CTwasmthreads, it should be used to compile the RTL, instead of -dFPC_WASM_THREADS)
(→‎Atomic instructions: - atomic functions are available in the WebAssembly unit)
Line 22: Line 22:
  
 
Note that these require proper alignment (4 bytes) of the target, otherwise they trap (i.e. terminate the program with a stack trace).
 
Note that these require proper alignment (4 bytes) of the target, otherwise they trap (i.e. terminate the program with a stack trace).
 +
 +
In addition to that, there are many more atomic functions available in the WebAssembly unit:
 +
 +
const
 +
  { Special values for the TimeoutNanoseconds parameter of AtomicWait }
 +
  awtInfiniteTimeout = -1;
 +
  { AtomicWait result values }
 +
  awrOk = 0;      { woken by another agent in the cluster }
 +
  awrNotEqual = 1; { the loaded value did not match the expected value }
 +
  awrTimedOut = 2; { not woken before timeout expired }
 +
 +
procedure AtomicFence; inline;
 +
 +
function AtomicLoad(constref Mem: Int8): Int8; inline;
 +
function AtomicLoad(constref Mem: UInt8): UInt8; inline;
 +
function AtomicLoad(constref Mem: Int16): Int16; inline;
 +
function AtomicLoad(constref Mem: UInt16): UInt16; inline;
 +
function AtomicLoad(constref Mem: Int32): Int32; inline;
 +
function AtomicLoad(constref Mem: UInt32): UInt32; inline;
 +
function AtomicLoad(constref Mem: Int64): Int64; inline;
 +
function AtomicLoad(constref Mem: UInt64): UInt64; inline;
 +
 +
procedure AtomicStore(out Mem: Int8; Data: Int8); inline;
 +
procedure AtomicStore(out Mem: UInt8; Data: UInt8); inline;
 +
procedure AtomicStore(out Mem: Int16; Data: Int16); inline;
 +
procedure AtomicStore(out Mem: UInt16; Data: UInt16); inline;
 +
procedure AtomicStore(out Mem: Int32; Data: Int32); inline;
 +
procedure AtomicStore(out Mem: UInt32; Data: UInt32); inline;
 +
procedure AtomicStore(out Mem: Int64; Data: Int64); inline;
 +
procedure AtomicStore(out Mem: UInt64; Data: UInt64); inline;
 +
 +
function AtomicAdd(var Mem: Int8; Data: Int8): Int8; inline;
 +
function AtomicAdd(var Mem: UInt8; Data: UInt8): UInt8; inline;
 +
function AtomicAdd(var Mem: Int16; Data: Int16): Int16; inline;
 +
function AtomicAdd(var Mem: UInt16; Data: UInt16): UInt16; inline;
 +
function AtomicAdd(var Mem: Int32; Data: Int32): Int32; inline;
 +
function AtomicAdd(var Mem: UInt32; Data: UInt32): UInt32; inline;
 +
function AtomicAdd(var Mem: Int64; Data: Int64): Int64; inline;
 +
function AtomicAdd(var Mem: UInt64; Data: UInt64): UInt64; inline;
 +
 +
function AtomicSub(var Mem: Int8; Data: Int8): Int8; inline;
 +
function AtomicSub(var Mem: UInt8; Data: UInt8): UInt8; inline;
 +
function AtomicSub(var Mem: Int16; Data: Int16): Int16; inline;
 +
function AtomicSub(var Mem: UInt16; Data: UInt16): UInt16; inline;
 +
function AtomicSub(var Mem: Int32; Data: Int32): Int32; inline;
 +
function AtomicSub(var Mem: UInt32; Data: UInt32): UInt32; inline;
 +
function AtomicSub(var Mem: Int64; Data: Int64): Int64; inline;
 +
function AtomicSub(var Mem: UInt64; Data: UInt64): UInt64; inline;
 +
 +
function AtomicAnd(var Mem: Int8; Data: Int8): Int8; inline;
 +
function AtomicAnd(var Mem: UInt8; Data: UInt8): UInt8; inline;
 +
function AtomicAnd(var Mem: Int16; Data: Int16): Int16; inline;
 +
function AtomicAnd(var Mem: UInt16; Data: UInt16): UInt16; inline;
 +
function AtomicAnd(var Mem: Int32; Data: Int32): Int32; inline;
 +
function AtomicAnd(var Mem: UInt32; Data: UInt32): UInt32; inline;
 +
function AtomicAnd(var Mem: Int64; Data: Int64): Int64; inline;
 +
function AtomicAnd(var Mem: UInt64; Data: UInt64): UInt64; inline;
 +
 +
function AtomicOr(var Mem: Int8; Data: Int8): Int8; inline;
 +
function AtomicOr(var Mem: UInt8; Data: UInt8): UInt8; inline;
 +
function AtomicOr(var Mem: Int16; Data: Int16): Int16; inline;
 +
function AtomicOr(var Mem: UInt16; Data: UInt16): UInt16; inline;
 +
function AtomicOr(var Mem: Int32; Data: Int32): Int32; inline;
 +
function AtomicOr(var Mem: UInt32; Data: UInt32): UInt32; inline;
 +
function AtomicOr(var Mem: Int64; Data: Int64): Int64; inline;
 +
function AtomicOr(var Mem: UInt64; Data: UInt64): UInt64; inline;
 +
 +
function AtomicXor(var Mem: Int8; Data: Int8): Int8; inline;
 +
function AtomicXor(var Mem: UInt8; Data: UInt8): UInt8; inline;
 +
function AtomicXor(var Mem: Int16; Data: Int16): Int16; inline;
 +
function AtomicXor(var Mem: UInt16; Data: UInt16): UInt16; inline;
 +
function AtomicXor(var Mem: Int32; Data: Int32): Int32; inline;
 +
function AtomicXor(var Mem: UInt32; Data: UInt32): UInt32; inline;
 +
function AtomicXor(var Mem: Int64; Data: Int64): Int64; inline;
 +
function AtomicXor(var Mem: UInt64; Data: UInt64): UInt64; inline;
 +
 +
function AtomicExchange(var Mem: Int8; Data: Int8): Int8; inline;
 +
function AtomicExchange(var Mem: UInt8; Data: UInt8): UInt8; inline;
 +
function AtomicExchange(var Mem: Int16; Data: Int16): Int16; inline;
 +
function AtomicExchange(var Mem: UInt16; Data: UInt16): UInt16; inline;
 +
function AtomicExchange(var Mem: Int32; Data: Int32): Int32; inline;
 +
function AtomicExchange(var Mem: UInt32; Data: UInt32): UInt32; inline;
 +
function AtomicExchange(var Mem: Int64; Data: Int64): Int64; inline;
 +
function AtomicExchange(var Mem: UInt64; Data: UInt64): UInt64; inline;
 +
 +
function AtomicCompareExchange(var Mem: Int8; Compare, Data: Int8): Int8; inline;
 +
function AtomicCompareExchange(var Mem: UInt8; Compare, Data: UInt8): UInt8; inline;
 +
function AtomicCompareExchange(var Mem: Int16; Compare, Data: Int16): Int16; inline;
 +
function AtomicCompareExchange(var Mem: UInt16; Compare, Data: UInt16): UInt16; inline;
 +
function AtomicCompareExchange(var Mem: Int32; Compare, Data: Int32): Int32; inline;
 +
function AtomicCompareExchange(var Mem: UInt32; Compare, Data: UInt32): UInt32; inline;
 +
function AtomicCompareExchange(var Mem: Int64; Compare, Data: Int64): Int64; inline;
 +
function AtomicCompareExchange(var Mem: UInt64; Compare, Data: UInt64): UInt64; inline;
 +
 +
function AtomicWait(constref Mem: Int32; Compare: Int32; TimeoutNanoseconds: Int64): Int32; inline;
 +
function AtomicWait(constref Mem: UInt32; Compare: UInt32; TimeoutNanoseconds: Int64): Int32; inline;
 +
function AtomicWait(constref Mem: Int64; Compare: Int64; TimeoutNanoseconds: Int64): Int32; inline;
 +
function AtomicWait(constref Mem: UInt64; Compare: UInt64; TimeoutNanoseconds: Int64): Int32; inline;
 +
 +
function AtomicNotify(constref Mem: Int32; Count: UInt32): UInt32; inline;
 +
function AtomicNotify(constref Mem: UInt32; Count: UInt32): UInt32; inline;
 +
function AtomicNotify(constref Mem: Int64; Count: UInt32): UInt32; inline;
 +
function AtomicNotify(constref Mem: UInt64; Count: UInt32): UInt32; inline;
  
 
== Thread support ==
 
== Thread support ==

Revision as of 00:35, 28 May 2022

Thread support

This page contains some collected informations on the features needed for thread support in WebAssembly (in the browser).

Thread support consists of 2 parts:

  • Atomic instructions.
  • Actually starting a thread.


Atomic instructions

The proposed specs 

When the Free Pascal RTL is compiled with -CTwasmthreads, the following RTL functions will use the new atomic instructions and thus should be thread safe in a multithreaded environment:

InterlockedDecrement
InterlockedIncrement
InterlockedExchange
InterlockedCompareExchange
InterlockedExchangeAdd

Note that these require proper alignment (4 bytes) of the target, otherwise they trap (i.e. terminate the program with a stack trace).

In addition to that, there are many more atomic functions available in the WebAssembly unit:

const
  { Special values for the TimeoutNanoseconds parameter of AtomicWait }
  awtInfiniteTimeout = -1;
  { AtomicWait result values }
  awrOk = 0;       { woken by another agent in the cluster }
  awrNotEqual = 1; { the loaded value did not match the expected value }
  awrTimedOut = 2; { not woken before timeout expired }

procedure AtomicFence; inline;

function AtomicLoad(constref Mem: Int8): Int8; inline;
function AtomicLoad(constref Mem: UInt8): UInt8; inline;
function AtomicLoad(constref Mem: Int16): Int16; inline;
function AtomicLoad(constref Mem: UInt16): UInt16; inline;
function AtomicLoad(constref Mem: Int32): Int32; inline;
function AtomicLoad(constref Mem: UInt32): UInt32; inline;
function AtomicLoad(constref Mem: Int64): Int64; inline;
function AtomicLoad(constref Mem: UInt64): UInt64; inline;

procedure AtomicStore(out Mem: Int8; Data: Int8); inline;
procedure AtomicStore(out Mem: UInt8; Data: UInt8); inline;
procedure AtomicStore(out Mem: Int16; Data: Int16); inline;
procedure AtomicStore(out Mem: UInt16; Data: UInt16); inline;
procedure AtomicStore(out Mem: Int32; Data: Int32); inline;
procedure AtomicStore(out Mem: UInt32; Data: UInt32); inline;
procedure AtomicStore(out Mem: Int64; Data: Int64); inline;
procedure AtomicStore(out Mem: UInt64; Data: UInt64); inline;

function AtomicAdd(var Mem: Int8; Data: Int8): Int8; inline;
function AtomicAdd(var Mem: UInt8; Data: UInt8): UInt8; inline;
function AtomicAdd(var Mem: Int16; Data: Int16): Int16; inline;
function AtomicAdd(var Mem: UInt16; Data: UInt16): UInt16; inline;
function AtomicAdd(var Mem: Int32; Data: Int32): Int32; inline;
function AtomicAdd(var Mem: UInt32; Data: UInt32): UInt32; inline;
function AtomicAdd(var Mem: Int64; Data: Int64): Int64; inline;
function AtomicAdd(var Mem: UInt64; Data: UInt64): UInt64; inline;

function AtomicSub(var Mem: Int8; Data: Int8): Int8; inline;
function AtomicSub(var Mem: UInt8; Data: UInt8): UInt8; inline;
function AtomicSub(var Mem: Int16; Data: Int16): Int16; inline;
function AtomicSub(var Mem: UInt16; Data: UInt16): UInt16; inline;
function AtomicSub(var Mem: Int32; Data: Int32): Int32; inline;
function AtomicSub(var Mem: UInt32; Data: UInt32): UInt32; inline;
function AtomicSub(var Mem: Int64; Data: Int64): Int64; inline;
function AtomicSub(var Mem: UInt64; Data: UInt64): UInt64; inline;

function AtomicAnd(var Mem: Int8; Data: Int8): Int8; inline;
function AtomicAnd(var Mem: UInt8; Data: UInt8): UInt8; inline;
function AtomicAnd(var Mem: Int16; Data: Int16): Int16; inline;
function AtomicAnd(var Mem: UInt16; Data: UInt16): UInt16; inline;
function AtomicAnd(var Mem: Int32; Data: Int32): Int32; inline;
function AtomicAnd(var Mem: UInt32; Data: UInt32): UInt32; inline;
function AtomicAnd(var Mem: Int64; Data: Int64): Int64; inline;
function AtomicAnd(var Mem: UInt64; Data: UInt64): UInt64; inline;

function AtomicOr(var Mem: Int8; Data: Int8): Int8; inline;
function AtomicOr(var Mem: UInt8; Data: UInt8): UInt8; inline;
function AtomicOr(var Mem: Int16; Data: Int16): Int16; inline;
function AtomicOr(var Mem: UInt16; Data: UInt16): UInt16; inline;
function AtomicOr(var Mem: Int32; Data: Int32): Int32; inline;
function AtomicOr(var Mem: UInt32; Data: UInt32): UInt32; inline;
function AtomicOr(var Mem: Int64; Data: Int64): Int64; inline;
function AtomicOr(var Mem: UInt64; Data: UInt64): UInt64; inline;

function AtomicXor(var Mem: Int8; Data: Int8): Int8; inline;
function AtomicXor(var Mem: UInt8; Data: UInt8): UInt8; inline;
function AtomicXor(var Mem: Int16; Data: Int16): Int16; inline;
function AtomicXor(var Mem: UInt16; Data: UInt16): UInt16; inline;
function AtomicXor(var Mem: Int32; Data: Int32): Int32; inline;
function AtomicXor(var Mem: UInt32; Data: UInt32): UInt32; inline;
function AtomicXor(var Mem: Int64; Data: Int64): Int64; inline;
function AtomicXor(var Mem: UInt64; Data: UInt64): UInt64; inline;

function AtomicExchange(var Mem: Int8; Data: Int8): Int8; inline;
function AtomicExchange(var Mem: UInt8; Data: UInt8): UInt8; inline;
function AtomicExchange(var Mem: Int16; Data: Int16): Int16; inline;
function AtomicExchange(var Mem: UInt16; Data: UInt16): UInt16; inline;
function AtomicExchange(var Mem: Int32; Data: Int32): Int32; inline;
function AtomicExchange(var Mem: UInt32; Data: UInt32): UInt32; inline;
function AtomicExchange(var Mem: Int64; Data: Int64): Int64; inline;
function AtomicExchange(var Mem: UInt64; Data: UInt64): UInt64; inline;

function AtomicCompareExchange(var Mem: Int8; Compare, Data: Int8): Int8; inline;
function AtomicCompareExchange(var Mem: UInt8; Compare, Data: UInt8): UInt8; inline;
function AtomicCompareExchange(var Mem: Int16; Compare, Data: Int16): Int16; inline;
function AtomicCompareExchange(var Mem: UInt16; Compare, Data: UInt16): UInt16; inline;
function AtomicCompareExchange(var Mem: Int32; Compare, Data: Int32): Int32; inline;
function AtomicCompareExchange(var Mem: UInt32; Compare, Data: UInt32): UInt32; inline;
function AtomicCompareExchange(var Mem: Int64; Compare, Data: Int64): Int64; inline;
function AtomicCompareExchange(var Mem: UInt64; Compare, Data: UInt64): UInt64; inline;

function AtomicWait(constref Mem: Int32; Compare: Int32; TimeoutNanoseconds: Int64): Int32; inline;
function AtomicWait(constref Mem: UInt32; Compare: UInt32; TimeoutNanoseconds: Int64): Int32; inline;
function AtomicWait(constref Mem: Int64; Compare: Int64; TimeoutNanoseconds: Int64): Int32; inline;
function AtomicWait(constref Mem: UInt64; Compare: UInt64; TimeoutNanoseconds: Int64): Int32; inline;

function AtomicNotify(constref Mem: Int32; Count: UInt32): UInt32; inline;
function AtomicNotify(constref Mem: UInt32; Count: UInt32): UInt32; inline;
function AtomicNotify(constref Mem: Int64; Count: UInt32): UInt32; inline;
function AtomicNotify(constref Mem: UInt64; Count: UInt32): UInt32; inline;

Thread support

Webassembly relies on the hosting environment to actually start threads.

Some extra info: