systhrd.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2002-2010 by Tomas Hajny,
  4. member of the Free Pascal development team.
  5. OS/2 threading support implementation
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {*****************************************************************************
  13. Local Api imports
  14. *****************************************************************************}
  15. const
  16. pag_Read = 1;
  17. pag_Write = 2;
  18. pag_Execute = 4;
  19. pag_Guard = 8;
  20. pag_Commit = $10;
  21. obj_Tile = $40;
  22. sem_Indefinite_Wait = cardinal (-1);
  23. dtSuspended = 1;
  24. dtStack_Commited = 2;
  25. deThread = 0; {DosExit - exit thread only}
  26. dcWW_Wait = 0;
  27. dcWW_NoWait = 1;
  28. dpThread = 2;
  29. dpSameClass = 0;
  30. { import the necessary stuff from the OS }
  31. function DosAllocThreadLocalMemory (Count: cardinal; var P: pointer): cardinal;
  32. cdecl; external 'DOSCALLS' index 454;
  33. function DosFreeThreadLocalMemory (P: pointer): cardinal; cdecl;
  34. external 'DOSCALLS' index 455;
  35. function DosCreateThread (var TID: cardinal; Address: pointer;
  36. (* TThreadFunc *)
  37. aParam: pointer; Flags: cardinal; StackSize: cardinal): cardinal; cdecl;
  38. external 'DOSCALLS' index 311;
  39. function DosCreateMutExSem (Name: PChar; var Handle: longint; Attr: cardinal;
  40. State: boolean): cardinal; cdecl; external 'DOSCALLS' index 331;
  41. function DosCloseMutExSem (Handle: longint): cardinal; cdecl;
  42. external 'DOSCALLS' index 333;
  43. function DosQueryMutExSem (Handle: longint; var PID, TID, Count: cardinal):
  44. cardinal; cdecl; external 'DOSCALLS' index 336;
  45. function DosRequestMutExSem (Handle:longint; Timeout: cardinal): cardinal; cdecl;
  46. external 'DOSCALLS' index 334;
  47. function DosReleaseMutExSem (Handle: longint): cardinal; cdecl;
  48. external 'DOSCALLS' index 335;
  49. function DosSuspendThread (TID:cardinal): cardinal; cdecl;
  50. external 'DOSCALLS' index 238;
  51. function DosResumeThread (TID: cardinal): cardinal; cdecl;
  52. external 'DOSCALLS' index 237;
  53. function DosKillThread (TID: cardinal): cardinal; cdecl;
  54. external 'DOSCALLS' index 111;
  55. function DosWaitThread (var TID: cardinal; Option: cardinal): cardinal; cdecl;
  56. external 'DOSCALLS' index 349;
  57. function DosEnterCritSec:cardinal; cdecl; external 'DOSCALLS' index 232;
  58. function DosExitCritSec:cardinal; cdecl; external 'DOSCALLS' index 233;
  59. procedure DosSleep (MSec: cardinal); cdecl; external 'DOSCALLS' index 229;
  60. {
  61. procedure DosExit (Action, Result: cardinal); cdecl;
  62. external 'DOSCALLS' index 234;
  63. Already declared in the main part of system.pas...
  64. }
  65. function DosSetPriority (Scope, TrClass: cardinal; Delta: longint;
  66. PortID: cardinal): cardinal; cdecl;
  67. external 'DOSCALLS' index 236;
  68. {*****************************************************************************
  69. Threadvar support
  70. *****************************************************************************}
  71. const
  72. ThreadVarBlockSize: dword = 0;
  73. const
  74. (* Pointer to an allocated dword space within the local thread *)
  75. (* memory area. Pointer to the real memory block allocated for *)
  76. (* thread vars in this block is then stored in this dword. *)
  77. DataIndex: PPointer = nil;
  78. procedure SysInitThreadvar (var Offset: dword; Size: dword);
  79. begin
  80. Offset := ThreadVarBlockSize;
  81. Inc (ThreadVarBlockSize, Size);
  82. end;
  83. procedure SysAllocateThreadVars;
  84. begin
  85. { we've to allocate the memory from the OS }
  86. { because the FPC heap management uses }
  87. { exceptions which use threadvars but }
  88. { these aren't allocated yet ... }
  89. { allocate room on the heap for the thread vars }
  90. if DosAllocMem (DataIndex^, ThreadVarBlockSize, pag_Read or pag_Write
  91. or pag_Commit) <> 0 then
  92. HandleError (8);
  93. { The Windows API apparently provides a way to fill the allocated memory with }
  94. { zeros; we probably need to do it ourselves for compatibility. }
  95. FillChar (DataIndex^^, 0, ThreadVarBlockSize);
  96. end;
  97. function SysRelocateThreadVar (Offset: dword): pointer;
  98. begin
  99. { DataIndex itself not checked for not being nil - expected that this should }
  100. { not be necessary because the equivalent check (i.e. TlsKey not being set) }
  101. { is note performed by the Windows implementation. }
  102. if DataIndex^ = nil then
  103. begin
  104. SysAllocateThreadVars;
  105. InitThread ($1000000);
  106. end;
  107. SysRelocateThreadVar := DataIndex^ + Offset;
  108. end;
  109. procedure SysInitMultithreading;
  110. begin
  111. { do not check IsMultiThread, as program could have altered it, out of Delphi habit }
  112. { the thread attach/detach code uses locks to avoid multiple calls of this }
  113. if DataIndex = nil then
  114. begin
  115. { We're still running in single thread mode, setup the TLS }
  116. if DosAllocThreadLocalMemory (1, DataIndex) <> 0 then RunError (8);
  117. InitThreadVars (@SysRelocateThreadvar);
  118. IsMultiThread := true;
  119. end;
  120. end;
  121. procedure SysFiniMultithreading;
  122. begin
  123. if IsMultiThread then
  124. begin
  125. if DosFreeThreadLocalMemory (DataIndex) <> 0 then
  126. begin
  127. {??? What to do if releasing fails?}
  128. end;
  129. DataIndex := nil;
  130. end;
  131. end;
  132. procedure SysReleaseThreadVars;
  133. begin
  134. DosFreeMem (DataIndex^);
  135. DataIndex^ := nil;
  136. end;
  137. (* procedure InitThreadVars;
  138. begin
  139. { allocate one ThreadVar entry from the OS, we use this entry }
  140. { for a pointer to our threadvars }
  141. if DosAllocThreadLocalMemory (1, DataIndex) <> 0 then HandleError (8);
  142. { initialize threadvars }
  143. init_all_unit_threadvars;
  144. { allocate mem for main thread threadvars }
  145. SysAllocateThreadVars;
  146. { copy main thread threadvars }
  147. copy_all_unit_threadvars;
  148. { install threadvar handler }
  149. fpc_threadvar_relocate_proc := @SysRelocateThreadvar;
  150. end;
  151. *)
  152. {*****************************************************************************
  153. Thread starting
  154. *****************************************************************************}
  155. type
  156. pthreadinfo = ^tthreadinfo;
  157. tthreadinfo = record
  158. f : tthreadfunc;
  159. p : pointer;
  160. stklen : cardinal;
  161. end;
  162. (* procedure InitThread(stklen:cardinal);
  163. begin
  164. SysResetFPU;
  165. SysInitFPU;
  166. { ExceptAddrStack and ExceptObjectStack are threadvars }
  167. { so every thread has its on exception handling capabilities }
  168. SysInitExceptions;
  169. { Open all stdio fds again }
  170. SysInitStdio;
  171. InOutRes:=0;
  172. // ErrNo:=0;
  173. { Stack checking }
  174. StackLength:=stklen;
  175. StackBottom:=Sptr - StackLength;
  176. end;
  177. *)
  178. function ThreadMain(param : pointer) : pointer;cdecl;
  179. var
  180. ti : tthreadinfo;
  181. begin
  182. { Allocate local thread vars, this must be the first thing,
  183. because the exception management and io depends on threadvars }
  184. SysAllocateThreadVars;
  185. { Copy parameter to local data }
  186. {$ifdef DEBUG_MT}
  187. writeln('New thread started, initialising ...');
  188. {$endif DEBUG_MT}
  189. ti:=pthreadinfo(param)^;
  190. dispose(pthreadinfo(param));
  191. { Initialize thread }
  192. InitThread(ti.stklen);
  193. { Start thread function }
  194. {$ifdef DEBUG_MT}
  195. writeln('Jumping to thread function');
  196. {$endif DEBUG_MT}
  197. ThreadMain:=pointer(ti.f(ti.p));
  198. end;
  199. function SysBeginThread (SA: pointer; StackSize : PtrUInt;
  200. ThreadFunction: TThreadFunc; P: pointer;
  201. CreationFlags: cardinal; var ThreadId: TThreadID): DWord;
  202. var
  203. TI: PThreadInfo;
  204. begin
  205. { WriteLn is not a good idea before thread initialization...
  206. $ifdef DEBUG_MT
  207. WriteLn ('Creating new thread');
  208. $endif DEBUG_MT}
  209. { Initialize multithreading if not done }
  210. SysInitMultithreading;
  211. { the only way to pass data to the newly created thread
  212. in a MT safe way, is to use the heap }
  213. New (TI);
  214. TI^.F := ThreadFunction;
  215. TI^.P := P;
  216. TI^.StkLen := StackSize;
  217. ThreadID := 0;
  218. {$ifdef DEBUG_MT}
  219. WriteLn ('Starting new thread');
  220. {$endif DEBUG_MT}
  221. if DosCreateThread (cardinal (ThreadID), @ThreadMain, TI,
  222. CreationFlags, StackSize) = 0 then
  223. SysBeginThread := ThreadID
  224. else
  225. begin
  226. SysBeginThread := 0;
  227. {$IFDEF DEBUG_MT}
  228. WriteLn ('Thread creation failed');
  229. {$ENDIF DEBUG_MT}
  230. Dispose (TI);
  231. end;
  232. end;
  233. procedure SysEndThread (ExitCode: cardinal);
  234. begin
  235. DoneThread;
  236. DosExit (0, ExitCode);
  237. end;
  238. procedure SysThreadSwitch;
  239. begin
  240. DosSleep (0);
  241. end;
  242. function SysSuspendThread (ThreadHandle: dword): dword;
  243. begin
  244. {$WARNING Check expected return value}
  245. SysSuspendThread := DosSuspendThread (ThreadHandle);
  246. end;
  247. function SysResumeThread (ThreadHandle: dword): dword;
  248. begin
  249. {$WARNING Check expected return value}
  250. SysResumeThread := DosResumeThread (ThreadHandle);
  251. end;
  252. function SysKillThread (ThreadHandle: dword): dword;
  253. begin
  254. SysKillThread := DosKillThread (ThreadHandle);
  255. end;
  256. function SysCloseThread (ThreadHandle: TThreadID): dword;
  257. begin
  258. { Probably not relevant under OS/2? }
  259. // SysCloseThread:=CloseHandle(threadHandle);
  260. end;
  261. function SysWaitForThreadTerminate (ThreadHandle: dword;
  262. TimeoutMs: longint): dword;
  263. var
  264. RC: cardinal;
  265. const
  266. { Wait at most 100 ms before next check for thread termination }
  267. WaitTime = 100;
  268. begin
  269. if TimeoutMs = 0 then
  270. RC := DosWaitThread (ThreadHandle, dcWW_Wait)
  271. else
  272. repeat
  273. RC := DosWaitThread (ThreadHandle, dcWW_NoWait);
  274. if RC = 294 then
  275. begin
  276. if TimeoutMs > WaitTime then
  277. DosSleep (WaitTime)
  278. else
  279. begin
  280. DosSleep (TimeoutMs);
  281. DosWaitThread (ThreadHandle, dcWW_NoWait);
  282. end;
  283. Dec (TimeoutMs, WaitTime);
  284. end;
  285. until (RC <> 294) or (TimeoutMs <= 0);
  286. SysWaitForThreadTerminate := RC;
  287. end;
  288. function SysThreadSetPriority (ThreadHandle: dword; Prio: longint): boolean;
  289. {-15..+15, 0=normal}
  290. var
  291. Delta: longint;
  292. begin
  293. {$WARNING TODO!}
  294. {
  295. SysThreadSetPriority:=WinThreadSetPriority(threadHandle,Prio);
  296. Find out current priority first using DosGetInfoBlocks, then calculate delta
  297. (recalculate the scale from -15..+15 on input to -31..+31 used by OS/2).
  298. SysThreadSetPriority := DosSetPriority (dpThread, dpSameClass, Delta,
  299. ThreadHandle);
  300. }
  301. end;
  302. function SysThreadGetPriority (ThreadHandle: dword): longint;
  303. begin
  304. {$WARNING TODO!}
  305. {
  306. SysThreadGetPriority:=WinThreadGetPriority(threadHandle);
  307. DosGetInfoBlocks - recalculate the scale afterwards to -15..+15
  308. }
  309. end;
  310. function SysGetCurrentThreadID: dword;
  311. var
  312. TIB: PThreadInfoBlock;
  313. begin
  314. DosGetInfoBlocks (@TIB, nil);
  315. SysGetCurrentThreadID := TIB^.TIB2^.TID;
  316. end;
  317. {*****************************************************************************
  318. Delphi/Win32 compatibility
  319. *****************************************************************************}
  320. { DosEnter/ExitCritSec have quite a few limitations, so let's try to avoid
  321. them. I'm not sure whether mutex semaphores are SMP-safe, though... :-( }
  322. procedure SysInitCriticalSection(var CS);
  323. begin
  324. {$WARNING TODO!}
  325. end;
  326. procedure SysDoneCriticalSection (var CS);
  327. begin
  328. {$WARNING TODO!}
  329. end;
  330. procedure SysEnterCriticalSection (var CS);
  331. begin
  332. {$WARNING TODO!}
  333. end;
  334. procedure SysLeaveCriticalSection (var CS);
  335. begin
  336. {$WARNING TODO!}
  337. end;
  338. type
  339. TBasicEventState = record
  340. FHandle: THandle;
  341. FLastError: longint;
  342. end;
  343. PLocalEventRec = ^TBasicEventState;
  344. function IntBasicEventCreate (EventAttributes: Pointer;
  345. AManualReset, InitialState: Boolean; const Name: ansistring): PEventState;
  346. begin
  347. New (PLocalEventRec (Result));
  348. {$WARNING TODO!}
  349. {
  350. PLocalEventrec (Result)^.FHandle :=
  351. CreateEvent (EventAttributes, AManualReset, InitialState,PChar(Name));
  352. }
  353. end;
  354. procedure IntBasicEventDestroy (State: PEventState);
  355. begin
  356. {$WARNING TODO!}
  357. {
  358. closehandle(plocaleventrec(state)^.fhandle);
  359. }
  360. Dispose (PLocalEventRec (State));
  361. end;
  362. procedure IntBasicEventResetEvent (State: PEventState);
  363. begin
  364. {$WARNING TODO!}
  365. {
  366. ResetEvent(plocaleventrec(state)^.FHandle)
  367. }
  368. end;
  369. procedure IntBasicEventSetEvent (State: PEventState);
  370. begin
  371. {$WARNING TODO!}
  372. {
  373. SetEvent(plocaleventrec(state)^.FHandle);
  374. }
  375. end;
  376. function IntBasicEventWaitFor (Timeout: Cardinal; State: PEventState): longint;
  377. begin
  378. {$WARNING TODO!}
  379. {
  380. case WaitForSingleObject(plocaleventrec(state)^.fHandle, Timeout) of
  381. WAIT_ABANDONED: Result := wrAbandoned;
  382. WAIT_OBJECT_0: Result := wrSignaled;
  383. WAIT_TIMEOUT: Result := wrTimeout;
  384. WAIT_FAILED:
  385. begin
  386. Result := wrError;
  387. plocaleventrec(state)^.FLastError := GetLastError;
  388. end;
  389. else
  390. Result := wrError;
  391. end;
  392. }
  393. end;
  394. function IntRTLEventCreate: PRTLEvent;
  395. begin
  396. {$WARNING TODO!}
  397. {
  398. Result := PRTLEVENT(CreateEvent(nil, false, false, nil));
  399. }
  400. end;
  401. procedure IntRTLEventDestroy (AEvent: PRTLEvent);
  402. begin
  403. {$WARNING TODO!}
  404. {
  405. CloseHandle(THANDLE(AEvent));
  406. }
  407. end;
  408. procedure IntRTLEventSetEvent (AEvent: PRTLEvent);
  409. begin
  410. {$WARNING TODO!}
  411. {
  412. SetEvent(THANDLE(AEvent));
  413. }
  414. end;
  415. procedure IntRTLEventWaitFor (AEvent: PRTLEvent);
  416. CONST INFINITE=-1;
  417. begin
  418. {$WARNING TODO!}
  419. {
  420. WaitForSingleObject(THANDLE(AEvent), INFINITE);
  421. }
  422. end;
  423. function SysTryEnterCriticalSection (var CS): longint;
  424. begin
  425. {$WARNING TODO!}
  426. end;
  427. procedure IntRTLEventWaitForTimeout (AEvent: PRTLEvent; Timeout: longint);
  428. begin
  429. {$WARNING TODO!}
  430. {
  431. WaitForSingleObject(THANDLE(AEvent), Timeout);
  432. }
  433. end;
  434. procedure intRTLEventResetEvent (AEvent: PRTLEvent);
  435. begin
  436. {$WARNING TODO!}
  437. {
  438. ResetEvent(THANDLE(AEvent));
  439. }
  440. end;
  441. var
  442. OS2ThreadManager: TThreadManager;
  443. procedure InitSystemThreads;
  444. begin
  445. with OS2ThreadManager do
  446. begin
  447. InitManager :=Nil;
  448. DoneManager :=Nil;
  449. BeginThread :=@SysBeginThread;
  450. EndThread :=@SysEndThread;
  451. SuspendThread :=@SysSuspendThread;
  452. ResumeThread :=@SysResumeThread;
  453. KillThread :=@SysKillThread;
  454. ThreadSwitch :=@SysThreadSwitch;
  455. CloseThread :=@SysCloseThread;
  456. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  457. ThreadSetPriority :=@SysThreadSetPriority;
  458. ThreadGetPriority :=@SysThreadGetPriority;
  459. GetCurrentThreadId :=@SysGetCurrentThreadId;
  460. InitCriticalSection :=@SysInitCriticalSection;
  461. DoneCriticalSection :=@SysDoneCriticalSection;
  462. EnterCriticalSection :=@SysEnterCriticalSection;
  463. TryEnterCriticalSection:=@SysTryEnterCriticalSection;
  464. LeaveCriticalSection :=@SysLeaveCriticalSection;
  465. InitThreadVar :=@SysInitThreadVar;
  466. RelocateThreadVar :=@SysRelocateThreadVar;
  467. AllocateThreadVars :=@SysAllocateThreadVars;
  468. ReleaseThreadVars :=@SysReleaseThreadVars;
  469. BasicEventCreate :=@IntBasicEventCreate;
  470. BasicEventDestroy :=@IntBasicEventDestroy;
  471. BasicEventResetEvent :=@IntBasicEventResetEvent;
  472. BasicEventSetEvent :=@IntBasicEventSetEvent;
  473. BasiceventWaitFor :=@IntBasiceventWaitFor;
  474. RTLEventCreate :=@IntRTLEventCreate;
  475. RTLEventDestroy :=@IntRTLEventDestroy;
  476. RTLEventSetEvent :=@IntRTLEventSetEvent;
  477. RTLEventResetEvent :=@intRTLEventResetEvent;
  478. RTLEventWaitFor :=@IntRTLEventWaitFor;
  479. RTLEventWaitForTimeout :=@intRTLEventWaitForTimeout;
  480. end;
  481. SetThreadManager (OS2ThreadManager);
  482. end;