thread.inc 17 KB

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