thread.inc 15 KB

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