thread.inc 15 KB

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