thread.inc 5.7 KB

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