thread.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. {
  2. This file is part of the Free Pascal Run time library.
  3. Copyright (c) 2000 by the Free Pascal development team
  4. OS independent thread functions/overloads
  5. See the File COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. Var
  12. CurrentTM : TThreadManager;
  13. {*****************************************************************************
  14. Threadvar initialization
  15. *****************************************************************************}
  16. procedure InitThread(stklen:SizeUInt);
  17. begin
  18. {$ifndef FPUNONE}
  19. SysResetFPU;
  20. SysInitFPU;
  21. {$endif}
  22. {$ifndef HAS_MEMORYMANAGER}
  23. { initialize this thread's heap }
  24. InitHeapThread;
  25. {$endif HAS_MEMORYMANAGER}
  26. if MemoryManager.InitThread <> nil then
  27. MemoryManager.InitThread();
  28. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  29. if assigned(widestringmanager.ThreadInitProc) then
  30. widestringmanager.ThreadInitProc;
  31. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  32. {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
  33. { ExceptAddrStack and ExceptObjectStack are threadvars }
  34. { so every thread has its on exception handling capabilities }
  35. SysInitExceptions;
  36. {$endif FPC_HAS_FEATURE_EXCEPTIONS}
  37. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  38. { Open all stdio fds again }
  39. SysInitStdio;
  40. InOutRes:=0;
  41. // ErrNo:=0;
  42. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  43. {$ifdef FPC_HAS_FEATURE_STACKCHECK}
  44. { Stack checking }
  45. StackLength:= CheckInitialStkLen(stkLen);
  46. StackBottom:=Sptr - StackLength;
  47. {$endif FPC_HAS_FEATURE_STACKCHECK}
  48. ThreadID := CurrentTM.GetCurrentThreadID();
  49. end;
  50. procedure DoneThread;
  51. begin
  52. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  53. if assigned(widestringmanager.ThreadFiniProc) then
  54. widestringmanager.ThreadFiniProc;
  55. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  56. {$ifndef HAS_MEMORYMANAGER}
  57. FinalizeHeap;
  58. {$endif HAS_MEMORYMANAGER}
  59. if MemoryManager.DoneThread <> nil then
  60. MemoryManager.DoneThread();
  61. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  62. { Open all stdio fds again }
  63. SysFlushStdio;
  64. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  65. { Support platforms where threadvar memory is managed outside of the RTL:
  66. reset ThreadID and allow ReleaseThreadVars to be unassigned }
  67. ThreadID := TThreadID(0);
  68. if assigned(CurrentTM.ReleaseThreadVars) then
  69. CurrentTM.ReleaseThreadVars;
  70. end;
  71. {*****************************************************************************
  72. Overloaded functions
  73. *****************************************************************************}
  74. function BeginThread(ThreadFunction : tthreadfunc) : TThreadID;
  75. var
  76. dummy : TThreadID;
  77. begin
  78. BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,nil,0,dummy);
  79. end;
  80. function BeginThread(ThreadFunction : tthreadfunc;p : pointer) : TThreadID;
  81. var
  82. dummy : TThreadID;
  83. begin
  84. BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,dummy);
  85. end;
  86. function BeginThread(ThreadFunction : tthreadfunc;p : pointer;var ThreadId : TThreadID) : TThreadID;
  87. begin
  88. BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,ThreadId);
  89. end;
  90. function BeginThread(ThreadFunction : tthreadfunc;p : pointer;
  91. var ThreadId : TThreadID; const stacksize: SizeUInt) : TThreadID;
  92. begin
  93. BeginThread:=BeginThread(nil,stacksize,ThreadFunction,p,0,ThreadId);
  94. end;
  95. procedure EndThread;
  96. begin
  97. EndThread(0);
  98. end;
  99. function BeginThread(sa : Pointer;stacksize : SizeUInt; ThreadFunction : tthreadfunc;p : pointer;creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
  100. begin
  101. Result:=CurrentTM.BeginThread(sa,stacksize,threadfunction,P,creationflags,ThreadID);
  102. end;
  103. procedure FlushThread;
  104. begin
  105. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  106. { Make sure that all output is written to the redirected file }
  107. Flush(Output);
  108. Flush(ErrOutput);
  109. Flush(StdOut);
  110. Flush(StdErr);
  111. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  112. end;
  113. procedure EndThread(ExitCode : DWord);
  114. begin
  115. FlushThread;
  116. CurrentTM.EndThread(ExitCode);
  117. end;
  118. function SuspendThread (threadHandle : TThreadID) : dword;
  119. begin
  120. Result:=CurrentTM.SuspendThread(ThreadHandle);
  121. end;
  122. function ResumeThread (threadHandle : TThreadID) : dword;
  123. begin
  124. Result:=CurrentTM.ResumeThread(ThreadHandle);
  125. end;
  126. function CloseThread (threadHandle : TThreadID):dword;
  127. begin
  128. result:=CurrentTM.CloseThread(ThreadHandle);
  129. end;
  130. procedure ThreadSwitch;
  131. begin
  132. CurrentTM.ThreadSwitch;
  133. end;
  134. function KillThread (threadHandle : TThreadID) : dword;
  135. begin
  136. Result:=CurrentTM.KillThread(ThreadHandle);
  137. end;
  138. function WaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;
  139. begin
  140. Result:=CurrentTM.WaitForThreadTerminate(ThreadHandle,TimeOutMS);
  141. end;
  142. function ThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean;
  143. begin
  144. Result:=CurrentTM.ThreadSetPriority(ThreadHandle,Prio);
  145. end;
  146. function ThreadGetPriority (threadHandle : TThreadID): longint;
  147. begin
  148. Result:=CurrentTM.ThreadGetPriority(ThreadHandle);
  149. end;
  150. function GetCurrentThreadId : TThreadID;
  151. begin
  152. Result:=CurrentTM.GetCurrentThreadID();
  153. end;
  154. procedure InitCriticalSection(var cs : TRTLCriticalSection);
  155. begin
  156. CurrentTM.InitCriticalSection(cs);
  157. end;
  158. procedure DoneCriticalsection(var cs : TRTLCriticalSection);
  159. begin
  160. CurrentTM.DoneCriticalSection(cs);
  161. end;
  162. procedure EnterCriticalsection(var cs : TRTLCriticalSection);
  163. begin
  164. CurrentTM.EnterCriticalSection(cs);
  165. end;
  166. function TryEnterCriticalsection(var cs : TRTLCriticalSection):longint;
  167. begin
  168. result:=CurrentTM.TryEnterCriticalSection(cs);
  169. end;
  170. procedure LeaveCriticalsection(var cs : TRTLCriticalSection);
  171. begin
  172. CurrentTM.LeaveCriticalSection(cs);
  173. end;
  174. Function GetThreadManager(Var TM : TThreadManager) : Boolean;
  175. begin
  176. TM:=CurrentTM;
  177. Result:=True;
  178. end;
  179. Function SetThreadManager(Const NewTM : TThreadManager; Var OldTM : TThreadManager) : Boolean;
  180. begin
  181. GetThreadManager(OldTM);
  182. Result:=SetThreadManager(NewTM);
  183. end;
  184. Function SetThreadManager(Const NewTM : TThreadManager) : Boolean;
  185. begin
  186. Result:=True;
  187. If Assigned(CurrentTM.DoneManager) then
  188. Result:=CurrentTM.DoneManager();
  189. If Result then
  190. begin
  191. CurrentTM:=NewTM;
  192. If Assigned(CurrentTM.InitManager) then
  193. Result:=CurrentTM.InitManager();
  194. end;
  195. end;
  196. function BasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  197. begin
  198. result:=currenttm.BasicEventCreate(EventAttributes,AManualReset,InitialState, Name);
  199. end;
  200. procedure basiceventdestroy(state:peventstate);
  201. begin
  202. currenttm.basiceventdestroy(state);
  203. end;
  204. procedure basiceventResetEvent(state:peventstate);
  205. begin
  206. currenttm.basiceventResetEvent(state);
  207. end;
  208. procedure basiceventSetEvent(state:peventstate);
  209. begin
  210. currenttm.basiceventSetEvent(state);
  211. end;
  212. function basiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  213. begin
  214. result:=currenttm.basiceventWaitFor(Timeout,state);
  215. end;
  216. function RTLEventCreate :PRTLEvent;
  217. begin
  218. result:=currenttm.rtleventcreate();
  219. end;
  220. procedure RTLeventdestroy(state:pRTLEvent);
  221. begin
  222. currenttm.rtleventdestroy(state);
  223. end;
  224. procedure RTLeventSetEvent(state:pRTLEvent);
  225. begin
  226. currenttm.rtleventsetEvent(state);
  227. end;
  228. procedure RTLeventResetEvent(state:pRTLEvent);
  229. begin
  230. currenttm.rtleventResetEvent(state);
  231. end;
  232. procedure RTLeventWaitFor(state:pRTLEvent);
  233. begin
  234. currenttm.rtleventWaitFor(state);
  235. end;
  236. procedure RTLeventWaitFor(state:pRTLEvent;timeout : longint);
  237. begin
  238. currenttm.rtleventWaitForTimeout(state,timeout);
  239. end;
  240. procedure RTLeventsync(m:trtlmethod;p:tprocedure);
  241. begin
  242. currenttm.rtleventsync(m,p);
  243. end;
  244. { ---------------------------------------------------------------------
  245. ThreadManager which gives run-time error. Use if no thread support.
  246. ---------------------------------------------------------------------}
  247. {$ifndef DISABLE_NO_THREAD_MANAGER}
  248. { resourcestrings are not supported by the system unit,
  249. they are in the objpas unit and not available for fpc/tp modes }
  250. const
  251. SNoThreads = 'This binary has no thread support compiled in.';
  252. SRecompileWithThreads = 'Recompile the application with a thread-driver in the program uses clause before other units using thread.';
  253. Procedure NoThreadError;
  254. begin
  255. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  256. If IsConsole then
  257. begin
  258. Writeln(StdErr,SNoThreads);
  259. Writeln(StdErr,SRecompileWithThreads);
  260. end;
  261. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  262. RunError(232)
  263. end;
  264. function NoBeginThread(sa : Pointer;stacksize : PtrUInt;
  265. ThreadFunction : tthreadfunc;p : pointer;
  266. creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
  267. begin
  268. NoThreadError;
  269. result:=tthreadid(-1);
  270. end;
  271. procedure NoEndThread(ExitCode : DWord);
  272. begin
  273. NoThreadError;
  274. end;
  275. function NoThreadHandler (threadHandle : TThreadID) : dword;
  276. begin
  277. NoThreadError;
  278. result:=dword(-1);
  279. end;
  280. procedure NoThreadSwitch; {give time to other threads}
  281. begin
  282. NoThreadError;
  283. end;
  284. function NoCloseThread (threadHandle : TThreadID):dword;
  285. begin
  286. Result:=0; // avoid warnings.
  287. NoThreadError;
  288. end;
  289. function NoWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword; {0=no timeout}
  290. begin
  291. NoThreadError;
  292. result:=dword(-1);
  293. end;
  294. function NoThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
  295. begin
  296. NoThreadError;
  297. result:=false;
  298. end;
  299. function NoThreadGetPriority (threadHandle : TThreadID): longint;
  300. begin
  301. NoThreadError;
  302. result:=-1;
  303. end;
  304. function NoGetCurrentThreadId : TThreadID;
  305. begin
  306. if IsMultiThread then
  307. NoThreadError
  308. else
  309. ThreadingAlreadyUsed:=true;
  310. result:=ThreadID;
  311. end;
  312. procedure NoCriticalSection(var CS);
  313. begin
  314. if IsMultiThread then
  315. NoThreadError
  316. else
  317. ThreadingAlreadyUsed:=true;
  318. end;
  319. function NoTryEnterCriticalSection(var CS):longint;
  320. begin
  321. if IsMultiThread then
  322. NoThreadError
  323. else
  324. ThreadingAlreadyUsed:=true;
  325. end;
  326. procedure NoInitThreadvar(var offset : dword;size : dword);
  327. begin
  328. NoThreadError;
  329. end;
  330. function NoRelocateThreadvar(offset : dword) : pointer;
  331. begin
  332. NoThreadError;
  333. result:=nil;
  334. end;
  335. procedure NoAllocateThreadVars;
  336. begin
  337. NoThreadError;
  338. end;
  339. procedure NoReleaseThreadVars;
  340. begin
  341. NoThreadError;
  342. end;
  343. function noBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  344. begin
  345. if IsMultiThread then
  346. NoThreadError
  347. else
  348. ThreadingAlreadyUsed:=true;
  349. result:=nil;
  350. end;
  351. procedure nobasiceventdestroy(state:peventstate);
  352. begin
  353. if IsMultiThread then
  354. NoThreadError
  355. else
  356. ThreadingAlreadyUsed:=true;
  357. end;
  358. procedure nobasiceventResetEvent(state:peventstate);
  359. begin
  360. if IsMultiThread then
  361. NoThreadError
  362. else
  363. ThreadingAlreadyUsed:=true;
  364. end;
  365. procedure nobasiceventSetEvent(state:peventstate);
  366. begin
  367. if IsMultiThread then
  368. NoThreadError
  369. else
  370. ThreadingAlreadyUsed:=true;
  371. end;
  372. function nobasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  373. begin
  374. if IsMultiThread then
  375. NoThreadError
  376. else
  377. ThreadingAlreadyUsed:=true;
  378. result:=-1;
  379. end;
  380. function NORTLEventCreate :PRTLEvent;
  381. begin
  382. if IsMultiThread then
  383. NoThreadError
  384. else
  385. ThreadingAlreadyUsed:=true;
  386. result:=nil;
  387. end;
  388. procedure NORTLeventdestroy(state:pRTLEvent);
  389. begin
  390. if IsMultiThread then
  391. NoThreadError
  392. else
  393. ThreadingAlreadyUsed:=true
  394. end;
  395. procedure NORTLeventSetEvent(state:pRTLEvent);
  396. begin
  397. if IsMultiThread then
  398. NoThreadError
  399. else
  400. ThreadingAlreadyUsed:=true;
  401. end;
  402. procedure NORTLeventResetEvent(state:pRTLEvent);
  403. begin
  404. if IsMultiThread then
  405. NoThreadError
  406. else
  407. ThreadingAlreadyUsed:=true;
  408. end;
  409. procedure NORTLeventWaitFor(state:pRTLEvent);
  410. begin
  411. if IsMultiThread then
  412. NoThreadError
  413. else
  414. ThreadingAlreadyUsed:=true;
  415. end;
  416. procedure NORTLeventWaitForTimeout(state:pRTLEvent;timeout : longint);
  417. begin
  418. if IsMultiThread then
  419. NoThreadError
  420. else
  421. ThreadingAlreadyUsed:=true;
  422. end;
  423. procedure NORTLeventsync(m:trtlmethod;p:tprocedure);
  424. begin
  425. if IsMultiThread then
  426. NoThreadError
  427. else
  428. ThreadingAlreadyUsed:=true;
  429. end;
  430. function NoSemaphoreInit: Pointer;
  431. begin
  432. if IsMultiThread then
  433. NoThreadError
  434. else
  435. ThreadingAlreadyUsed:=true;
  436. result:=nil;
  437. end;
  438. procedure NoSemaphoreWait(const FSem: Pointer);
  439. begin
  440. NoThreadError;
  441. end;
  442. procedure NoSemaphorePost(const FSem: Pointer);
  443. begin
  444. if IsMultiThread then
  445. NoThreadError
  446. else
  447. ThreadingAlreadyUsed:=true;
  448. end;
  449. procedure NoSemaphoreDestroy(const FSem: Pointer);
  450. begin
  451. if IsMultiThread then
  452. NoThreadError
  453. else
  454. ThreadingAlreadyUsed:=true;
  455. end;
  456. Var
  457. NoThreadManager : TThreadManager;
  458. Procedure SetNoThreadManager;
  459. begin
  460. With NoThreadManager do
  461. begin
  462. InitManager :=Nil;
  463. DoneManager :=Nil;
  464. BeginThread :=@NoBeginThread;
  465. EndThread :=@NoEndThread;
  466. SuspendThread :=@NoThreadHandler;
  467. ResumeThread :=@NoThreadHandler;
  468. KillThread :=@NoThreadHandler;
  469. CloseThread :=@NoCloseThread;
  470. ThreadSwitch :=@NoThreadSwitch;
  471. WaitForThreadTerminate :=@NoWaitForThreadTerminate;
  472. ThreadSetPriority :=@NoThreadSetPriority;
  473. ThreadGetPriority :=@NoThreadGetPriority;
  474. GetCurrentThreadId :=@NoGetCurrentThreadId;
  475. InitCriticalSection :=@NoCriticalSection;
  476. DoneCriticalSection :=@NoCriticalSection;
  477. EnterCriticalSection :=@NoCriticalSection;
  478. TryEnterCriticalSection:=@NoTryEnterCriticalSection;
  479. LeaveCriticalSection :=@NoCriticalSection;
  480. InitThreadVar :=@NoInitThreadVar;
  481. RelocateThreadVar :=@NoRelocateThreadVar;
  482. AllocateThreadVars :=@NoAllocateThreadVars;
  483. ReleaseThreadVars :=@NoReleaseThreadVars;
  484. BasicEventCreate :=@NoBasicEventCreate;
  485. basiceventdestroy :=@Nobasiceventdestroy;
  486. basiceventResetEvent :=@NobasiceventResetEvent;
  487. basiceventSetEvent :=@NobasiceventSetEvent;
  488. basiceventWaitFor :=@NobasiceventWaitFor;
  489. rtlEventCreate :=@NortlEventCreate;
  490. rtleventdestroy :=@Nortleventdestroy;
  491. rtleventSetEvent :=@NortleventSetEvent;
  492. rtleventResetEvent :=@NortleventResetEvent;
  493. rtleventWaitFor :=@NortleventWaitFor;
  494. rtleventsync :=@Nortleventsync;
  495. rtleventwaitfortimeout :=@NortleventWaitForTimeout;
  496. // semaphores stuff
  497. SemaphoreInit :=@NoSemaphoreInit;
  498. SemaphoreDestroy :=@NoSemaphoreDestroy;
  499. SemaphoreWait :=@NoSemaphoreWait;
  500. SemaphorePost :=@NoSemaphorePost;
  501. end;
  502. SetThreadManager(NoThreadManager);
  503. end;
  504. Procedure InitSystemThreads;
  505. begin
  506. { This should be changed to a real value during
  507. thread driver initialization if appropriate. }
  508. ThreadID := TThreadID(1);
  509. SetNoThreadManager;
  510. end;
  511. {$endif DISABLE_NO_THREAD_MANAGER}