tthread.inc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************}
  11. {* TThread *}
  12. {****************************************************************************}
  13. {$ifdef FPC_WASM_THREADS}
  14. procedure TThread.CallOnTerminate;
  15. begin
  16. FOnTerminate(self);
  17. end;
  18. function TThread.GetPriority: TThreadPriority;
  19. begin
  20. GetPriority:=tpNormal;
  21. end;
  22. procedure TThread.SetPriority(Value: TThreadPriority);
  23. begin
  24. // Not supported
  25. end;
  26. procedure TThread.SetSuspended(Value: Boolean);
  27. begin
  28. if Value <> FSuspended then
  29. if Value then
  30. Suspend
  31. else
  32. Resume;
  33. end;
  34. procedure TThread.DoTerminate;
  35. begin
  36. if Assigned(FOnTerminate) then
  37. Synchronize(@CallOnTerminate);
  38. end;
  39. function ThreadFunc(parameter: Pointer): ptrint;
  40. Var
  41. LThread : TThread Absolute parameter;
  42. LFreeOnTerminate : Boolean;
  43. begin
  44. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('In threadfunc. Thread object: '+IntToStr(PTrUint(LThread)));{$ENDIF}
  45. try
  46. if LThread.FInitialSuspended then
  47. begin
  48. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('thread '+IntToStr(ptruint(LThread))+' waiting for RTLEvent '+IntToStr(ptruint(LThread.FSuspendEvent)));{$ENDIF}
  49. RtlEventWaitFor(LThread.FSuspendEvent);
  50. if (LThread.FTerminated) then
  51. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('initially created suspended, but already terminated'){$ENDIF}
  52. else if LThread.FSuspended then
  53. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('thread '+IntToStr(PtrUint(LThread))+' initially created suspended, resumed, but still suspended?!'){$ENDIF}
  54. else
  55. begin
  56. LThread.FInitialSuspended := false;
  57. CurrentThreadVar := LThread;
  58. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('going into LThread.Execute (1)');{$ENDIF}
  59. LThread.Execute;
  60. end
  61. end
  62. else
  63. begin
  64. // The suspend internal is needed due to bug 16884
  65. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Suspending internally');{$ENDIF}
  66. LThread.FSuspendedInternal:=True;
  67. RtlEventWaitFor(LThread.FSuspendEvent);
  68. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Internal suspend done.');{$ENDIF}
  69. CurrentThreadVar := LThread;
  70. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('going into LThread.Execute (2)');{$ENDIF}
  71. LThread.Execute;
  72. end;
  73. except
  74. on e: exception do
  75. begin
  76. LThread.FFatalException := TObject(AcquireExceptionObject);
  77. if e is EThreadDestroyCalled then
  78. LThread.FFreeOnTerminate := true;
  79. end;
  80. end;
  81. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('thread done running');{$ENDIF}
  82. Result := LThread.FReturnValue;
  83. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Result is '+IntToStr(Result));{$ENDIF}
  84. LFreeOnTerminate := LThread.FreeOnTerminate;
  85. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Calling doterminate');{$ENDIF}
  86. LThread.DoTerminate;
  87. LThread.FFinished := True;
  88. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Thread Set to finished');{$ENDIF}
  89. if LFreeOnTerminate then
  90. begin
  91. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Thread '+IntToStr(ptruint(lthread))+' should be freed');{$ENDIF}
  92. LThread.Free;
  93. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Thread freed');{$ENDIF}
  94. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Thread func calling EndThread');{$ENDIF}
  95. EndThread(Result);
  96. end;
  97. end;
  98. procedure TThread.SysCreate(CreateSuspended: Boolean; const StackSize: SizeUInt);
  99. begin
  100. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('In TThread.SysCreate');{$ENDIF}
  101. FSuspendEvent := RtlEventCreate;
  102. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('TThread.SysCreate: Created suspend event');{$ENDIF}
  103. FSuspended := CreateSuspended;
  104. FThreadReaped := false;
  105. FInitialSuspended := CreateSuspended;
  106. FSuspendedInternal := not CreateSuspended;
  107. FFatalException := nil;
  108. FHandle:=BeginThread(@ThreadFunc, Pointer(Self), FThreadID, StackSize);
  109. if FHandle = TThreadID(0) then
  110. begin
  111. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('TThread.SysCreate: Failed to create thread');{$ENDIF}
  112. raise EThread.create('Failed to create new thread');
  113. end;
  114. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('TThread.SysCreate: thread created');{$ENDIF}
  115. end;
  116. procedure TThread.SysDestroy;
  117. begin
  118. { exception in constructor }
  119. if not assigned(FSuspendEvent) then
  120. exit;
  121. { exception in constructor }
  122. if (FHandle = TThreadID(0)) then
  123. begin
  124. RtlEventDestroy(FSuspendEvent);
  125. exit;
  126. end;
  127. { Thread itself called destroy ? }
  128. if (FThreadID = GetCurrentThreadID) then
  129. begin
  130. if not(FFreeOnTerminate) and not FFinished then
  131. raise EThreadDestroyCalled.Create('A thread cannot destroy itself except by setting FreeOnTerminate and leaving!');
  132. FFreeOnTerminate := false;
  133. end
  134. else
  135. begin
  136. { avoid recursion}
  137. FFreeOnTerminate := false;
  138. { you can't join yourself, so only for FThreadID<>GetCurrentThreadID }
  139. { and you can't join twice -> make sure we didn't join already }
  140. if not FThreadReaped then
  141. begin
  142. Terminate;
  143. if (FSuspendedInternal or FInitialSuspended) then
  144. Resume;
  145. WaitFor;
  146. end;
  147. end;
  148. RtlEventDestroy(FSuspendEvent);
  149. FFatalException.Free;
  150. FFatalException := nil;
  151. end;
  152. procedure TThread.Resume;
  153. begin
  154. if FSuspendedInternal and (InterLockedExchange(longint(FSuspendedInternal),ord(false)) = longint(longbool(true))) then
  155. begin
  156. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('resuming thread after TThread construction '+IntToStr(ptruint(self)));{$ENDIF}
  157. RtlEventSetEvent(FSuspendEvent);
  158. end
  159. else
  160. begin
  161. { don't compare with ord(true) or ord(longbool(true)), }
  162. { becaue a longbool's "true" value is anyting <> false }
  163. if FSuspended and
  164. (InterLockedExchange(longint(FSuspended),longint(false)) <> longint(longbool(false))) then
  165. begin
  166. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('resuming '+IntToStr(ptruint(self)));{$ENDIF}
  167. RtlEventSetEvent(FSuspendEvent);
  168. end
  169. end
  170. end;
  171. procedure TThread.Suspend;
  172. begin
  173. if FThreadID<>GetCurrentThreadID then
  174. Raise EThread.create('Suspending one thread from inside another one is unsupported (because it is unsafe and deadlock prone) by *nix and posix operating systems');
  175. { don't compare with ord(true) or ord(longbool(true)), }
  176. { becaue a longbool's "true" value is anyting <> false }
  177. if not FSuspended and
  178. (InterLockedExchange(longint(FSuspended),longint(longbool(true))) = longint(longbool(false))) then
  179. RtlEventWaitFor(FSuspendEvent)
  180. end;
  181. function TThread.WaitFor: Integer;
  182. begin
  183. WaitFor:=WaitForThreadTerminate(FThreadID,-1);
  184. end;
  185. {$else FPC_WASM_THREADS}
  186. procedure TThread.CallOnTerminate;
  187. begin
  188. end;
  189. function TThread.GetPriority: TThreadPriority;
  190. begin
  191. GetPriority:=tpNormal;
  192. end;
  193. procedure TThread.SetPriority(Value: TThreadPriority);
  194. begin
  195. end;
  196. procedure TThread.SetSuspended(Value: Boolean);
  197. begin
  198. end;
  199. procedure TThread.DoTerminate;
  200. begin
  201. end;
  202. procedure TThread.SysCreate(CreateSuspended: Boolean; const StackSize: SizeUInt);
  203. begin
  204. {IsMultiThread := TRUE; }
  205. end;
  206. procedure TThread.SysDestroy;
  207. begin
  208. end;
  209. procedure TThread.Resume;
  210. begin
  211. end;
  212. procedure TThread.Suspend;
  213. begin
  214. end;
  215. function TThread.WaitFor: Integer;
  216. begin
  217. WaitFor:=0;
  218. end;
  219. {$endif FPC_WASM_THREADS}