Browse Source

* Wasm semaphore implementation

Michaël Van Canneyt 1 week ago
parent
commit
4af9b675e2

+ 2 - 0
rtl/inc/Makefile.rtl

@@ -263,6 +263,7 @@ WASIAPIUNIT=WASIApi.WASIApi
 WASIUTILUNIT=WASIApi.WASIUtil
 WASIUTILUNIT=WASIApi.WASIUtil
 WATCOMUNIT=WatcomApi.WatCom
 WATCOMUNIT=WatcomApi.WatCom
 WEBASSEMBLYUNIT=Wasm.Api
 WEBASSEMBLYUNIT=Wasm.Api
+WASMSEMUNIT=Wasm.Semaphore
 WIN31UNIT=WinApi.Win31
 WIN31UNIT=WinApi.Win31
 WINDIRSUNIT=WinApi.WinDirs
 WINDIRSUNIT=WinApi.WinDirs
 WINDOWSUNIT=WinApi.Windows
 WINDOWSUNIT=WinApi.Windows
@@ -531,6 +532,7 @@ WASIAPIUNIT=wasiapi
 WASIUTILUNIT=wasiutil
 WASIUTILUNIT=wasiutil
 WATCOMUNIT=watcom
 WATCOMUNIT=watcom
 WEBASSEMBLYUNIT=webassembly
 WEBASSEMBLYUNIT=webassembly
+WASMSEMUNIT=wasmsem
 WIN31UNIT=win31
 WIN31UNIT=win31
 WINDIRSUNIT=windirs
 WINDIRSUNIT=windirs
 WINDOWSUNIT=windows
 WINDOWSUNIT=windows

+ 3 - 0
rtl/namespaced/wasm32/Wasm.Semaphore.pp

@@ -0,0 +1,3 @@
+unit Wasm.Semaphore;
+{$DEFINE FPC_DOTTEDUNITS}
+{$i wasmsem.pas}

+ 8 - 1
rtl/wasip1/Makefile

@@ -622,6 +622,7 @@ WASIAPIUNIT=WASIApi.WASIApi
 WASIUTILUNIT=WASIApi.WASIUtil
 WASIUTILUNIT=WASIApi.WASIUtil
 WATCOMUNIT=WatcomApi.WatCom
 WATCOMUNIT=WatcomApi.WatCom
 WEBASSEMBLYUNIT=Wasm.Api
 WEBASSEMBLYUNIT=Wasm.Api
+WASMSEMUNIT=Wasm.Semaphore
 WIN31UNIT=WinApi.Win31
 WIN31UNIT=WinApi.Win31
 WINDIRSUNIT=WinApi.WinDirs
 WINDIRSUNIT=WinApi.WinDirs
 WINDOWSUNIT=WinApi.Windows
 WINDOWSUNIT=WinApi.Windows
@@ -884,6 +885,7 @@ WASIAPIUNIT=wasiapi
 WASIUTILUNIT=wasiutil
 WASIUTILUNIT=wasiutil
 WATCOMUNIT=watcom
 WATCOMUNIT=watcom
 WEBASSEMBLYUNIT=webassembly
 WEBASSEMBLYUNIT=webassembly
+WASMSEMUNIT=wasmsem
 WIN31UNIT=win31
 WIN31UNIT=win31
 WINDIRSUNIT=windirs
 WINDIRSUNIT=windirs
 WINDOWSUNIT=windows
 WINDOWSUNIT=windows
@@ -933,7 +935,7 @@ endif
 override FPC_SYSTEM_OPT += -Fi$(WASICOMMONINC)/wasiinc
 override FPC_SYSTEM_OPT += -Fi$(WASICOMMONINC)/wasiinc
 DOS_DEPS_OS=$(WASIAPIUNIT)$(PPUEXT) $(WASIUTILUNIT)$(PPUEXT)
 DOS_DEPS_OS=$(WASIAPIUNIT)$(PPUEXT) $(WASIUTILUNIT)$(PPUEXT)
 ifeq ($(CPU_OS_TARGET),wasm32-wasip1)
 ifeq ($(CPU_OS_TARGET),wasm32-wasip1)
-override TARGET_UNITS+=$(SYSTEMUNIT) $(SYSINIT_UNITS) $(OBJPASUNIT) $(EXTPASUNIT) $(MACPASUNIT) $(ISO7185UNIT) $(UUCHARUNIT) $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT)
+override TARGET_UNITS+=$(SYSTEMUNIT) $(SYSINIT_UNITS) $(OBJPASUNIT) $(EXTPASUNIT) $(MACPASUNIT) $(ISO7185UNIT) $(UUCHARUNIT) $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT) $(WASMSEMUNIT)
 endif
 endif
 ifeq ($(CPU_OS_TARGET),wasm32-wasip1)
 ifeq ($(CPU_OS_TARGET),wasm32-wasip1)
 override TARGET_IMPLICITUNITS+=$(CP_UNITS) $(UNICODEDATAUNIT)
 override TARGET_IMPLICITUNITS+=$(CP_UNITS) $(UNICODEDATAUNIT)
@@ -2974,6 +2976,11 @@ webassembly$(PPUEXT) : $(WEBASSEMBLYDEPS)
 	$(COMPILER) $<
 	$(COMPILER) $<
 Wasm.Api$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Api.pp $(WEBASSEMBLYDEPS)
 Wasm.Api$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Api.pp $(WEBASSEMBLYDEPS)
 	$(COMPILER) $<
 	$(COMPILER) $<
+WASMSEMDEPS=$(PROCINC)/websem.pp $(SYSTEMUNIT)$(PPUEXT) $(PROCINC)/cpuh.inc $(PROCINC)/cpuinnr.inc $(WEBASSEMBLYUNIT)$(PPUEXT)
+wamsem$(PPUEXT) : $(WASMSEMDEPS)
+	$(COMPILER) $<
+Wasm.Semaphore$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Semaphore.pp $(WEBASSEMBLYDEPS)
+	$(COMPILER) $<
 WASIAPIDEPS=$(WASICOMMONINC)/wasiinc/wasitypes.inc $(WASICOMMONINC)/wasiinc/wasiprocs.inc $(SYSTEMUNIT)$(PPUEXT)
 WASIAPIDEPS=$(WASICOMMONINC)/wasiinc/wasitypes.inc $(WASICOMMONINC)/wasiinc/wasiprocs.inc $(SYSTEMUNIT)$(PPUEXT)
 wasiapi$(PPUEXT) : wasiapi.pp $(WASIAPIDEPS)
 wasiapi$(PPUEXT) : wasiapi.pp $(WASIAPIDEPS)
 	$(COMPILER) $< -Fiwasiinc
 	$(COMPILER) $< -Fiwasiinc

+ 13 - 1
rtl/wasip1/Makefile.fpc

@@ -9,7 +9,8 @@ units=$(SYSTEMUNIT) $(SYSINIT_UNITS) $(OBJPASUNIT) $(EXTPASUNIT) $(MACPASUNIT) $
       $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) \
       $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) \
       $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) \
       $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) \
       $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) \
       $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) \
-      $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT)
+      $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT) \
+      $(WASMSEMUNIT)
 
 
 implicitunits= $(CP_UNITS) $(UNICODEDATAUNIT)
 implicitunits= $(CP_UNITS) $(UNICODEDATAUNIT)
 
 
@@ -90,6 +91,17 @@ webassembly$(PPUEXT) : $(WEBASSEMBLYDEPS)
 
 
 Wasm.Api$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Api.pp $(WEBASSEMBLYDEPS)
 Wasm.Api$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Api.pp $(WEBASSEMBLYDEPS)
         $(COMPILER) $<
         $(COMPILER) $<
+#
+# wasmsem/Wasm.Semaphore
+#
+WASMSEMDEPS=$(PROCINC)/websem.pp $(SYSTEMUNIT)$(PPUEXT) $(PROCINC)/cpuh.inc $(PROCINC)/cpuinnr.inc $(WEBASSEMBLYUNIT)$(PPUEXT)
+
+wamsem$(PPUEXT) : $(WASMSEMDEPS)
+        $(COMPILER) $<
+
+Wasm.Semaphore$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Semaphore.pp $(WEBASSEMBLYDEPS)
+        $(COMPILER) $<
+
 
 
 #
 #
 # WASIAPI
 # WASIAPI

+ 8 - 1
rtl/wasip1threads/Makefile

@@ -622,6 +622,7 @@ WASIAPIUNIT=WASIApi.WASIApi
 WASIUTILUNIT=WASIApi.WASIUtil
 WASIUTILUNIT=WASIApi.WASIUtil
 WATCOMUNIT=WatcomApi.WatCom
 WATCOMUNIT=WatcomApi.WatCom
 WEBASSEMBLYUNIT=Wasm.Api
 WEBASSEMBLYUNIT=Wasm.Api
+WASMSEMUNIT=Wasm.Semaphore
 WIN31UNIT=WinApi.Win31
 WIN31UNIT=WinApi.Win31
 WINDIRSUNIT=WinApi.WinDirs
 WINDIRSUNIT=WinApi.WinDirs
 WINDOWSUNIT=WinApi.Windows
 WINDOWSUNIT=WinApi.Windows
@@ -884,6 +885,7 @@ WASIAPIUNIT=wasiapi
 WASIUTILUNIT=wasiutil
 WASIUTILUNIT=wasiutil
 WATCOMUNIT=watcom
 WATCOMUNIT=watcom
 WEBASSEMBLYUNIT=webassembly
 WEBASSEMBLYUNIT=webassembly
+WASMSEMUNIT=wasmsem
 WIN31UNIT=win31
 WIN31UNIT=win31
 WINDIRSUNIT=windirs
 WINDIRSUNIT=windirs
 WINDOWSUNIT=windows
 WINDOWSUNIT=windows
@@ -933,7 +935,7 @@ endif
 override FPC_SYSTEM_OPT += -Fi$(WASICOMMONINC)/wasiinc
 override FPC_SYSTEM_OPT += -Fi$(WASICOMMONINC)/wasiinc
 DOS_DEPS_OS=$(WASIAPIUNIT)$(PPUEXT) $(WASIUTILUNIT)$(PPUEXT)
 DOS_DEPS_OS=$(WASIAPIUNIT)$(PPUEXT) $(WASIUTILUNIT)$(PPUEXT)
 ifeq ($(CPU_OS_TARGET),wasm32-wasip1threads)
 ifeq ($(CPU_OS_TARGET),wasm32-wasip1threads)
-override TARGET_UNITS+=$(SYSTEMUNIT) $(SYSINIT_UNITS) $(OBJPASUNIT) $(EXTPASUNIT) $(MACPASUNIT) $(ISO7185UNIT) $(UUCHARUNIT) $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT)
+override TARGET_UNITS+=$(SYSTEMUNIT) $(SYSINIT_UNITS) $(OBJPASUNIT) $(EXTPASUNIT) $(MACPASUNIT) $(ISO7185UNIT) $(UUCHARUNIT) $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT) $(WASMSEMUNIT)
 endif
 endif
 ifeq ($(CPU_OS_TARGET),wasm32-wasip1threads)
 ifeq ($(CPU_OS_TARGET),wasm32-wasip1threads)
 override TARGET_IMPLICITUNITS+=$(CP_UNITS) $(UNICODEDATAUNIT)
 override TARGET_IMPLICITUNITS+=$(CP_UNITS) $(UNICODEDATAUNIT)
@@ -2974,6 +2976,11 @@ webassembly$(PPUEXT) : $(WEBASSEMBLYDEPS)
 	$(COMPILER) $<
 	$(COMPILER) $<
 Wasm.Api$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Api.pp $(WEBASSEMBLYDEPS)
 Wasm.Api$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Api.pp $(WEBASSEMBLYDEPS)
 	$(COMPILER) $<
 	$(COMPILER) $<
+WASMSEMDEPS=$(PROCINC)/websem.pp $(SYSTEMUNIT)$(PPUEXT) $(PROCINC)/cpuh.inc $(PROCINC)/cpuinnr.inc $(WEBASSEMBLYUNIT)$(PPUEXT)
+wamsem$(PPUEXT) : $(WASMSEMDEPS)
+	$(COMPILER) $<
+Wasm.Semaphore$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Semaphore.pp $(WEBASSEMBLYDEPS)
+	$(COMPILER) $< 
 WASIAPIDEPS=$(WASICOMMONINC)/wasiinc/wasitypes.inc $(WASICOMMONINC)/wasiinc/wasiprocs.inc $(SYSTEMUNIT)$(PPUEXT)
 WASIAPIDEPS=$(WASICOMMONINC)/wasiinc/wasitypes.inc $(WASICOMMONINC)/wasiinc/wasiprocs.inc $(SYSTEMUNIT)$(PPUEXT)
 wasiapi$(PPUEXT) : wasiapi.pp $(WASIAPIDEPS)
 wasiapi$(PPUEXT) : wasiapi.pp $(WASIAPIDEPS)
 	$(COMPILER) $< -Fiwasiinc
 	$(COMPILER) $< -Fiwasiinc

+ 15 - 1
rtl/wasip1threads/Makefile.fpc

@@ -9,7 +9,9 @@ units=$(SYSTEMUNIT) $(SYSINIT_UNITS) $(OBJPASUNIT) $(EXTPASUNIT) $(MACPASUNIT) $
       $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) \
       $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) \
       $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) \
       $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) \
       $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) \
       $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) \
-      $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT)
+      $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT) \
+      $(WASMSEMUNIT)
+
 
 
 implicitunits= $(CP_UNITS) $(UNICODEDATAUNIT)
 implicitunits= $(CP_UNITS) $(UNICODEDATAUNIT)
 
 
@@ -91,6 +93,18 @@ webassembly$(PPUEXT) : $(WEBASSEMBLYDEPS)
 Wasm.Api$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Api.pp $(WEBASSEMBLYDEPS)
 Wasm.Api$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Api.pp $(WEBASSEMBLYDEPS)
         $(COMPILER) $<
         $(COMPILER) $<
 
 
+#
+# wasmsem/Wasm.Semaphore
+#
+
+WASMSEMDEPS=$(PROCINC)/websem.pp $(SYSTEMUNIT)$(PPUEXT) $(PROCINC)/cpuh.inc $(PROCINC)/cpuinnr.inc $(WEBASSEMBLYUNIT)$(PPUEXT)
+
+wamsem$(PPUEXT) : $(WASMSEMDEPS)
+        $(COMPILER) $<
+
+Wasm.Semaphore$(PPUEXT) : $(NSDIR)/wasm32/Wasm.Semaphore.pp $(WEBASSEMBLYDEPS)
+        $(COMPILER) $< 
+
 #
 #
 # WASIAPI
 # WASIAPI
 #
 #

+ 3 - 1
rtl/wasip2/Makefile.fpc

@@ -10,7 +10,9 @@ units=$(SYSTEMUNIT) $(SYSINIT_UNITS) $(RESUNIT) $(OBJPASUNIT)
 #      $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) \
 #      $(WASIAPIUNIT) $(CTYPESUNIT) $(STRINGSUNIT) $(SYSCONSTUNIT)  $(SYSUTILSUNIT) \
 #      $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) \
 #      $(SORTBASEUNIT) $(MATHUNIT) $(RTLCONSTSUNIT) $(TYPESUNIT)  $(TYPINFOUNIT)  $(FGLUNIT) $(GETOPTSUNIT) \
 #      $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) \
 #      $(CHARSETUNIT)  $(CPALLUNIT) $(CHARACTERUNIT) $(FPWIDESTRINGUNIT) $(NOTHREADSUNIT) \
-#      $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT)
+#      $(CLASSESUNIT) $(DOSUNIT) $(RESUNIT) $(HEAPTRCUNIT) $(WASIUTILUNIT)  $(WEBASSEMBLYUNIT) \
+#      $(WASMSEMUNIT)
+
 
 
 implicitunits= $(CP_UNITS) $(UNICODEDATAUNIT)
 implicitunits= $(CP_UNITS) $(UNICODEDATAUNIT)
 
 

+ 136 - 0
rtl/wasm32/wasmsem.pas

@@ -0,0 +1,136 @@
+{$IFNDEF FPC_DOTTEDUNITS}
+unit WasmSem;
+{$ENDIF}
+
+{$mode objfpc}{$H+}
+{$codepage utf8}
+
+interface
+
+uses
+{$IFDEF FPC_DOTTEDUNITS}
+  Wasm.Api;
+{$ELSE}  
+  WebAssembly;
+{$ENDIF}
+
+type
+  PWasmSemaphore = ^TWasmSemaphore;
+  TWasmSemaphore = packed record
+    counter: longint;     // Current counter value
+    max_count: longint;   // Maximum count allowed
+  end;
+
+// Initialize a semaphore with initial count and maximum count
+procedure semaphore_init(var sem: TWasmSemaphore; initial_count, max_count: longint);
+
+// Wait (acquire) operation with timeout - decrements counter, blocks if counter would go negative
+// timeout_ms: timeout in milliseconds (-1 for infinite timeout)
+// Returns true if acquired successfully, false if timeout occurred
+function semaphore_wait(var sem: TWasmSemaphore; timeout_ms: int64): boolean;
+
+// Wait (acquire) operation without timeout - blocks indefinitely until semaphore is available
+// Returns true when acquired successfully
+function semaphore_wait_infinite(var sem: TWasmSemaphore): boolean;
+
+// Signal (release) operation - increments counter up to max and notifies waiters
+// Returns true if signaled successfully, false if at max count
+function semaphore_signal(var sem: TWasmSemaphore): boolean;
+
+// Get current semaphore count (read-only)
+function semaphore_count(var sem: TWasmSemaphore): longint;
+
+// Get maximum semaphore count (read-only)
+function semaphore_max_count(var sem: TWasmSemaphore): longint;
+
+implementation
+
+procedure semaphore_init(var sem: TWasmSemaphore; initial_count, max_count: longint);
+begin
+  AtomicStore(sem.counter, initial_count);
+  AtomicStore(sem.max_count, max_count);
+end;
+
+function semaphore_wait(var sem: TWasmSemaphore; timeout_ms: int64): boolean;
+var
+  current_count: longint;
+  new_count: longint;
+  expected: longint;
+  wait_result: longint;
+  timeout_ns: int64;
+begin
+  if timeout_ms = -1 then
+    timeout_ns := awtInfiniteTimeout
+  else
+    timeout_ns := timeout_ms * 1000000;
+
+  repeat
+    current_count := AtomicLoad(sem.counter);
+
+    if current_count > 0 then
+      begin
+      new_count := current_count - 1;
+      expected := current_count;
+
+      if AtomicCompareExchange(sem.counter, expected, new_count) = expected then
+        exit(true);
+      // Failed CAS, retry immediately
+      end
+    else
+      begin
+      wait_result := AtomicWait(sem.counter, current_count, timeout_ns);
+      if wait_result = awrTimedOut then
+        exit(false);
+      // Either woke up (awrOk) or not-equal (awrNotEqual), retry the acquisition
+      end;
+  until false;
+  // Should never reach here
+  result := false;
+end;
+
+function semaphore_wait_infinite(var sem: TWasmSemaphore): boolean;
+begin
+  result := semaphore_wait(sem, -1);
+end;
+
+function semaphore_signal(var sem: TWasmSemaphore): boolean;
+var
+  current_count: longint;
+  max_count: longint;
+  new_count: longint;
+  expected: longint;
+  woken_count: longword;
+begin
+  max_count := AtomicLoad(sem.max_count);
+
+  repeat
+    current_count := AtomicLoad(sem.counter);
+    if current_count >= max_count then
+      exit(false);
+
+    new_count := current_count + 1;
+    expected := current_count;
+
+    // Try atomic compare-and-swap
+    if AtomicCompareExchange(sem.counter, expected, new_count) = expected then
+      begin
+      woken_count := AtomicNotify(sem.counter, 1);
+      exit(true);
+      end;
+    // Failed CAS, retry
+  until false;
+  // Should never reach here
+  result := false;
+end;
+
+function semaphore_count(var sem: TWasmSemaphore): longint;
+begin
+  result := AtomicLoad(sem.counter);
+end;
+
+function semaphore_max_count(var sem: TWasmSemaphore): longint;
+begin
+  result := AtomicLoad(sem.max_count);
+end;
+
+end.