thread.inc 14 KB

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