tthread.inc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by Peter Vreman
  5. Linux TThread implementation
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. type
  13. PThreadRec=^TThreadRec;
  14. TThreadRec=record
  15. thread : TThread;
  16. next : PThreadRec;
  17. end;
  18. var
  19. ThreadRoot : PThreadRec;
  20. ThreadsInited : boolean;
  21. // MainThreadID: longint;
  22. Const
  23. ThreadCount: longint = 0;
  24. function ThreadSelf:TThread;
  25. var
  26. hp : PThreadRec;
  27. sp : longint;
  28. begin
  29. sp:=SPtr;
  30. hp:=ThreadRoot;
  31. while assigned(hp) do
  32. begin
  33. if (sp<=hp^.Thread.FStackPointer) and
  34. (sp>(hp^.Thread.FStackPointer-hp^.Thread.FStackSize)) then
  35. begin
  36. Result:=hp^.Thread;
  37. exit;
  38. end;
  39. hp:=hp^.next;
  40. end;
  41. Result:=nil;
  42. end;
  43. //function SIGCHLDHandler(Sig: longint): longint; cdecl;//this is std linux C declaration as function
  44. procedure SIGCHLDHandler(Sig: longint); cdecl;
  45. begin
  46. waitpid(-1, nil, WNOHANG);
  47. end;
  48. procedure InitThreads;
  49. var
  50. Act, OldAct: PSigActionRec;
  51. begin
  52. ThreadRoot:=nil;
  53. ThreadsInited:=true;
  54. // This will install SIGCHLD signal handler
  55. // signal() installs "one-shot" handler,
  56. // so it is better to install and set up handler with sigaction()
  57. GetMem(Act, SizeOf(SigActionRec));
  58. GetMem(OldAct, SizeOf(SigActionRec));
  59. Act^.handler.sh := @SIGCHLDHandler;
  60. Act^.sa_flags := SA_NOCLDSTOP {or SA_NOMASK or SA_RESTART};
  61. Act^.sa_mask := 0; //Do not block all signals ??. Don't need if SA_NOMASK in flags
  62. SigAction(SIGCHLD, Act, OldAct);
  63. FreeMem(Act, SizeOf(SigActionRec));
  64. FreeMem(OldAct, SizeOf(SigActionRec));
  65. end;
  66. procedure DoneThreads;
  67. var
  68. hp : PThreadRec;
  69. begin
  70. while assigned(ThreadRoot) do
  71. begin
  72. ThreadRoot^.Thread.Destroy;
  73. hp:=ThreadRoot;
  74. ThreadRoot:=ThreadRoot^.Next;
  75. dispose(hp);
  76. end;
  77. ThreadsInited:=false;
  78. end;
  79. procedure AddThread(t:TThread);
  80. var
  81. hp : PThreadRec;
  82. begin
  83. { Need to initialize threads ? }
  84. if not ThreadsInited then
  85. InitThreads;
  86. { Put thread in the linked list }
  87. new(hp);
  88. hp^.Thread:=t;
  89. hp^.next:=ThreadRoot;
  90. ThreadRoot:=hp;
  91. inc(ThreadCount, 1);
  92. end;
  93. procedure RemoveThread(t:TThread);
  94. var
  95. lasthp,hp : PThreadRec;
  96. begin
  97. hp:=ThreadRoot;
  98. lasthp:=nil;
  99. while assigned(hp) do
  100. begin
  101. if hp^.Thread=t then
  102. begin
  103. if assigned(lasthp) then
  104. lasthp^.next:=hp^.next
  105. else
  106. ThreadRoot:=hp^.next;
  107. dispose(hp);
  108. exit;
  109. end;
  110. lasthp:=hp;
  111. hp:=hp^.next;
  112. end;
  113. Dec(ThreadCount, 1);
  114. if ThreadCount = 0 then DoneThreads;
  115. end;
  116. { TThread }
  117. function ThreadProc(args:pointer): Integer;cdecl;
  118. var
  119. FreeThread: Boolean;
  120. Thread : TThread absolute args;
  121. begin
  122. try
  123. Thread.Execute;
  124. except
  125. Thread.FFatalException := TObject(AcquireExceptionObject);
  126. end;
  127. FreeThread := Thread.FFreeOnTerminate;
  128. Result := Thread.FReturnValue;
  129. Thread.FFinished := True;
  130. Thread.DoTerminate;
  131. if FreeThread then
  132. Thread.Free;
  133. ExitProcess(Result);
  134. end;
  135. constructor TThread.Create(CreateSuspended: Boolean);
  136. var
  137. Flags: Integer;
  138. begin
  139. inherited Create;
  140. AddThread(self);
  141. FSuspended := CreateSuspended;
  142. Flags := CLONE_VM + CLONE_FS + CLONE_FILES + CLONE_SIGHAND + SIGCHLD;
  143. { Setup 16k of stack }
  144. FStackSize:=16384;
  145. Getmem(pointer(FStackPointer),FStackSize);
  146. inc(FStackPointer,FStackSize);
  147. FCallExitProcess:=false;
  148. { Clone }
  149. FHandle:= Clone(@ThreadProc,pointer(FStackPointer),Flags,self);
  150. if FSuspended then Suspend;
  151. FThreadID := FHandle;
  152. IsMultiThread := TRUE;
  153. FFatalException := nil;
  154. end;
  155. destructor TThread.Destroy;
  156. begin
  157. if not FFinished and not Suspended then
  158. begin
  159. Terminate;
  160. WaitFor;
  161. end;
  162. if FHandle <> -1 then
  163. Kill(FHandle, SIGKILL);
  164. dec(FStackPointer,FStackSize);
  165. Freemem(pointer(FStackPointer),FStackSize);
  166. FFatalException.Free;
  167. FFatalException := nil;
  168. inherited Destroy;
  169. RemoveThread(self);
  170. end;
  171. procedure TThread.CallOnTerminate;
  172. begin
  173. FOnTerminate(Self);
  174. end;
  175. procedure TThread.DoTerminate;
  176. begin
  177. if Assigned(FOnTerminate) then
  178. Synchronize(@CallOnTerminate);
  179. end;
  180. const
  181. { I Don't know idle or timecritical, value is also 20, so the largest other
  182. possibility is 19 (PFV) }
  183. Priorities: array [TThreadPriority] of Integer =
  184. (-20,-19,-10,9,10,19,20);
  185. function TThread.GetPriority: TThreadPriority;
  186. var
  187. P: Integer;
  188. I: TThreadPriority;
  189. begin
  190. P := {$ifdef ver1_0}Linux{$else}Unix{$endif}.GetPriority(Prio_Process,FHandle);
  191. Result := tpNormal;
  192. for I := Low(TThreadPriority) to High(TThreadPriority) do
  193. if Priorities[I] = P then
  194. Result := I;
  195. end;
  196. procedure TThread.SetPriority(Value: TThreadPriority);
  197. begin
  198. {$ifdef ver1_0}Linux{$else}Unix{$endif}.SetPriority(Prio_Process,FHandle, Priorities[Value]);
  199. end;
  200. procedure TThread.Synchronize(Method: TThreadMethod);
  201. begin
  202. FSynchronizeException := nil;
  203. FMethod := Method;
  204. { SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self)); }
  205. if Assigned(FSynchronizeException) then
  206. raise FSynchronizeException;
  207. end;
  208. procedure TThread.SetSuspended(Value: Boolean);
  209. begin
  210. if Value <> FSuspended then
  211. if Value then
  212. Suspend
  213. else
  214. Resume;
  215. end;
  216. procedure TThread.Suspend;
  217. begin
  218. Kill(FHandle, SIGSTOP);
  219. FSuspended := true;
  220. end;
  221. procedure TThread.Resume;
  222. begin
  223. Kill(FHandle, SIGCONT);
  224. FSuspended := False;
  225. end;
  226. procedure TThread.Terminate;
  227. begin
  228. FTerminated := True;
  229. end;
  230. function TThread.WaitFor: Integer;
  231. var
  232. status : longint;
  233. begin
  234. if FThreadID = MainThreadID then
  235. WaitPid(0,@status,0)
  236. else
  237. WaitPid(FHandle,@status,0);
  238. Result:=status;
  239. end;
  240. {
  241. $Log$
  242. Revision 1.1 2003-10-06 21:01:06 peter
  243. * moved classes unit to rtl
  244. Revision 1.3 2003/10/06 17:06:55 florian
  245. * applied Johannes Berg's patch for exception handling in threads
  246. Revision 1.2 2002/09/07 15:15:27 peter
  247. * old logs removed and tabs fixed
  248. Revision 1.1 2002/07/30 16:03:29 marco
  249. * Added for OpenBSD. Plain copy of NetBSD
  250. }