thread.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  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. {$ifndef THREADVAR_RELOCATED_ALREADY_DEFINED}
  14. fpc_threadvar_relocate_proc : TRelocateThreadVarHandler; public name 'FPC_THREADVAR_RELOCATE';
  15. {$endif THREADVAR_RELOCATED_ALREADY_DEFINED}
  16. {$ifndef HAS_GETCPUCOUNT}
  17. function GetCPUCount: LongWord;
  18. begin
  19. Result := 1;
  20. end;
  21. {$endif}
  22. {*****************************************************************************
  23. Threadvar initialization
  24. *****************************************************************************}
  25. procedure InitThread(stklen:SizeUInt);
  26. begin
  27. {$ifndef FPUNONE}
  28. SysResetFPU;
  29. SysInitFPU;
  30. {$endif}
  31. {$ifndef HAS_MEMORYMANAGER}
  32. {$ifndef FPC_NO_DEFAULT_HEAP}
  33. { initialize this thread's heap }
  34. InitHeapThread;
  35. {$endif ndef FPC_NO_DEFAULT_HEAP}
  36. {$else HAS_MEMORYMANAGER}
  37. if MemoryManager.InitThread <> nil then
  38. MemoryManager.InitThread();
  39. {$endif HAS_MEMORYMANAGER}
  40. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  41. if assigned(widestringmanager.ThreadInitProc) then
  42. widestringmanager.ThreadInitProc;
  43. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  44. {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
  45. { ExceptAddrStack and ExceptObjectStack are threadvars }
  46. { so every thread has its on exception handling capabilities }
  47. SysInitExceptions;
  48. {$endif FPC_HAS_FEATURE_EXCEPTIONS}
  49. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  50. {$ifndef EMBEDDED}
  51. { Open all stdio fds again }
  52. SysInitStdio;
  53. InOutRes:=0;
  54. // ErrNo:=0;
  55. {$endif EMBEDDED}
  56. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  57. {$ifdef FPC_HAS_FEATURE_STACKCHECK}
  58. { Stack checking }
  59. StackLength:= CheckInitialStkLen(stkLen);
  60. StackBottom:=Sptr - StackLength;
  61. {$endif FPC_HAS_FEATURE_STACKCHECK}
  62. ThreadID := CurrentTM.GetCurrentThreadID();
  63. end;
  64. procedure DoneThread;
  65. begin
  66. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  67. if assigned(widestringmanager.ThreadFiniProc) then
  68. widestringmanager.ThreadFiniProc;
  69. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  70. {$ifndef HAS_MEMORYMANAGER}
  71. {$ifndef FPC_NO_DEFAULT_HEAP}
  72. FinalizeHeap;
  73. {$endif ndef FPC_NO_DEFAULT_HEAP}
  74. {$endif HAS_MEMORYMANAGER}
  75. if MemoryManager.DoneThread <> nil then
  76. MemoryManager.DoneThread();
  77. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  78. { Open all stdio fds again }
  79. SysFlushStdio;
  80. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  81. { Support platforms where threadvar memory is managed outside of the RTL:
  82. reset ThreadID and allow ReleaseThreadVars to be unassigned }
  83. ThreadID := TThreadID(0);
  84. if assigned(CurrentTM.ReleaseThreadVars) then
  85. CurrentTM.ReleaseThreadVars;
  86. end;
  87. {*****************************************************************************
  88. Overloaded functions
  89. *****************************************************************************}
  90. function BeginThread(ThreadFunction : tthreadfunc) : TThreadID;
  91. var
  92. dummy : TThreadID;
  93. begin
  94. BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,nil,0,dummy);
  95. end;
  96. function BeginThread(ThreadFunction : tthreadfunc;p : pointer) : TThreadID;
  97. var
  98. dummy : TThreadID;
  99. begin
  100. BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,dummy);
  101. end;
  102. function BeginThread(ThreadFunction : tthreadfunc;p : pointer;var ThreadId : TThreadID) : TThreadID;
  103. begin
  104. BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,ThreadId);
  105. end;
  106. function BeginThread(ThreadFunction : tthreadfunc;p : pointer;
  107. var ThreadId : TThreadID; const stacksize: SizeUInt) : TThreadID;
  108. begin
  109. BeginThread:=BeginThread(nil,stacksize,ThreadFunction,p,0,ThreadId);
  110. end;
  111. procedure EndThread;
  112. begin
  113. EndThread(0);
  114. end;
  115. function BeginThread(sa : Pointer;stacksize : SizeUInt; ThreadFunction : tthreadfunc;p : pointer;creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
  116. begin
  117. Result:=CurrentTM.BeginThread(sa,stacksize,threadfunction,P,creationflags,ThreadID);
  118. end;
  119. procedure FlushThread;
  120. begin
  121. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  122. SysFlushStdio;
  123. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  124. end;
  125. procedure EndThread(ExitCode : DWord);
  126. begin
  127. CurrentTM.EndThread(ExitCode);
  128. end;
  129. function SuspendThread (threadHandle : TThreadID) : dword;
  130. begin
  131. Result:=CurrentTM.SuspendThread(ThreadHandle);
  132. end;
  133. function ResumeThread (threadHandle : TThreadID) : dword;
  134. begin
  135. Result:=CurrentTM.ResumeThread(ThreadHandle);
  136. end;
  137. function CloseThread (threadHandle : TThreadID):dword;
  138. begin
  139. result:=CurrentTM.CloseThread(ThreadHandle);
  140. end;
  141. procedure ThreadSwitch;
  142. begin
  143. CurrentTM.ThreadSwitch;
  144. end;
  145. function KillThread (threadHandle : TThreadID) : dword;
  146. begin
  147. Result:=CurrentTM.KillThread(ThreadHandle);
  148. end;
  149. function WaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;
  150. begin
  151. Result:=CurrentTM.WaitForThreadTerminate(ThreadHandle,TimeOutMS);
  152. end;
  153. function ThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean;
  154. begin
  155. Result:=CurrentTM.ThreadSetPriority(ThreadHandle,Prio);
  156. end;
  157. function ThreadGetPriority (threadHandle : TThreadID): longint;
  158. begin
  159. Result:=CurrentTM.ThreadGetPriority(ThreadHandle);
  160. end;
  161. function GetCurrentThreadId : TThreadID;
  162. begin
  163. Result:=CurrentTM.GetCurrentThreadID();
  164. end;
  165. procedure InitCriticalSection(var cs : TRTLCriticalSection);
  166. begin
  167. CurrentTM.InitCriticalSection(cs);
  168. end;
  169. procedure DoneCriticalsection(var cs : TRTLCriticalSection);
  170. begin
  171. CurrentTM.DoneCriticalSection(cs);
  172. end;
  173. procedure EnterCriticalsection(var cs : TRTLCriticalSection);
  174. begin
  175. CurrentTM.EnterCriticalSection(cs);
  176. end;
  177. function TryEnterCriticalsection(var cs : TRTLCriticalSection):longint;
  178. begin
  179. result:=CurrentTM.TryEnterCriticalSection(cs);
  180. end;
  181. procedure LeaveCriticalsection(var cs : TRTLCriticalSection);
  182. begin
  183. CurrentTM.LeaveCriticalSection(cs);
  184. end;
  185. Function GetThreadManager(Var TM : TThreadManager) : Boolean;
  186. begin
  187. TM:=CurrentTM;
  188. Result:=True;
  189. end;
  190. Function SetThreadManager(Const NewTM : TThreadManager; Var OldTM : TThreadManager) : Boolean;
  191. begin
  192. GetThreadManager(OldTM);
  193. Result:=SetThreadManager(NewTM);
  194. end;
  195. Function SetThreadManager(Const NewTM : TThreadManager) : Boolean;
  196. begin
  197. Result:=True;
  198. If Assigned(CurrentTM.DoneManager) then
  199. Result:=CurrentTM.DoneManager();
  200. If Result then
  201. begin
  202. CurrentTM:=NewTM;
  203. If Assigned(CurrentTM.InitManager) then
  204. Result:=CurrentTM.InitManager();
  205. end;
  206. end;
  207. function BasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  208. begin
  209. result:=currenttm.BasicEventCreate(EventAttributes,AManualReset,InitialState, Name);
  210. end;
  211. procedure basiceventdestroy(state:peventstate);
  212. begin
  213. currenttm.basiceventdestroy(state);
  214. end;
  215. procedure basiceventResetEvent(state:peventstate);
  216. begin
  217. currenttm.basiceventResetEvent(state);
  218. end;
  219. procedure basiceventSetEvent(state:peventstate);
  220. begin
  221. currenttm.basiceventSetEvent(state);
  222. end;
  223. function basiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  224. begin
  225. result:=currenttm.basiceventWaitFor(Timeout,state);
  226. end;
  227. function RTLEventCreate :PRTLEvent;
  228. begin
  229. result:=currenttm.rtleventcreate();
  230. end;
  231. procedure RTLeventdestroy(state:pRTLEvent);
  232. begin
  233. currenttm.rtleventdestroy(state);
  234. end;
  235. procedure RTLeventSetEvent(state:pRTLEvent);
  236. begin
  237. currenttm.rtleventsetEvent(state);
  238. end;
  239. procedure RTLeventResetEvent(state:pRTLEvent);
  240. begin
  241. currenttm.rtleventResetEvent(state);
  242. end;
  243. procedure RTLeventWaitFor(state:pRTLEvent);
  244. begin
  245. currenttm.rtleventWaitFor(state);
  246. end;
  247. procedure RTLeventWaitFor(state:pRTLEvent;timeout : longint);
  248. begin
  249. currenttm.rtleventWaitForTimeout(state,timeout);
  250. end;
  251. function SemaphoreInit: pointer;
  252. begin
  253. result:=currenttm.SemaphoreInit();
  254. end;
  255. procedure SemaphoreDestroy(const sem: pointer);
  256. begin
  257. currenttm.SemaphoreDestroy(sem);
  258. end;
  259. procedure SemaphoreWait(const sem: pointer);
  260. begin
  261. currenttm.SemaphoreWait(sem);
  262. end;
  263. procedure SemaphorePost(const sem: pointer);
  264. begin
  265. currenttm.SemaphorePost(sem);
  266. end;
  267. { ---------------------------------------------------------------------
  268. ThreadManager which gives run-time error. Use if no thread support.
  269. ---------------------------------------------------------------------}
  270. {$ifndef DISABLE_NO_THREAD_MANAGER}
  271. { resourcestrings are not supported by the system unit,
  272. they are in the objpas unit and not available for fpc/tp modes }
  273. const
  274. SNoThreads = 'This binary has no thread support compiled in.';
  275. SRecompileWithThreads = 'Recompile the application with a thread-driver in the program uses clause before other units using thread.';
  276. Procedure NoThreadError;
  277. begin
  278. {$ifndef EMBEDDED}
  279. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  280. If IsConsole then
  281. begin
  282. Writeln(StdErr,SNoThreads);
  283. Writeln(StdErr,SRecompileWithThreads);
  284. end;
  285. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  286. {$endif EMBEDDED}
  287. RunError(232)
  288. end;
  289. function NoBeginThread(sa : Pointer;stacksize : PtrUInt;
  290. ThreadFunction : tthreadfunc;p : pointer;
  291. creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
  292. begin
  293. NoThreadError;
  294. result:=tthreadid(-1);
  295. end;
  296. procedure NoEndThread(ExitCode : DWord);
  297. begin
  298. NoThreadError;
  299. end;
  300. function NoThreadHandler (threadHandle : TThreadID) : dword;
  301. begin
  302. NoThreadError;
  303. result:=dword(-1);
  304. end;
  305. function NoWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword; {0=no timeout}
  306. begin
  307. NoThreadError;
  308. result:=dword(-1);
  309. end;
  310. function NoThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
  311. begin
  312. NoThreadError;
  313. result:=false;
  314. end;
  315. function NoThreadGetPriority (threadHandle : TThreadID): longint;
  316. begin
  317. NoThreadError;
  318. result:=-1;
  319. end;
  320. function NoGetCurrentThreadId : TThreadID;
  321. begin
  322. if IsMultiThread then
  323. NoThreadError
  324. else
  325. ThreadingAlreadyUsed:=true;
  326. result:=TThreadID(1);
  327. end;
  328. procedure NoCriticalSection(var CS);
  329. begin
  330. if IsMultiThread then
  331. NoThreadError
  332. else
  333. ThreadingAlreadyUsed:=true;
  334. end;
  335. function NoTryEnterCriticalSection(var CS):longint;
  336. begin
  337. if IsMultiThread then
  338. NoThreadError
  339. else
  340. ThreadingAlreadyUsed:=true;
  341. Result:=-1;
  342. end;
  343. procedure NoInitThreadvar(var offset : {$ifdef cpu16}word{$else}dword{$endif};size : dword);
  344. begin
  345. NoThreadError;
  346. end;
  347. function NoRelocateThreadvar(offset : {$ifdef cpu16}word{$else}dword{$endif}) : pointer;
  348. begin
  349. NoThreadError;
  350. result:=nil;
  351. end;
  352. function NoBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  353. begin
  354. if IsMultiThread then
  355. NoThreadError
  356. else
  357. ThreadingAlreadyUsed:=true;
  358. result:=nil;
  359. end;
  360. procedure NoBasicEvent(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 NoRTLEvent(state:pRTLEvent);
  384. begin
  385. if IsMultiThread then
  386. NoThreadError
  387. else
  388. ThreadingAlreadyUsed:=true
  389. end;
  390. procedure NoRTLEventWaitForTimeout(state:pRTLEvent;timeout : longint);
  391. begin
  392. if IsMultiThread then
  393. NoThreadError
  394. else
  395. ThreadingAlreadyUsed:=true;
  396. end;
  397. function NoSemaphoreInit: Pointer;
  398. begin
  399. if IsMultiThread then
  400. NoThreadError
  401. else
  402. ThreadingAlreadyUsed:=true;
  403. result:=nil;
  404. end;
  405. procedure NoSemaphoreWait(const FSem: Pointer);
  406. begin
  407. NoThreadError;
  408. end;
  409. procedure NoSemaphore(const FSem: Pointer);
  410. begin
  411. if IsMultiThread then
  412. NoThreadError
  413. else
  414. ThreadingAlreadyUsed:=true;
  415. end;
  416. const
  417. NoThreadManager : TThreadManager = (
  418. InitManager : Nil;
  419. DoneManager : Nil;
  420. {$ifdef EMBEDDED}
  421. { while this is pretty hacky, it reduces the size of typical embedded programs
  422. and works fine on arm and avr }
  423. BeginThread : @NoBeginThread;
  424. EndThread : TEndThreadHandler(@NoThreadError);
  425. SuspendThread : TThreadHandler(@NoThreadError);
  426. ResumeThread : TThreadHandler(@NoThreadError);
  427. KillThread : TThreadHandler(@NoThreadError);
  428. CloseThread : TThreadHandler(@NoThreadError);
  429. ThreadSwitch : TThreadSwitchHandler(@NoThreadError);
  430. WaitForThreadTerminate : TWaitForThreadTerminateHandler(@NoThreadError);
  431. ThreadSetPriority : TThreadSetPriorityHandler(@NoThreadError);
  432. ThreadGetPriority : TThreadGetPriorityHandler(@NoThreadError);
  433. GetCurrentThreadId : @NoGetCurrentThreadId;
  434. InitCriticalSection : TCriticalSectionHandler(@NoThreadError);
  435. DoneCriticalSection : TCriticalSectionHandler(@NoThreadError);
  436. EnterCriticalSection : TCriticalSectionHandler(@NoThreadError);
  437. TryEnterCriticalSection: TCriticalSectionHandlerTryEnter(@NoThreadError);
  438. LeaveCriticalSection : TCriticalSectionHandler(@NoThreadError);
  439. InitThreadVar : TInitThreadVarHandler(@NoThreadError);
  440. RelocateThreadVar : TRelocateThreadVarHandler(@NoThreadError);
  441. AllocateThreadVars : @NoThreadError;
  442. ReleaseThreadVars : @NoThreadError;
  443. BasicEventCreate : TBasicEventCreateHandler(@NoThreadError);
  444. basiceventdestroy : TBasicEventHandler(@NoThreadError);
  445. basiceventResetEvent : TBasicEventHandler(@NoThreadError);
  446. basiceventSetEvent : TBasicEventHandler(@NoThreadError);
  447. basiceventWaitFor : TBasicEventWaitForHandler(@NoThreadError);
  448. rtlEventCreate : TRTLCreateEventHandler(@NoThreadError);
  449. rtleventdestroy : TRTLEventHandler(@NoThreadError);
  450. rtleventSetEvent : TRTLEventHandler(@NoThreadError);
  451. rtleventResetEvent : TRTLEventHandler(@NoThreadError);
  452. rtleventWaitFor : TRTLEventHandler(@NoThreadError);
  453. rtleventwaitfortimeout : TRTLEventHandlerTimeout(@NoThreadError);
  454. SemaphoreInit : TSempahoreInitHandler(@NoThreadError);
  455. SemaphoreDestroy : TSemaphoreDestroyHandler(@NoThreadError);
  456. SemaphorePost : TSemaphorePostHandler(@NoThreadError);
  457. SemaphoreWait : TSemaphoreWaitHandler(@NoThreadError)
  458. {$else EMBEDDED}
  459. BeginThread : @NoBeginThread;
  460. EndThread : @NoEndThread;
  461. SuspendThread : @NoThreadHandler;
  462. ResumeThread : @NoThreadHandler;
  463. KillThread : @NoThreadHandler;
  464. CloseThread : @NoThreadHandler;
  465. ThreadSwitch : @NoThreadError;
  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 : @NoThreadError;
  478. ReleaseThreadVars : @NoThreadError;
  479. BasicEventCreate : @NoBasicEventCreate;
  480. basiceventdestroy : @NoBasicEvent;
  481. basiceventResetEvent : @NoBasicEvent;
  482. basiceventSetEvent : @NoBasicEvent;
  483. basiceventWaitFor : @NoBasiceventWaitFor;
  484. rtlEventCreate : @NoRTLEventCreate;
  485. rtleventdestroy : @NoRTLevent;
  486. rtleventSetEvent : @NoRTLevent;
  487. rtleventResetEvent : @NoRTLEvent;
  488. rtleventWaitFor : @NoRTLEvent;
  489. rtleventwaitfortimeout : @NoRTLEventWaitForTimeout;
  490. SemaphoreInit : @NoSemaphoreInit;
  491. SemaphoreDestroy : @NoSemaphore;
  492. SemaphorePost : @NoSemaphore;
  493. SemaphoreWait : @NoSemaphoreWait
  494. {$endif EMBEDDED}
  495. );
  496. Procedure SetNoThreadManager;
  497. begin
  498. SetThreadManager(NoThreadManager);
  499. end;
  500. Procedure InitSystemThreads; public name '_FPC_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}