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 zeroset :sigset = (0,0,0,0);
  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. {$ifndef ver1_0}
  61. Act^.sa_handler := @SIGCHLDHandler;
  62. fillchar(Act^.sa_mask,sizeof(sigset_t),#0);
  63. {$else}
  64. Act^.handler.sh := @SIGCHLDHandler;
  65. Act^.sa_mask := zeroset;
  66. {$endif}
  67. Act^.sa_flags := SA_NOCLDSTOP {or SA_NOMASK or SA_RESTART};
  68. //Do not block all signals ??. Don't need if SA_NOMASK in flags
  69. SigAction(SIGCHLD, Act, OldAct);
  70. FreeMem(Act, SizeOf(SigActionRec));
  71. FreeMem(OldAct, SizeOf(SigActionRec));
  72. end;
  73. procedure DoneThreads;
  74. var
  75. hp : PThreadRec;
  76. begin
  77. while assigned(ThreadRoot) do
  78. begin
  79. ThreadRoot^.Thread.Destroy;
  80. hp:=ThreadRoot;
  81. ThreadRoot:=ThreadRoot^.Next;
  82. dispose(hp);
  83. end;
  84. ThreadsInited:=false;
  85. end;
  86. procedure AddThread(t:TThread);
  87. var
  88. hp : PThreadRec;
  89. begin
  90. { Need to initialize threads ? }
  91. if not ThreadsInited then
  92. InitThreads;
  93. { Put thread in the linked list }
  94. new(hp);
  95. hp^.Thread:=t;
  96. hp^.next:=ThreadRoot;
  97. ThreadRoot:=hp;
  98. inc(ThreadCount, 1);
  99. end;
  100. procedure RemoveThread(t:TThread);
  101. var
  102. lasthp,hp : PThreadRec;
  103. begin
  104. hp:=ThreadRoot;
  105. lasthp:=nil;
  106. while assigned(hp) do
  107. begin
  108. if hp^.Thread=t then
  109. begin
  110. if assigned(lasthp) then
  111. lasthp^.next:=hp^.next
  112. else
  113. ThreadRoot:=hp^.next;
  114. dispose(hp);
  115. exit;
  116. end;
  117. lasthp:=hp;
  118. hp:=hp^.next;
  119. end;
  120. Dec(ThreadCount, 1);
  121. if ThreadCount = 0 then DoneThreads;
  122. end;
  123. { TThread }
  124. function ThreadProc(args:pointer): Integer;cdecl;
  125. var
  126. FreeThread: Boolean;
  127. Thread : TThread absolute args;
  128. begin
  129. Thread.Execute;
  130. FreeThread := Thread.FFreeOnTerminate;
  131. Result := Thread.FReturnValue;
  132. Thread.FFinished := True;
  133. Thread.DoTerminate;
  134. if FreeThread then
  135. Thread.Free;
  136. ExitProcess(Result);
  137. end;
  138. constructor TThread.Create(CreateSuspended: Boolean);
  139. var
  140. Flags: Integer;
  141. begin
  142. inherited Create;
  143. AddThread(self);
  144. FSuspended := CreateSuspended;
  145. Flags := CLONE_VM + CLONE_FS + CLONE_FILES + CLONE_SIGHAND + SIGCHLD;
  146. { Setup 16k of stack }
  147. FStackSize:=16384;
  148. Getmem(pointer(FStackPointer),FStackSize);
  149. inc(FStackPointer,FStackSize);
  150. FCallExitProcess:=false;
  151. { Clone }
  152. FHandle:= Clone(@ThreadProc,pointer(FStackPointer),Flags,self);
  153. if FSuspended then Suspend;
  154. FThreadID := FHandle;
  155. IsMultiThread := TRUE;
  156. end;
  157. destructor TThread.Destroy;
  158. begin
  159. if not FFinished and not Suspended then
  160. begin
  161. Terminate;
  162. WaitFor;
  163. end;
  164. if FHandle <> -1 then
  165. Kill(FHandle, SIGKILL);
  166. dec(FStackPointer,FStackSize);
  167. Freemem(pointer(FStackPointer),FStackSize);
  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.9 2003-01-17 19:01:07 marco
  243. * small fix
  244. Revision 1.8 2002/11/17 21:09:44 marco
  245. * 16byte sigset
  246. Revision 1.7 2002/10/24 12:47:54 marco
  247. * Fix emptying sa_mask
  248. Revision 1.6 2002/09/07 15:15:24 peter
  249. * old logs removed and tabs fixed
  250. }