wasmmutex.inc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. {%MainUnit system.pp}
  2. // In nanoseconds
  3. Type
  4. // We us an alias here.
  5. TWasmMutex = TRTLCriticalSection;
  6. TMutexKind = (mkNormal,mkRecursive);
  7. TLockMutexResult = (lmrNone,lmrOK,lmrNotOwner,lmrError,lmrTimeout);
  8. Function MutexKind(M : TWasmMutex) : TMutexKind;
  9. begin
  10. Result:=TMutexKind(M.Kind);
  11. end;
  12. procedure InitMutex(M : TWasmMutex; aKind : TMutexKind = mkNormal; aOwner : TThreadID = Nil);
  13. begin
  14. FillChar(M,SizeOf(TWasmMutex),0);
  15. if aOwner=Nil then
  16. aOwner:=GetSelfThread;
  17. M.Owner:=aOwner;
  18. M.Kind:=Ord(aKind);
  19. end;
  20. procedure DoneMutex(M : TWasmMutex);
  21. Var
  22. a : LongInt;
  23. begin
  24. if (M.Locked>0) and (M.Owner=GetSelfThread) then
  25. begin
  26. M.Destroying:=True;
  27. a:=fpc_wasm32_memory_atomic_notify(@M.Locked,MaxThreadSignal);
  28. end;
  29. end;
  30. Function TryLockMutex(var M : TWasmMutex) : Boolean;
  31. Var
  32. Res : Boolean;
  33. begin
  34. // We already have the lock ?
  35. Res:=(M.Locked=1) and (M.Owner=GetSelfThread);
  36. if Not Res then
  37. Res:=fpc_wasm32_i32_atomic_rmw_cmpxchg_u(@M.Locked,0,1)=0
  38. else
  39. begin
  40. // TryLockMutex is called in a loop. Be VERY careful when adding this log.
  41. // {$IFDEF DEBUGWASMTHREADS}DebugWriteln('TryLockMutex : we ('+IntToStr(PtrUint(GetSelfThread))+') own the lock.');{$ENDIF}
  42. end;
  43. if Res then
  44. begin
  45. if (MutexKind(M)=mkRecursive) or (M.Count=0) then
  46. InterLockedIncrement(M.Count);
  47. // {$IFDEF DEBUGWASMTHREADS}DebugWriteln('TryLockMutex : setting owner to '+IntToStr(PtrUint(GetSelfThread))+'.');{$ENDIF}
  48. M.Owner:=GetSelfThread;
  49. end;
  50. TryLockMutex:=Res;
  51. end;
  52. // aTimeOutNS is in milliseconds. -1 is infinite
  53. Function LockMutexTimeoutNoWait(var m : TWasmMutex; aTimeOutMS : LongInt) : TLockMutexResult;
  54. Var
  55. Res : TLockMutexResult;
  56. MyThread : TThreadID;
  57. EndTime: TOSTime;
  58. begin
  59. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('LockMutexTimeoutNoWait('+IntToStr(m.locked)+','+intToStr(aTimeOutMs)+')');{$ENDIF}
  60. Res:=lmrNone;
  61. EndTime:=GetClockTime+aTimeOutMS*1000;
  62. MyThread:=GetSelfThread;
  63. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('LockMutexTimeoutNoWait: entering loop');{$ENDIF}
  64. Repeat
  65. if TryLockMutex(M) then
  66. Result:=lmrOK
  67. else
  68. begin
  69. If (GetThreadState(MyThread)<>tsRunning) then
  70. Res:=lmrError
  71. else
  72. begin
  73. If (aTimeOutMS<>-1) and (GetClockTime>EndTime) then
  74. Res:=lmrTimeOut
  75. end;
  76. end;
  77. Until (res<>lmrNone);
  78. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('LockMutexTimeoutNoWait: done loop');{$ENDIF}
  79. LockMutexTimeoutNoWait:=Res;
  80. end;
  81. Function LockMutexTimeoutWait(var m : TWasmMutex; aTimeOutMS : LongInt) : TLockMutexResult;
  82. Var
  83. Res : TLockMutexResult;
  84. MyThread : TThreadID;
  85. EndTime: TOSTime;
  86. begin
  87. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('LockMutexTimeoutWait('+IntToStr(m.locked)+','+intToStr(aTimeOutMs)+')');{$ENDIF}
  88. Res:=lmrNone;
  89. MyThread:=GetSelfThread;
  90. EndTime:=GetClockTime+aTimeOutMS*1000;
  91. InterLockedIncrement(M.Waiters);
  92. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('LockMutexTimeoutWait: entering loop');{$ENDIF}
  93. Repeat
  94. Case fpc_wasm32_memory_atomic_wait32(@M.Locked,1,1000) of
  95. 0 : begin
  96. if M.Destroying then
  97. Res:=lmrError
  98. else
  99. Res:=lmrOK;
  100. end;
  101. 1 : Res:=lmrError;
  102. 2 : begin
  103. if M.Destroying then
  104. Res:=lmrError
  105. else if (GetThreadState(MyThread)<>tsRunning) then
  106. Res:=lmrError
  107. else
  108. begin
  109. If (aTimeOutMS<>-1) and (GetClockTime>EndTime) then
  110. Res:=lmrTimeOut
  111. end;
  112. end;
  113. end;
  114. Until Res<>lmrNone;
  115. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('LockMutexTimeoutWait: done loop');{$ENDIF}
  116. InterLockedDecrement(M.Waiters);
  117. LockMutexTimeoutWait:=Res;
  118. end;
  119. Function LockMutexTimeout(var m : TWasmMutex; aTimeOutMS : Int64) : TLockMutexResult;
  120. begin
  121. if TryLockMutex(M) then
  122. Result:=lmrOK
  123. else if isWaitAllowed then
  124. Result:=LockMutexTimeoutWait(m,aTimeOutMS)
  125. else
  126. Result:=LockMutexTimeoutNoWait(m,aTimeOutMS)
  127. end;
  128. Function LockMutex(var m : TRTLCriticalSection) : TLockMutexResult;
  129. begin
  130. LockMutexTimeout(M,-1);
  131. end;
  132. function UnLockMutex(var m : TRTLCriticalSection) : TLockMutexResult;
  133. var
  134. Res : TLockMutexResult;
  135. MyThread : TThreadID;
  136. EndTime: TOSTime;
  137. a : LongInt;
  138. begin
  139. Res:=lmrNone;
  140. MyThread:=GetSelfThread;
  141. if MyThread<>M.owner then
  142. Res:=lmrNotOwner
  143. else if M.Count=0 then
  144. Res:=lmrError
  145. else
  146. begin
  147. res:=lmrOK;
  148. if (MutexKind(M)=mkRecursive) or (M.Count=1) then
  149. InterLockedDecrement(M.Count);
  150. if (M.Count=0) then
  151. a:=fpc_wasm32_memory_atomic_notify(@M.Locked,1);
  152. end;
  153. end;