thread.inc 17 KB

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