tthread.inc 6.5 KB

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