IdThread.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.34 03/16/05 10:29:40 AM JSouthwell
  18. Added a default thread name to ease debugging of IdThreads.
  19. Rev 1.33 1/15/05 1:52:36 PM RLebeau
  20. Extra cleanup handling for the FYarn member
  21. Rev 1.32 1/6/2005 10:02:58 PM JPMugaas
  22. This should compile.
  23. Rev 1.31 1/6/05 2:33:04 PM RLebeau
  24. one more try...finally block, for Before/AfterExecute()
  25. Rev 1.29 1/5/05 5:31:08 PM RLebeau
  26. Added extra try..finally block to Execute() to free the FYarn member.
  27. Rev 1.28 6/9/2004 10:38:46 PM DSiders
  28. Fixed case for TIdNotifyThreadEvent.
  29. Rev 1.27 3/12/2004 7:11:02 PM BGooijen
  30. Changed order of commands for dotnet
  31. Rev 1.26 2004.03.01 5:12:44 PM czhower
  32. -Bug fix for shutdown of servers when connections still existed (AV)
  33. -Implicit HELP support in CMDserver
  34. -Several command handler bugs
  35. -Additional command handler functionality.
  36. Rev 1.25 2004.02.03 4:17:00 PM czhower
  37. For unit name changes.
  38. Rev 1.24 2004.01.22 5:59:12 PM czhower
  39. IdCriticalSection
  40. Rev 1.23 2003.12.28 2:33:16 PM czhower
  41. .Net finalization fix.
  42. Rev 1.22 2003.12.28 1:27:46 PM czhower
  43. .Net compatibility
  44. Rev 1.21 2003.10.24 12:59:20 PM czhower
  45. Name change
  46. Rev 1.20 2003.10.21 12:19:04 AM czhower
  47. TIdTask support and fiber bug fixes.
  48. Rev 1.19 10/15/2003 8:40:48 PM DSiders
  49. Added locaization comments.
  50. Rev 1.18 10/5/2003 3:19:58 PM BGooijen
  51. disabled some stuff for DotNet
  52. Rev 1.17 2003.09.19 10:11:22 PM czhower
  53. Next stage of fiber support in servers.
  54. Rev 1.14 2003.09.19 11:54:36 AM czhower
  55. -Completed more features necessary for servers
  56. -Fixed some bugs
  57. Rev 1.13 2003.09.18 4:43:18 PM czhower
  58. -Removed IdBaseThread
  59. -Threads now have default names
  60. Rev 1.12 12.9.2003 ã. 16:42:08 DBondzhev
  61. Fixed AV when exception is raised in BeforeRun and thread is terminated
  62. before Start is compleated
  63. Rev 1.11 2003.07.08 2:41:52 PM czhower
  64. Avoid calling SetThreadName if we do not need to
  65. Rev 1.10 08.07.2003 13:16:18 ARybin
  66. tiny opt fix
  67. Rev 1.9 7/1/2003 7:11:30 PM BGooijen
  68. Added comment
  69. Rev 1.8 2003.07.01 4:14:58 PM czhower
  70. Consolidation.
  71. Added Name, Loop
  72. Rev 1.7 04.06.2003 14:06:20 ARybin
  73. bug fix & limited waiting
  74. Rev 1.6 28.05.2003 14:16:16 ARybin
  75. WaitAllThreadsTerminated class method
  76. Rev 1.5 08.05.2003 12:45:10 ARybin
  77. "be sure" fix
  78. Rev 1.4 4/30/2003 4:53:26 PM BGooijen
  79. Fixed bug in Kylix where GThreadCount was not decremented
  80. Rev 1.3 4/22/2003 4:44:06 PM BGooijen
  81. changed Handle to ThreadID
  82. Rev 1.2 3/22/2003 12:53:26 PM BGooijen
  83. - Exceptions in the constructor are now handled better.
  84. - GThreadCount can't become negative anymore
  85. Rev 1.1 06.03.2003 11:54:24 ARybin
  86. TIdThreadOptions: is thread Data owner, smart Cleanup
  87. Rev 1.0 11/13/2002 09:01:14 AM JPMugaas
  88. 2002-03-12 -Andrew P.Rybin
  89. -TerminatingExceptionClass, etc.
  90. 2002-06-20 -Andrew P.Rybin
  91. -"Terminated Start" bug fix (FLock.Leave AV)
  92. -Wait All threads termination in FINALIZATION (prevent AV in WinSock)
  93. -HandleRunException
  94. 2003-01-27 -Andrew P.Rybin
  95. -TIdThreadOptions
  96. }
  97. unit IdThread;
  98. {
  99. 2002-03-12 -Andrew P.Rybin
  100. -TerminatingExceptionClass, etc.
  101. 2002-06-20 -Andrew P.Rybin
  102. -"Terminated Start" bug fix (FLock.Leave AV)
  103. -Wait All threads termination in FINALIZATION (prevent AV in WinSock)
  104. -HandleRunException
  105. 2003-01-27 -Andrew P.Rybin
  106. -TIdThreadOptions
  107. }
  108. interface
  109. {$I IdCompilerDefines.inc}
  110. // RLebeau: On OSX/iOS, an auto-release object pool should be used to clean up
  111. // Objective-C objects that are created within a thread. On Android, any thread
  112. // that uses Java objects will attach to the JVM and must be detached from the
  113. // JVM before terminating.
  114. //
  115. // All objects must be released before terminating/detaching the thread.
  116. //
  117. // This problem was fixed in TThread in RAD Studio XE6.
  118. //
  119. {$IF DEFINED(DCC) AND (NOT DEFINED(DCC_XE6_OR_ABOVE)) AND (DEFINED(MACOS) OR DEFINED(ANDROID))}
  120. {$DEFINE PLATFORM_CLEANUP_NEEDED}
  121. {$ELSE}
  122. // TODO: Does this need to be applied to FreePascal?
  123. {$UNDEF PLATFORM_CLEANUP_NEEDED}
  124. {$IFEND}
  125. uses
  126. Classes,
  127. IdGlobal, IdException, IdYarn, IdTask, IdThreadSafe, SysUtils;
  128. const
  129. IdWaitAllThreadsTerminatedCount = 1 * 60 * 1000;
  130. IdWaitAllThreadsTerminatedStep = 250;
  131. type
  132. EIdThreadException = class(EIdException);
  133. EIdThreadTerminateAndWaitFor = class(EIdThreadException);
  134. TIdThreadStopMode = (smTerminate, smSuspend);
  135. TIdThread = class;
  136. TIdExceptionThreadEvent = procedure(AThread: TIdThread; AException: Exception) of object;
  137. TIdNotifyThreadEvent = procedure(AThread: TIdThread) of object;
  138. TIdSynchronizeThreadEvent = procedure(AThread: TIdThread; AData: Pointer) of object;
  139. // Note: itoDataOwner doesn't make sense in DCC nextgen when AutoRefCounting is enabled...
  140. TIdThreadOptions = set of (itoStopped, itoReqCleanup, itoDataOwner, itoTag);
  141. TIdThread = class(TThread)
  142. protected
  143. // When ARC is enabled, object references MUST be valid objects.
  144. // It is common for users to store non-object values, though, so
  145. // we will provide separate properties for those purposes
  146. FDataObject: TObject;
  147. FDataValue: PtrInt;
  148. //
  149. FLock: TIdCriticalSection;
  150. FLoop: Boolean;
  151. FName: string;
  152. FStopMode: TIdThreadStopMode;
  153. FOptions: TIdThreadOptions;
  154. FTerminatingException: String;
  155. FTerminatingExceptionClass: TClass;
  156. FYarn: TIdYarn;
  157. //
  158. FOnException: TIdExceptionThreadEvent;
  159. FOnStopped: TIdNotifyThreadEvent;
  160. //
  161. {$IF DEFINED(PLATFORM_CLEANUP_NEEDED) AND DEFINED(MACOS)}
  162. FObjCPool: Pointer;
  163. {$IFEND}
  164. procedure AfterRun; virtual; //3* not abstract - otherwise it is required
  165. procedure AfterExecute; virtual;//5 not abstract - otherwise it is required
  166. procedure BeforeExecute; virtual;//1 not abstract - otherwise it is required
  167. procedure BeforeRun; virtual; //2* not abstract - otherwise it is required
  168. procedure Cleanup; virtual;//4*
  169. procedure DoException(AException: Exception); virtual;
  170. procedure DoStopped; virtual;
  171. procedure Execute; override;
  172. {$IFDEF PLATFORM_CLEANUP_NEEDED}
  173. procedure DoTerminate; override;
  174. {$ENDIF}
  175. function GetStopped: Boolean;
  176. function HandleRunException(AException: Exception): Boolean; virtual;
  177. procedure Run; virtual; abstract;
  178. class procedure WaitAllThreadsTerminated(AMSec: Integer = IdWaitAllThreadsTerminatedCount); deprecated;
  179. public
  180. constructor Create(ACreateSuspended: Boolean = True;
  181. ALoop: Boolean = True; const AName: string = ''); virtual;
  182. destructor Destroy; override;
  183. procedure Start; {$IFDEF DEPRECATED_TThread_SuspendResume}reintroduce;{$ENDIF} virtual;
  184. procedure Stop; virtual;
  185. procedure Synchronize(Method: TThreadMethod); overload;
  186. {$IFDEF HAS_TThreadProcedure}
  187. procedure Synchronize(Method: TThreadProcedure); overload;
  188. {$ENDIF}
  189. // Here to make virtual
  190. procedure Terminate; virtual;
  191. procedure TerminateAndWaitFor; virtual;
  192. //
  193. property DataObject: TObject read FDataObject write FDataObject;
  194. property DataValue: PtrInt read FDataValue write FDataValue;
  195. {$IFNDEF USE_OBJECT_ARC}
  196. property Data: TObject read FDataObject write FDataObject; // deprecated 'Use DataObject or DataValue property.';
  197. {$ENDIF}
  198. property Loop: Boolean read FLoop write FLoop;
  199. property Name: string read FName write FName;
  200. property ReturnValue;
  201. property StopMode: TIdThreadStopMode read FStopMode write FStopMode;
  202. property Stopped: Boolean read GetStopped;
  203. property Terminated;
  204. // TODO: Change this to be like TIdFiber. D6 implementation is not as good
  205. // as what is done in TIdFiber.
  206. property TerminatingException: string read FTerminatingException;
  207. property TerminatingExceptionClass: TClass read FTerminatingExceptionClass;
  208. //Represents the thread or fiber for the scheduler of the thread.
  209. property Yarn: TIdYarn read FYarn write FYarn;
  210. //
  211. property OnException: TIdExceptionThreadEvent read FOnException write FOnException;
  212. property OnStopped: TIdNotifyThreadEvent read FOnStopped write FOnStopped;
  213. end;
  214. TIdThreadWithTask = class(TIdThread)
  215. protected
  216. FTask: TIdTask;
  217. //
  218. procedure AfterRun; override;
  219. procedure BeforeRun; override;
  220. procedure Run; override;
  221. procedure DoException(AException: Exception); override;
  222. procedure SetTask(AValue: TIdTask);
  223. public
  224. // Defaults because
  225. // Must always create suspended so task can be set
  226. // And a bit crazy to create a non looped task
  227. constructor Create(ATask: TIdTask = nil; const AName: string = ''); reintroduce; virtual;
  228. destructor Destroy; override;
  229. //
  230. // Must be writeable because tasks are often created after thread or
  231. // thread is pooled
  232. property Task: TIdTask read FTask write SetTask;
  233. end;
  234. TIdThreadClass = class of TIdThread;
  235. TIdThreadWithTaskClass = class of TIdThreadWithTask;
  236. var
  237. // GThreadCount should be in implementation as it is not needed outside of
  238. // this unit. However with D8, GThreadCount will be deallocated before the
  239. // finalization can run and thus when the finalization accesses GThreadCount
  240. // in TerminateAll an error occurs. Moving this declaration to the interface
  241. // "fixes" it.
  242. GThreadCount: TIdThreadSafeInteger = nil{$IFDEF USE_SEMICOLON_BEFORE_DEPRECATED};{$ENDIF} deprecated;
  243. implementation
  244. uses
  245. //facilitate inlining only.
  246. {$IFDEF USE_VCL_POSIX}
  247. Posix.SysSelect,
  248. Posix.SysTime,
  249. {$ENDIF}
  250. {$IFDEF DCC_XE3_OR_ABOVE}
  251. System.SyncObjs,
  252. {$ENDIF}
  253. {$IFDEF PLATFORM_CLEANUP_NEEDED}
  254. {$IFDEF MACOS}
  255. Macapi.ObjCRuntime,
  256. {$ENDIF}
  257. {$IFDEF ANDROID}
  258. Androidapi.NativeActivity,
  259. {$ENDIF}
  260. {$ENDIF}
  261. IdSchedulerOfThread, IdScheduler,
  262. IdResourceStringsCore;
  263. class procedure TIdThread.WaitAllThreadsTerminated(AMSec: Integer = IdWaitAllThreadsTerminatedCount);
  264. begin
  265. {$I IdSymbolDeprecatedOff.inc}
  266. while AMSec > 0 do begin
  267. if GThreadCount.Value = 0 then begin
  268. Break;
  269. end;
  270. IndySleep(IdWaitAllThreadsTerminatedStep);
  271. AMSec := AMSec - IdWaitAllThreadsTerminatedStep;
  272. end;
  273. {$I IdSymbolDeprecatedOn.inc}
  274. end;
  275. procedure TIdThread.TerminateAndWaitFor;
  276. begin
  277. if FreeOnTerminate then begin
  278. raise EIdThreadTerminateAndWaitFor.Create(RSThreadTerminateAndWaitFor);
  279. end;
  280. Terminate;
  281. Start; //resume
  282. WaitFor;
  283. end;
  284. procedure TIdThread.BeforeRun;
  285. begin
  286. end;
  287. procedure TIdThread.AfterRun;
  288. begin
  289. end;
  290. procedure TIdThread.BeforeExecute;
  291. begin
  292. end;
  293. procedure TIdThread.AfterExecute;
  294. begin
  295. end;
  296. procedure TIdThread.Execute;
  297. begin
  298. // Must make this call from INSIDE the thread. The call in Create
  299. // was naming the thread that was creating this thread. :(
  300. //
  301. // RLebeau - no need to put this inside the try blocks below as it
  302. // already uses its own try..except block internally
  303. if Name = '' then begin
  304. Name := 'IdThread (unknown)'; {do not localize}
  305. end;
  306. SetThreadName(Name);
  307. {$IF DEFINED(PLATFORM_CLEANUP_NEEDED) AND DEFINED(MACOS)}
  308. // Register the auto release pool
  309. FObjCPool := objc_msgSend(objc_msgSend(objc_getClass('NSAutoreleasePool'), sel_getUid('alloc')), sel_getUid('init')); {do not localize}
  310. {$IFEND}
  311. try
  312. BeforeExecute;
  313. try
  314. while not Terminated do begin
  315. if Stopped then begin
  316. DoStopped;
  317. // It is possible that either in the DoStopped or from another thread,
  318. // the thread is restarted, in which case we dont want to restop it.
  319. if Stopped then begin // DONE: if terminated?
  320. if Terminated then begin
  321. Break;
  322. end;
  323. // Thread manager will revive us
  324. {$IFDEF DEPRECATED_TThread_SuspendResume}
  325. Suspended := True;
  326. {$ELSE}
  327. Suspend;
  328. {$ENDIF}
  329. if Terminated then begin
  330. Break;
  331. end;
  332. end;
  333. end;
  334. Include(FOptions, itoReqCleanup);
  335. try
  336. try
  337. try
  338. BeforeRun;
  339. if Loop then begin
  340. while not Stopped do begin
  341. try
  342. Run;
  343. except
  344. on E: Exception do begin
  345. if not HandleRunException(E) then begin
  346. Terminate;
  347. raise;
  348. end;
  349. end;
  350. end;
  351. end;
  352. end else begin
  353. try
  354. Run;
  355. except
  356. on E: Exception do begin
  357. if not HandleRunException(E) then begin
  358. Terminate;
  359. raise;
  360. end;
  361. end;
  362. end;
  363. end;
  364. finally
  365. AfterRun;
  366. end;
  367. except
  368. Terminate;
  369. raise;
  370. end;
  371. finally
  372. Cleanup;
  373. end;
  374. end;
  375. finally
  376. AfterExecute;
  377. end;
  378. except
  379. on E: Exception do begin
  380. FTerminatingExceptionClass := E.ClassType;
  381. FTerminatingException := E.Message;
  382. DoException(E);
  383. Terminate;
  384. end;
  385. end;
  386. end;
  387. {$IFDEF PLATFORM_CLEANUP_NEEDED}
  388. procedure TIdThread.DoTerminate;
  389. {$IFDEF ANDROID}
  390. var
  391. PActivity: PANativeActivity;
  392. {$ENDIF}
  393. begin
  394. try
  395. inherited;
  396. finally
  397. {$IFDEF MACOS}
  398. // Last thing to do in thread is to drain the pool
  399. objc_msgSend(FObjCPool, sel_getUid('drain')); {do not localize}
  400. {$ENDIF}
  401. {$IFDEF ANDROID}
  402. // Detach the NativeActivity virtual machine to ensure the proper release of JNI contexts attached to the current thread
  403. PActivity := PANativeActivity(System.DelphiActivity);
  404. PActivity^.vm^.DetachCurrentThread(PActivity^.vm);
  405. {$ENDIF}
  406. end;
  407. end;
  408. {$ENDIF}
  409. constructor TIdThread.Create(ACreateSuspended: Boolean; ALoop: Boolean; const AName: string);
  410. begin
  411. FOptions := [itoDataOwner];
  412. if ACreateSuspended then begin
  413. Include(FOptions, itoStopped);
  414. end;
  415. FLock := TIdCriticalSection.Create;
  416. Loop := ALoop;
  417. Name := AName;
  418. // Most things BEFORE inherited - inherited creates the actual thread and if
  419. // not suspended will start before we initialize
  420. inherited Create(ACreateSuspended);
  421. // Last, so we only do this if successful
  422. {$I IdSymbolDeprecatedOff.inc}
  423. GThreadCount.Increment;
  424. {$I IdSymbolDeprecatedOn.inc}
  425. end;
  426. destructor TIdThread.Destroy;
  427. begin
  428. inherited Destroy;
  429. try
  430. if itoReqCleanup in FOptions then begin
  431. Cleanup;
  432. end;
  433. finally
  434. // RLebeau- clean up the Yarn one more time, in case the thread was
  435. // terminated after the Yarn was assigned but the thread was not
  436. // re-started, so the Yarn would not be freed in Cleanup()
  437. try
  438. IdDisposeAndNil(FYarn);
  439. finally
  440. // Protect FLock if thread was resumed by Start Method and we are still there.
  441. // This usually happens if Exception was raised in BeforeRun for some reason
  442. // And thread was terminated there before Start method is completed.
  443. FLock.Enter; try
  444. finally FLock.Leave; end;
  445. FLock.Free;
  446. {$I IdSymbolDeprecatedOff.inc}
  447. GThreadCount.Decrement;
  448. {$I IdSymbolDeprecatedOn.inc}
  449. end;
  450. end;
  451. end;
  452. procedure TIdThread.Start;
  453. begin
  454. FLock.Enter; try
  455. if Stopped then begin
  456. // Resume is also called for smTerminate as .Start can be used to initially start a
  457. // thread that is created suspended
  458. if Terminated then begin
  459. Include(FOptions,itoStopped);
  460. end else begin
  461. Exclude(FOptions,itoStopped);
  462. end;
  463. {$IFDEF DEPRECATED_TThread_SuspendResume}
  464. Suspended := False;
  465. {$ELSE}
  466. Resume;
  467. {$ENDIF}
  468. {APR: [in past] thread can be destroyed here! now Destroy wait FLock}
  469. end;
  470. finally FLock.Leave; end;
  471. end;
  472. procedure TIdThread.Stop;
  473. begin
  474. FLock.Enter; try
  475. if not Stopped then begin
  476. case FStopMode of
  477. smTerminate: Terminate;
  478. smSuspend: {DO not suspend here. Suspend is immediate. See Execute for implementation};
  479. end;
  480. Include(FOptions, itoStopped);
  481. end;
  482. finally FLock.Leave; end;
  483. end;
  484. function TIdThread.GetStopped: Boolean;
  485. begin
  486. if Assigned(FLock) then begin
  487. FLock.Enter; try
  488. // Suspended may be True if checking stopped from another thread
  489. Result := Terminated or (itoStopped in FOptions) or Suspended;
  490. finally FLock.Leave; end;
  491. end else begin
  492. Result := True; //user call Destroy
  493. end;
  494. end;
  495. procedure TIdThread.DoStopped;
  496. begin
  497. if Assigned(OnStopped) then begin
  498. OnStopped(Self);
  499. end;
  500. end;
  501. procedure TIdThread.DoException(AException: Exception);
  502. begin
  503. if Assigned(FOnException) then begin
  504. FOnException(Self, AException);
  505. end;
  506. end;
  507. procedure TIdThread.Terminate;
  508. begin
  509. //this assert can only raise if terminate is called on an already-destroyed thread
  510. Assert(FLock<>nil);
  511. FLock.Enter; try
  512. Include(FOptions, itoStopped);
  513. inherited Terminate;
  514. finally FLock.Leave; end;
  515. end;
  516. type
  517. TIdYarnOfThreadAccess = class(TIdYarnOfThread)
  518. end;
  519. procedure TIdThread.Cleanup;
  520. var
  521. LScheduler: TIdScheduler;
  522. LList: TIdYarnList;
  523. begin
  524. Exclude(FOptions, itoReqCleanup);
  525. // RLebeau 9/20/2019: there is a race condition here with TIdScheduler.TerminateAllYarns().
  526. // Notify TIdScheduler of the Yarn being freed here, otherwise, a double free of the Yarn
  527. // can happen if TIdThread.Cleanup() and TIdSchedulerOfThread.TerminateYarn() try to destroy
  528. // the Yarn at the same time. TerminateYarn() destroys the Yarn inside the ActiveYarns lock,
  529. // so the destroy here needs to be done inside of the same lock...
  530. //IdDisposeAndNil(FYarn);
  531. if FYarn is TIdYarnOfThread then
  532. begin
  533. {$I IdObjectChecksOff.inc}
  534. LScheduler := TIdYarnOfThreadAccess(FYarn).FScheduler;
  535. {$I IdObjectChecksOn.inc}
  536. if Assigned(LScheduler) then
  537. begin
  538. LList := LScheduler.ActiveYarns.LockList;
  539. try
  540. // if the Yarn is still in the list, remove and destroy it now.
  541. // If not, assume TIdScheduler has already done so ...
  542. if LList.Remove(FYarn) <> -1 then begin
  543. IdDisposeAndNil(FYarn);
  544. end;
  545. finally
  546. LScheduler.ActiveYarns.UnlockList;
  547. end;
  548. end;
  549. end else
  550. begin
  551. // just free the Yarn normally and let it figure out what to do...
  552. // TODO: is special handling needed for TIdYarnOfFiber like above?
  553. IdDisposeAndNil(FYarn);
  554. end;
  555. if itoDataOwner in FOptions then begin
  556. IdDisposeAndNil(FDataObject);
  557. end else begin
  558. FDataObject := nil;
  559. end;
  560. FDataValue := 0;
  561. end;
  562. function TIdThread.HandleRunException(AException: Exception): Boolean;
  563. begin
  564. // Default behavior: Exception is death sentence
  565. Result := False;
  566. end;
  567. procedure TIdThread.Synchronize(Method: TThreadMethod);
  568. begin
  569. inherited Synchronize(Method);
  570. end;
  571. {$IFDEF HAS_TThreadProcedure}
  572. procedure TIdThread.Synchronize(Method: TThreadProcedure);
  573. begin
  574. inherited Synchronize(Method);
  575. end;
  576. {$ENDIF}
  577. { TIdThreadWithTask }
  578. procedure TIdThreadWithTask.AfterRun;
  579. begin
  580. FTask.DoAfterRun;
  581. inherited AfterRun;
  582. end;
  583. procedure TIdThreadWithTask.BeforeRun;
  584. begin
  585. inherited BeforeRun;
  586. FTask.DoBeforeRun;
  587. end;
  588. procedure TIdThreadWithTask.DoException(AException: Exception);
  589. begin
  590. inherited DoException(AException);
  591. FTask.DoException(AException);
  592. end;
  593. constructor TIdThreadWithTask.Create(ATask: TIdTask; const AName: string);
  594. begin
  595. inherited Create(True, True, AName);
  596. FTask := ATask;
  597. end;
  598. destructor TIdThreadWithTask.Destroy;
  599. begin
  600. FTask.Free;
  601. inherited Destroy;
  602. end;
  603. procedure TIdThreadWithTask.Run;
  604. begin
  605. if not FTask.DoRun then begin
  606. Stop;
  607. end;
  608. end;
  609. procedure TIdThreadWithTask.SetTask(AValue: TIdTask);
  610. begin
  611. if FTask <> AValue then begin
  612. FreeAndNil(FTask);
  613. FTask := AValue;
  614. end;
  615. end;
  616. {$IFDEF REGISTER_EXPECTED_MEMORY_LEAK}
  617. type
  618. TIdThreadSafeInt32Access = class(TIdThreadSafeInt32);
  619. {$ENDIF}
  620. initialization
  621. // RLebeau 7/19/09: According to RAID #271221:
  622. //
  623. // "Indy always names the main thread. It should not name the main thread,
  624. // it should only name threads that it creates. This basically means that
  625. // any app that uses Indy will end up with the main thread named "Main".
  626. //
  627. // The IDE currently names it's main thread, but because Indy is used by
  628. // the dcldbx140.bpl package which gets loaded by the IDE, the name used
  629. // for the main thread always ends up being overwritten with the name
  630. // Indy gives it."
  631. //
  632. // So, DO NOT uncomment the following line...
  633. // SetThreadName('Main'); {do not localize}
  634. {$I IdSymbolDeprecatedOff.inc}
  635. GThreadCount := TIdThreadSafeInt32.Create;
  636. {$IF (NOT DEFINED(FREE_ON_FINAL)) AND DEFINED(REGISTER_EXPECTED_MEMORY_LEAK)}
  637. IndyRegisterExpectedMemoryLeak(GThreadCount);
  638. {$I IdObjectChecksOff.inc}
  639. IndyRegisterExpectedMemoryLeak(TIdThreadSafeInt32Access(GThreadCount).FCriticalSection);
  640. {$I IdObjectChecksOn.inc}
  641. {$IFEND}
  642. {$I IdSymbolDeprecatedOn.inc}
  643. finalization
  644. // This call hangs if not all threads have been properly destroyed.
  645. // But without this, bad threads can often have worse results. Catch 22.
  646. // TIdThread.WaitAllThreadsTerminated;
  647. {$IFDEF FREE_ON_FINAL}
  648. //only enable this if you know your code exits thread-clean
  649. {$I IdSymbolDeprecatedOff.inc}
  650. FreeAndNil(GThreadCount);
  651. {$I IdSymbolDeprecatedOn.inc}
  652. {$ENDIF}
  653. end.