thread.inc 15 KB

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