Browse Source

+ WebAssembly threads: implemented basic events (both manual and auto reset)

Nikolay Nikolov 1 year ago
parent
commit
edf7b26f52
1 changed files with 201 additions and 6 deletions
  1. 201 6
      rtl/wasi/systhrd.inc

+ 201 - 6
rtl/wasi/systhrd.inc

@@ -643,31 +643,226 @@ end;
   Basic event
   ----------------------------------------------------------------------}
 
-
+const
+  wrSignaled  = 0;
+  wrTimeout   = 1;
+  wrAbandoned = 2;
+  wrError     = 3;
+
+type
+  PWasmBasicEventState = ^TWasmBasicEventState;
+  TWasmBasicEventState = record
+    Signal : Longint;
+    ManualReset : Boolean;
+    Destroying : Boolean;
+  end;
 
 function WasiBasicEventCreate(EventAttributes :Pointer;  AManualReset,InitialState : Boolean;const Name:ansistring):pEventState;
+var
+  P: PWasmBasicEventState;
 begin
-  {todo:implement}
+  New(P);
+  fpc_wasm32_i32_atomic_store(@P^.Signal,Ord(InitialState));
+  fpc_wasm32_i32_atomic_store8(@P^.ManualReset,Ord(AManualReset));
+  fpc_wasm32_i32_atomic_store8(@P^.Destroying,0);
+  Result:=P;
 end;
 
 procedure WasiBasicEventDestroy(state:peventstate);
+var
+  P: PWasmBasicEventState absolute state;
+  a: longword;
 begin
-  {todo:implement}
+  fpc_wasm32_i32_atomic_store8(@P^.Destroying,1);
+  fpc_wasm32_i32_atomic_store(@P^.Signal,1);
+  a:=fpc_wasm32_memory_atomic_notify(@(P^.Signal),MaxThreadSignal);
+  Dispose(P);
 end;
 
 procedure WasiBasicEventResetEvent(state:peventstate);
+var
+  P: PWasmBasicEventState absolute state;
 begin
-  {todo:implement}
+  fpc_wasm32_i32_atomic_store(@P^.Signal,0);
 end;
 
 procedure WasiBasicEventSetEvent(state:peventstate);
+var
+  P: PWasmBasicEventState absolute state;
+  a: longword;
 begin
-  {todo:implement}
+  if fpc_wasm32_i32_atomic_rmw_cmpxchg_u(@P^.Signal,0,1)=0 then
+    begin
+      if fpc_wasm32_i32_atomic_load8_u(@P^.ManualReset)<>0 then
+        a:=fpc_wasm32_memory_atomic_notify(@(P^.Signal),MaxThreadSignal)
+      else
+        a:=fpc_wasm32_memory_atomic_notify(@(P^.Signal),1);
+    end;
+end;
+
+function WasiBasicEventWaitFor_WaitAllowed(aTimeOutNS:Int64;P:PWasmBasicEventState):longint;
+var
+  EndTime: TOSTime;
+  RemainingTime: Int64;
+begin
+  if fpc_wasm32_i32_atomic_load8_u(@P^.Destroying)<>0 then
+    begin
+      result:=wrAbandoned;
+      exit;
+    end;
+  if fpc_wasm32_i32_atomic_load8_u(@P^.ManualReset)<>0 then
+    begin
+      { manual reset event }
+      case fpc_wasm32_memory_atomic_wait32(@P^.Signal,0,aTimeOutNS) of
+        0, 1:
+          result:=wrSignaled;
+        2:
+          result:=wrTimeout;
+        else
+          result:=wrError;
+      end;
+      if fpc_wasm32_i32_atomic_load8_u(@P^.Destroying)<>0 then
+        result:=wrAbandoned;
+    end
+  else
+    begin
+      { auto reset event }
+      if aTimeOutNS>=0 then
+        EndTime:=GetClockTime+aTimeOutNS
+      else
+        begin
+          EndTime:=0;
+          RemainingTime:=-1;
+        end;
+      repeat
+        if aTimeOutNS>=0 then
+          begin
+            RemainingTime:=EndTime-GetClockTime;
+            if RemainingTime<0 then
+              begin
+                result:=wrTimeout;
+                exit;
+              end;
+          end;
+        case fpc_wasm32_memory_atomic_wait32(@P^.Signal,0,RemainingTime) of
+          0, { "ok" }
+          1: { "not-equal" }
+            begin
+              if fpc_wasm32_i32_atomic_load8_u(@P^.Destroying)<>0 then
+                begin
+                  result:=wrAbandoned;
+                  exit;
+                end
+              else if fpc_wasm32_i32_atomic_rmw_cmpxchg_u(@P^.Signal,1,0)=1 then
+                begin
+                  result:=wrSignaled;
+                  exit;
+                end
+              else
+                ; { try waiting again (loop continues) }
+            end;
+          2: { "timed-out" }
+            if fpc_wasm32_i32_atomic_load8_u(@P^.Destroying)<>0 then
+              begin
+                result:=wrAbandoned;
+                exit;
+              end
+            else
+              begin
+                result:=wrTimeout;
+                exit;
+              end;
+          else { invalid result from wait }
+            begin
+              result:=wrError;
+              exit;
+            end;
+        end;
+      until false;
+    end;
+end;
+
+function WasiBasicEventWaitFor_WaitNotAllowed(aTimeOutNS:Int64;P:PWasmBasicEventState):longint;
+var
+  EndTime: TOSTime;
+  RemainingTime: Int64;
+begin
+  if fpc_wasm32_i32_atomic_load8_u(@P^.Destroying)<>0 then
+    begin
+      result:=wrAbandoned;
+      exit;
+    end;
+  if aTimeOutNS>=0 then
+    EndTime:=GetClockTime+aTimeOutNS
+  else
+    begin
+      EndTime:=0;
+      RemainingTime:=-1;
+    end;
+  if fpc_wasm32_i32_atomic_load8_u(@P^.ManualReset)<>0 then
+    begin
+      { manual reset event }
+      repeat
+        if aTimeOutNS>=0 then
+          begin
+            RemainingTime:=EndTime-GetClockTime;
+            if RemainingTime<0 then
+              begin
+                result:=wrTimeout;
+                exit;
+              end;
+          end;
+        if fpc_wasm32_i32_atomic_load8_u(@P^.Destroying)<>0 then
+          begin
+            result:=wrAbandoned;
+            exit;
+          end
+        else if fpc_wasm32_i32_atomic_load(@P^.Signal)<>0 then
+          begin
+            result:=wrSignaled;
+            exit;
+          end;
+      until false;
+    end
+  else
+    begin
+      { auto reset event }
+      repeat
+        if aTimeOutNS>=0 then
+          begin
+            RemainingTime:=EndTime-GetClockTime;
+            if RemainingTime<0 then
+              begin
+                result:=wrTimeout;
+                exit;
+              end;
+          end;
+        if fpc_wasm32_i32_atomic_load8_u(@P^.Destroying)<>0 then
+          begin
+            result:=wrAbandoned;
+            exit;
+          end
+        else if fpc_wasm32_i32_atomic_rmw_cmpxchg_u(@P^.Signal,1,0)=1 then
+          begin
+            result:=wrSignaled;
+            exit;
+          end;
+      until false;
+    end;
 end;
 
 function WasiBasicEventWaitFor(timeout:cardinal;state:peventstate;FUseComWait : Boolean=False):longint;
+var
+  timeoutNS: Int64;
 begin
-  {todo:implement}
+  if timeout<>$FFFFFFFF then
+    timeoutNS:=timeout*1000000
+  else
+    timeoutNS:=-1;
+  if isWaitAllowed then
+      Result:=WasiBasicEventWaitFor_WaitAllowed(timeoutNS,PWasmBasicEventState(state))
+    else
+      Result:=WasiBasicEventWaitFor_WaitNotAllowed(timeoutNS,PWasmBasicEventState(state));
 end;