thread.inc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. Thread.Execute;
  132. FreeThread := Thread.FFreeOnTerminate;
  133. Result := Thread.FReturnValue;
  134. Thread.FFinished := True;
  135. Thread.DoTerminate;
  136. if FreeThread then
  137. Thread.Free;
  138. ExitProcess(Result);
  139. end;
  140. constructor TThread.Create(CreateSuspended: Boolean);
  141. var
  142. Flags: Integer;
  143. begin
  144. inherited Create;
  145. AddThread(self);
  146. FSuspended := CreateSuspended;
  147. Flags := CLONE_VM + CLONE_FS + CLONE_FILES + CLONE_SIGHAND + SIGCHLD;
  148. { Setup 16k of stack }
  149. FStackSize:=16384;
  150. Getmem(pointer(FStackPointer),FStackSize);
  151. inc(FStackPointer,FStackSize);
  152. FCallExitProcess:=false;
  153. { Clone }
  154. FHandle:= Clone(@ThreadProc,pointer(FStackPointer),Flags,self);
  155. if FSuspended then Suspend;
  156. FThreadID := FHandle;
  157. IsMultiThread := TRUE;
  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. Kill(FHandle, SIGKILL);
  168. dec(FStackPointer,FStackSize);
  169. Freemem(pointer(FStackPointer),FStackSize);
  170. inherited Destroy;
  171. RemoveThread(self);
  172. end;
  173. procedure TThread.CallOnTerminate;
  174. begin
  175. FOnTerminate(Self);
  176. end;
  177. procedure TThread.DoTerminate;
  178. begin
  179. if Assigned(FOnTerminate) then
  180. Synchronize(@CallOnTerminate);
  181. end;
  182. const
  183. { I Don't know idle or timecritical, value is also 20, so the largest other
  184. possibility is 19 (PFV) }
  185. Priorities: array [TThreadPriority] of Integer =
  186. (-20,-19,-10,9,10,19,20);
  187. function TThread.GetPriority: TThreadPriority;
  188. var
  189. P: Integer;
  190. I: TThreadPriority;
  191. begin
  192. P := {$ifdef ver1_0}Linux{$else}Unix{$endif}.GetPriority(Prio_Process,FHandle);
  193. Result := tpNormal;
  194. for I := Low(TThreadPriority) to High(TThreadPriority) do
  195. if Priorities[I] = P then
  196. Result := I;
  197. end;
  198. procedure TThread.SetPriority(Value: TThreadPriority);
  199. begin
  200. {$ifdef ver1_0}Linux{$else}Unix{$endif}.SetPriority(Prio_Process,FHandle, Priorities[Value]);
  201. end;
  202. procedure TThread.Synchronize(Method: TThreadMethod);
  203. begin
  204. FSynchronizeException := nil;
  205. FMethod := Method;
  206. { SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self)); }
  207. if Assigned(FSynchronizeException) then
  208. raise FSynchronizeException;
  209. end;
  210. procedure TThread.SetSuspended(Value: Boolean);
  211. begin
  212. if Value <> FSuspended then
  213. if Value then
  214. Suspend
  215. else
  216. Resume;
  217. end;
  218. procedure TThread.Suspend;
  219. begin
  220. Kill(FHandle, SIGSTOP);
  221. FSuspended := true;
  222. end;
  223. procedure TThread.Resume;
  224. begin
  225. Kill(FHandle, SIGCONT);
  226. FSuspended := False;
  227. end;
  228. procedure TThread.Terminate;
  229. begin
  230. FTerminated := True;
  231. end;
  232. function TThread.WaitFor: Integer;
  233. var
  234. status : longint;
  235. begin
  236. if FThreadID = MainThreadID then
  237. WaitPid(0,@status,0)
  238. else
  239. WaitPid(FHandle,@status,0);
  240. Result:=status;
  241. end;
  242. {
  243. $Log$
  244. Revision 1.5 2003-01-31 14:49:56 pierre
  245. * adapt 1.0 to change in signal.inc
  246. Revision 1.4 2003/01/24 21:13:31 marco
  247. * More bugs, but now gmake all works.
  248. Revision 1.3 2002/09/07 15:15:27 peter
  249. * old logs removed and tabs fixed
  250. }