thread.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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. { ---------------------------------------------------------------------
  247. ThreadManager which gives run-time error. Use if no thread support.
  248. ---------------------------------------------------------------------}
  249. {$ifndef DISABLE_NO_THREAD_MANAGER}
  250. { resourcestrings are not supported by the system unit,
  251. they are in the objpas unit and not available for fpc/tp modes }
  252. const
  253. SNoThreads = 'This binary has no thread support compiled in.';
  254. SRecompileWithThreads = 'Recompile the application with a thread-driver in the program uses clause before other units using thread.';
  255. Procedure NoThreadError;
  256. begin
  257. {$ifndef EMBEDDED}
  258. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  259. If IsConsole then
  260. begin
  261. Writeln(StdErr,SNoThreads);
  262. Writeln(StdErr,SRecompileWithThreads);
  263. end;
  264. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  265. {$endif EMBEDDED}
  266. RunError(232)
  267. end;
  268. function NoBeginThread(sa : Pointer;stacksize : PtrUInt;
  269. ThreadFunction : tthreadfunc;p : pointer;
  270. creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
  271. begin
  272. NoThreadError;
  273. result:=tthreadid(-1);
  274. end;
  275. procedure NoEndThread(ExitCode : DWord);
  276. begin
  277. NoThreadError;
  278. end;
  279. function NoThreadHandler (threadHandle : TThreadID) : dword;
  280. begin
  281. NoThreadError;
  282. result:=dword(-1);
  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:=TThreadID(1);
  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. Result:=-1;
  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. function NoBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  332. begin
  333. if IsMultiThread then
  334. NoThreadError
  335. else
  336. ThreadingAlreadyUsed:=true;
  337. result:=nil;
  338. end;
  339. procedure NoBasicEvent(state:peventstate);
  340. begin
  341. if IsMultiThread then
  342. NoThreadError
  343. else
  344. ThreadingAlreadyUsed:=true;
  345. end;
  346. function NoBasicEventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  347. begin
  348. if IsMultiThread then
  349. NoThreadError
  350. else
  351. ThreadingAlreadyUsed:=true;
  352. result:=-1;
  353. end;
  354. function NoRTLEventCreate :PRTLEvent;
  355. begin
  356. if IsMultiThread then
  357. NoThreadError
  358. else
  359. ThreadingAlreadyUsed:=true;
  360. result:=nil;
  361. end;
  362. procedure NoRTLEvent(state:pRTLEvent);
  363. begin
  364. if IsMultiThread then
  365. NoThreadError
  366. else
  367. ThreadingAlreadyUsed:=true
  368. end;
  369. procedure NoRTLEventWaitForTimeout(state:pRTLEvent;timeout : longint);
  370. begin
  371. if IsMultiThread then
  372. NoThreadError
  373. else
  374. ThreadingAlreadyUsed:=true;
  375. end;
  376. function NoSemaphoreInit: Pointer;
  377. begin
  378. if IsMultiThread then
  379. NoThreadError
  380. else
  381. ThreadingAlreadyUsed:=true;
  382. result:=nil;
  383. end;
  384. procedure NoSemaphoreWait(const FSem: Pointer);
  385. begin
  386. NoThreadError;
  387. end;
  388. procedure NoSemaphore(const FSem: Pointer);
  389. begin
  390. if IsMultiThread then
  391. NoThreadError
  392. else
  393. ThreadingAlreadyUsed:=true;
  394. end;
  395. const
  396. NoThreadManager : TThreadManager = (
  397. InitManager : Nil;
  398. DoneManager : Nil;
  399. {$ifdef EMBEDDED}
  400. { while this is pretty hacky, it reduces the size of typical embedded programs
  401. and works fine on arm and avr }
  402. BeginThread : @NoBeginThread;
  403. EndThread : TEndThreadHandler(@NoThreadError);
  404. SuspendThread : TThreadHandler(@NoThreadError);
  405. ResumeThread : TThreadHandler(@NoThreadError);
  406. KillThread : TThreadHandler(@NoThreadError);
  407. CloseThread : TThreadHandler(@NoThreadError);
  408. ThreadSwitch : TThreadSwitchHandler(@NoThreadError);
  409. WaitForThreadTerminate : TWaitForThreadTerminateHandler(@NoThreadError);
  410. ThreadSetPriority : TThreadSetPriorityHandler(@NoThreadError);
  411. ThreadGetPriority : TThreadGetPriorityHandler(@NoThreadError);
  412. GetCurrentThreadId : @NoGetCurrentThreadId;
  413. InitCriticalSection : TCriticalSectionHandler(@NoThreadError);
  414. DoneCriticalSection : TCriticalSectionHandler(@NoThreadError);
  415. EnterCriticalSection : TCriticalSectionHandler(@NoThreadError);
  416. TryEnterCriticalSection: TCriticalSectionHandlerTryEnter(@NoThreadError);
  417. LeaveCriticalSection : TCriticalSectionHandler(@NoThreadError);
  418. InitThreadVar : TInitThreadVarHandler(@NoThreadError);
  419. RelocateThreadVar : TRelocateThreadVarHandler(@NoThreadError);
  420. AllocateThreadVars : @NoThreadError;
  421. ReleaseThreadVars : @NoThreadError;
  422. BasicEventCreate : TBasicEventCreateHandler(@NoThreadError);
  423. basiceventdestroy : TBasicEventHandler(@NoThreadError);
  424. basiceventResetEvent : TBasicEventHandler(@NoThreadError);
  425. basiceventSetEvent : TBasicEventHandler(@NoThreadError);
  426. basiceventWaitFor : TBasicEventWaitForHandler(@NoThreadError);
  427. rtlEventCreate : TRTLCreateEventHandler(@NoThreadError);
  428. rtleventdestroy : TRTLEventHandler(@NoThreadError);
  429. rtleventSetEvent : TRTLEventHandler(@NoThreadError);
  430. rtleventResetEvent : TRTLEventHandler(@NoThreadError);
  431. rtleventWaitFor : TRTLEventHandler(@NoThreadError);
  432. rtleventwaitfortimeout : TRTLEventHandlerTimeout(@NoThreadError);
  433. SemaphoreInit : TSempahoreInitHandler(@NoThreadError);
  434. SemaphoreDestroy : TSemaphoreDestroyHandler(@NoThreadError);
  435. SemaphorePost : TSemaphorePostHandler(@NoThreadError);
  436. SemaphoreWait : TSemaphoreWaitHandler(@NoThreadError)
  437. {$else EMBEDDED}
  438. BeginThread : @NoBeginThread;
  439. EndThread : @NoEndThread;
  440. SuspendThread : @NoThreadHandler;
  441. ResumeThread : @NoThreadHandler;
  442. KillThread : @NoThreadHandler;
  443. CloseThread : @NoThreadHandler;
  444. ThreadSwitch : @NoThreadError;
  445. WaitForThreadTerminate : @NoWaitForThreadTerminate;
  446. ThreadSetPriority : @NoThreadSetPriority;
  447. ThreadGetPriority : @NoThreadGetPriority;
  448. GetCurrentThreadId : @NoGetCurrentThreadId;
  449. InitCriticalSection : @NoCriticalSection;
  450. DoneCriticalSection : @NoCriticalSection;
  451. EnterCriticalSection : @NoCriticalSection;
  452. TryEnterCriticalSection: @NoTryEnterCriticalSection;
  453. LeaveCriticalSection : @NoCriticalSection;
  454. InitThreadVar : @NoInitThreadVar;
  455. RelocateThreadVar : @NoRelocateThreadVar;
  456. AllocateThreadVars : @NoThreadError;
  457. ReleaseThreadVars : @NoThreadError;
  458. BasicEventCreate : @NoBasicEventCreate;
  459. basiceventdestroy : @NoBasicEvent;
  460. basiceventResetEvent : @NoBasicEvent;
  461. basiceventSetEvent : @NoBasicEvent;
  462. basiceventWaitFor : @NoBasiceventWaitFor;
  463. rtlEventCreate : @NoRTLEventCreate;
  464. rtleventdestroy : @NoRTLevent;
  465. rtleventSetEvent : @NoRTLevent;
  466. rtleventResetEvent : @NoRTLEvent;
  467. rtleventWaitFor : @NoRTLEvent;
  468. rtleventwaitfortimeout : @NoRTLEventWaitForTimeout;
  469. SemaphoreInit : @NoSemaphoreInit;
  470. SemaphoreDestroy : @NoSemaphore;
  471. SemaphorePost : @NoSemaphore;
  472. SemaphoreWait : @NoSemaphoreWait
  473. {$endif EMBEDDED}
  474. );
  475. Procedure SetNoThreadManager;
  476. begin
  477. SetThreadManager(NoThreadManager);
  478. end;
  479. Procedure InitSystemThreads; public name '_FPC_InitSystemThreads';
  480. begin
  481. { This should be changed to a real value during
  482. thread driver initialization if appropriate. }
  483. ThreadID := TThreadID(1);
  484. SetNoThreadManager;
  485. end;
  486. {$endif DISABLE_NO_THREAD_MANAGER}