tthread.inc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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 : Pointer;
  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. {$ifdef ver1_0}waitpid{$else}fpwaitpid{$endif}(-1, nil, WNOHANG);
  47. end;
  48. procedure InitThreads;
  49. var
  50. Act, OldAct: Baseunix.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^.sa_handler := @SIGCHLDHandler;
  60. Act^.sa_flags := SA_NOCLDSTOP {or SA_NOMASK or SA_RESTART};
  61. Fillchar(Act^.sa_mask,sizeof(Act^.sa_mask),0); //Do not block all signals ??. Don't need if SA_NOMASK in flags
  62. {$ifdef ver1_0}
  63. SigAction(SIGCHLD, Act, OldAct);
  64. {$else}
  65. FpSigAction(SIGCHLD, @Act, @OldAct);
  66. {$endif}
  67. FreeMem(Act, SizeOf(SigActionRec));
  68. FreeMem(OldAct, SizeOf(SigActionRec));
  69. end;
  70. procedure DoneThreads;
  71. var
  72. hp : PThreadRec;
  73. begin
  74. while assigned(ThreadRoot) do
  75. begin
  76. ThreadRoot^.Thread.Destroy;
  77. hp:=ThreadRoot;
  78. ThreadRoot:=ThreadRoot^.Next;
  79. dispose(hp);
  80. end;
  81. ThreadsInited:=false;
  82. end;
  83. procedure AddThread(t:TThread);
  84. var
  85. hp : PThreadRec;
  86. begin
  87. { Need to initialize threads ? }
  88. if not ThreadsInited then
  89. InitThreads;
  90. { Put thread in the linked list }
  91. new(hp);
  92. hp^.Thread:=t;
  93. hp^.next:=ThreadRoot;
  94. ThreadRoot:=hp;
  95. inc(ThreadCount, 1);
  96. end;
  97. procedure RemoveThread(t:TThread);
  98. var
  99. lasthp,hp : PThreadRec;
  100. begin
  101. hp:=ThreadRoot;
  102. lasthp:=nil;
  103. while assigned(hp) do
  104. begin
  105. if hp^.Thread=t then
  106. begin
  107. if assigned(lasthp) then
  108. lasthp^.next:=hp^.next
  109. else
  110. ThreadRoot:=hp^.next;
  111. dispose(hp);
  112. exit;
  113. end;
  114. lasthp:=hp;
  115. hp:=hp^.next;
  116. end;
  117. Dec(ThreadCount, 1);
  118. if ThreadCount = 0 then DoneThreads;
  119. end;
  120. { TThread }
  121. function ThreadProc(args:pointer): Integer;cdecl;
  122. var
  123. FreeThread: Boolean;
  124. Thread : TThread absolute args;
  125. begin
  126. try
  127. Thread.Execute;
  128. except
  129. Thread.FFatalException := TObject(AcquireExceptionObject);
  130. end;
  131. FreeThread := Thread.FFreeOnTerminate;
  132. Result := Thread.FReturnValue;
  133. Thread.FFinished := True;
  134. Thread.DoTerminate;
  135. if FreeThread then
  136. Thread.Free;
  137. {$ifdef ver1_0}ExitProcess{$else}fpexit{$endif}(Result);
  138. end;
  139. constructor TThread.Create(CreateSuspended: Boolean);
  140. var
  141. Flags: Integer;
  142. begin
  143. inherited Create;
  144. AddThread(self);
  145. FSuspended := CreateSuspended;
  146. Flags := CLONE_VM + CLONE_FS + CLONE_FILES + CLONE_SIGHAND + SIGCHLD;
  147. { Setup 16k of stack }
  148. FStackSize:=16384;
  149. Getmem(FStackPointer,FStackSize);
  150. inc(FStackPointer,FStackSize);
  151. FCallExitProcess:=false;
  152. { Clone }
  153. FHandle:= Clone(@ThreadProc,FStackPointer,Flags,self);
  154. if FSuspended then Suspend;
  155. FThreadID := FHandle;
  156. IsMultiThread := TRUE;
  157. FFatalException := nil;
  158. end;
  159. destructor TThread.Destroy;
  160. begin
  161. if not FFinished and not Suspended then
  162. begin
  163. Terminate;
  164. WaitFor;
  165. end;
  166. if FHandle <> -1 then
  167. {$ifdef ver1_0}Kill{$else}fpkill{$endif}(FHandle, SIGKILL);
  168. dec(FStackPointer,FStackSize);
  169. Freemem(FStackPointer);
  170. FFatalException.Free;
  171. FFatalException := nil;
  172. inherited Destroy;
  173. RemoveThread(self);
  174. end;
  175. procedure TThread.CallOnTerminate;
  176. begin
  177. FOnTerminate(Self);
  178. end;
  179. procedure TThread.DoTerminate;
  180. begin
  181. if Assigned(FOnTerminate) then
  182. Synchronize(@CallOnTerminate);
  183. end;
  184. const
  185. { I Don't know idle or timecritical, value is also 20, so the largest other
  186. possibility is 19 (PFV) }
  187. Priorities: array [TThreadPriority] of Integer =
  188. (-20,-19,-10,9,10,19,20);
  189. function TThread.GetPriority: TThreadPriority;
  190. var
  191. P: Integer;
  192. I: TThreadPriority;
  193. begin
  194. P := {$ifdef ver1_0}
  195. Linux.GetPriority(Prio_Process,FHandle);
  196. {$else}
  197. Unix.fpGetPriority(Prio_Process,FHandle);
  198. {$endif}
  199. Result := tpNormal;
  200. for I := Low(TThreadPriority) to High(TThreadPriority) do
  201. if Priorities[I] = P then
  202. Result := I;
  203. end;
  204. procedure TThread.SetPriority(Value: TThreadPriority);
  205. begin
  206. {$ifdef ver1_0}
  207. Linux.SetPriority(Prio_Process,FHandle,Priorities[Value]);
  208. {$else}
  209. Unix.fpSetPriority(Prio_Process,FHandle,Priorities[Value]);
  210. {$endif}
  211. end;
  212. procedure TThread.Synchronize(Method: TThreadMethod);
  213. begin
  214. FSynchronizeException := nil;
  215. FMethod := Method;
  216. { SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self)); }
  217. if Assigned(FSynchronizeException) then
  218. raise FSynchronizeException;
  219. end;
  220. procedure TThread.SetSuspended(Value: Boolean);
  221. begin
  222. if Value <> FSuspended then
  223. if Value then
  224. Suspend
  225. else
  226. Resume;
  227. end;
  228. procedure TThread.Suspend;
  229. begin
  230. {$ifdef ver1_0}Kill{$else}fpkill{$endif}(FHandle, SIGSTOP);
  231. FSuspended := true;
  232. end;
  233. procedure TThread.Resume;
  234. begin
  235. {$ifdef ver1_0}Kill{$else}fpkill{$endif}(FHandle, SIGCONT);
  236. FSuspended := False;
  237. end;
  238. procedure TThread.Terminate;
  239. begin
  240. FTerminated := True;
  241. end;
  242. function TThread.WaitFor: Integer;
  243. var
  244. status : longint;
  245. begin
  246. if FThreadID = MainThreadID then
  247. {$ifdef ver1_0}waitpid{$else}fpwaitpid{$endif}(0,@status,0)
  248. else
  249. {$ifdef ver1_0}waitpid{$else}fpwaitpid{$endif}(FHandle,@status,0);
  250. Result:=status;
  251. end;
  252. {
  253. $Log$
  254. Revision 1.2 2003-11-03 09:42:28 marco
  255. * Peter's Cardinal<->Longint fixes patch
  256. Revision 1.1 2003/10/06 21:01:06 peter
  257. * moved classes unit to rtl
  258. Revision 1.9 2003/10/06 17:06:55 florian
  259. * applied Johannes Berg's patch for exception handling in threads
  260. Revision 1.8 2003/09/20 15:10:30 marco
  261. * small fixes. fcl now compiles
  262. Revision 1.7 2002/12/18 20:44:36 peter
  263. * use fillchar to clear sigset
  264. Revision 1.6 2002/09/07 15:15:27 peter
  265. * old logs removed and tabs fixed
  266. }