systhrd.inc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2002-2014 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. var
  16. OS2ThreadManager: TThreadManager;
  17. const
  18. pag_Read = 1;
  19. pag_Write = 2;
  20. pag_Execute = 4;
  21. pag_Guard = 8;
  22. pag_Commit = $10;
  23. obj_Tile = $40;
  24. sem_Indefinite_Wait = cardinal (-1);
  25. dtSuspended = 1;
  26. dtStack_Commited = 2;
  27. deThread = 0; {DosExit - exit thread only}
  28. dcWW_Wait = 0;
  29. dcWW_NoWait = 1;
  30. dpThread = 2;
  31. dpSameClass = 0;
  32. dce_AutoReset = $1000;
  33. qs_End = 0;
  34. qs_Process = 1;
  35. qs_Thread = 256;
  36. type
  37. PQSTRec = ^TQSTRec;
  38. TQSTRec = record
  39. RecType: cardinal; { Record type }
  40. TID: word; { Thread ID }
  41. Slot: word; { "Unique" thread slot number }
  42. SleepID: cardinal; { Sleep ID thread is sleeping on }
  43. case boolean of
  44. false: (
  45. Priority: cardinal; { Thread priority (class + level) }
  46. SysTime: cardinal; { Thread system time }
  47. UserTime: cardinal; { Thread user time }
  48. State: byte; { Thread state }
  49. Pad: array [1..3] of byte); { Padding for 32-bit alignment }
  50. true: (
  51. PrioLevel: byte; { Thread priority level only }
  52. PrioClass: byte; { Thread priority class only }
  53. Pad2: array [1..14] of byte);
  54. end;
  55. PQSPRec = ^TQSPRec;
  56. TQSPrec = record
  57. RecType: cardinal; { Type of record being processed }
  58. PThrdRec: PQSTRec; { (Far?) pointer to thread records for this process }
  59. PID: word; { Process ID }
  60. PPID: word; { Parent process ID }
  61. ProcType: cardinal; { Process type }
  62. Stat: cardinal; { Process status }
  63. SGID: cardinal; { Process screen group }
  64. hMte: word; { Program module handle for process }
  65. cTCB: word; { Number of TCBs (Thread Control Blocks) in use }
  66. c32PSem: cardinal; { Number of private 32-bit semaphores in use }
  67. p32SemRec: pointer; { (Far?) pointer to head of 32-bit semaphores info }
  68. c16Sem: word; { Number of 16 bit system semaphores in use }
  69. cLib: word; { Number of runtime linked libraries }
  70. cShrMem: word; { Number of shared memory handles }
  71. cFH: word; { Number of open files }
  72. { NOTE: cFH is size of active part of }
  73. { the handle table if QS_FILE specified }
  74. p16SemRec: word; { Far pointer? to head of 16-bit semaphores info }
  75. pLibRec: word; { Far pointer? to list of runtime libraries }
  76. pShrMemRec: word; { Far pointer? to list of shared memory handles }
  77. pFSRec: word; { Far pointer to list of file handles; }
  78. { 0xFFFF means it's closed, otherwise }
  79. { it's an SFN if non-zero }
  80. end;
  81. (* Simplified version here to avoid need for all record types copied here. *)
  82. PQSPtrRec = ^TQSPtrRec;
  83. TQSPtrRec = record
  84. PGlobalRec: pointer;
  85. PProcRec: PQSPRec; { Pointer to head of process records }
  86. P16SemRec: pointer;
  87. P32SemRec: pointer;
  88. PMemRec: pointer;
  89. PLibRec: pointer;
  90. PShrMemRec: pointer;
  91. PFSRec: pointer;
  92. end;
  93. TDosAllocThreadLocalMemory = function (Count: cardinal; var P: pointer):
  94. cardinal; cdecl;
  95. TDosFreeThreadLocalMemory = function (P: pointer): cardinal; cdecl;
  96. const
  97. DosAllocThreadLocalMemory: TDosAllocThreadLocalMemory = nil;
  98. DosFreeThreadLocalMemory: TDosFreeThreadLocalMemory = nil;
  99. OrdDosAllocThreadLocalMemory = 454;
  100. OrdDosFreeThreadLocalMemory = 455;
  101. TLSAPISupported: boolean = false;
  102. { import the necessary stuff from the OS }
  103. (*
  104. function DosAllocThreadLocalMemory (Count: cardinal; var P: pointer): cardinal;
  105. cdecl; external 'DOSCALLS' index 454;
  106. function DosFreeThreadLocalMemory (P: pointer): cardinal; cdecl;
  107. external 'DOSCALLS' index 455;
  108. *)
  109. function DosCreateThread (var TID: cardinal; Address: pointer;
  110. (* TThreadFunc *)
  111. aParam: pointer; Flags: cardinal; StackSize: cardinal): cardinal; cdecl;
  112. external 'DOSCALLS' index 311;
  113. function DosCreateMutExSem (Name: PChar; var Handle: THandle; Attr: cardinal;
  114. State: cardinal): cardinal; cdecl; external 'DOSCALLS' index 331;
  115. function DosCloseMutExSem (Handle: THandle): cardinal; cdecl;
  116. external 'DOSCALLS' index 333;
  117. function DosRequestMutExSem (Handle: THandle; Timeout: cardinal): cardinal;
  118. cdecl; external 'DOSCALLS' index 334;
  119. function DosReleaseMutExSem (Handle: THandle): cardinal; cdecl;
  120. external 'DOSCALLS' index 335;
  121. function DosSuspendThread (TID:cardinal): cardinal; cdecl;
  122. external 'DOSCALLS' index 238;
  123. function DosResumeThread (TID: cardinal): cardinal; cdecl;
  124. external 'DOSCALLS' index 237;
  125. function DosKillThread (TID: cardinal): cardinal; cdecl;
  126. external 'DOSCALLS' index 111;
  127. function DosWaitThread (var TID: cardinal; Option: cardinal): cardinal; cdecl;
  128. external 'DOSCALLS' index 349;
  129. procedure DosSleep (MSec: cardinal); cdecl; external 'DOSCALLS' index 229;
  130. {
  131. procedure DosExit (Action, Result: cardinal); cdecl;
  132. external 'DOSCALLS' index 234;
  133. Already declared in the main part of system.pas...
  134. }
  135. function DosSetPriority (Scope, TrClass: cardinal; Delta: longint;
  136. PortID: cardinal): cardinal; cdecl;
  137. external 'DOSCALLS' index 236;
  138. function DosCreateEventSem (Name: PChar; var Handle: THandle;
  139. Attr: cardinal; State: cardinal): cardinal; cdecl;
  140. external 'DOSCALLS' index 324;
  141. function DosCloseEventSem (Handle: THandle): cardinal; cdecl;
  142. external 'DOSCALLS' index 326;
  143. function DosResetEventSem (Handle: THandle; var PostCount: cardinal): cardinal;
  144. cdecl; external 'DOSCALLS' index 327;
  145. function DosPostEventSem (Handle: THandle): cardinal; cdecl;
  146. external 'DOSCALLS' index 328;
  147. function DosWaitEventSem (Handle: THandle; Timeout: cardinal): cardinal; cdecl;
  148. external 'DOSCALLS' index 329;
  149. function DosQueryEventSem (Handle: THandle; var Posted: cardinal): cardinal;
  150. cdecl; external 'DOSCALLS' index 330;
  151. function DosQuerySysState (EntityList, EntityLevel, PID, TID: cardinal;
  152. var Buffer; BufLen: cardinal): cardinal; cdecl;
  153. external 'DOSCALLS' index 368;
  154. {*****************************************************************************
  155. Threadvar support
  156. *****************************************************************************}
  157. const
  158. ThreadVarBlockSize: dword = 0;
  159. const
  160. (* Pointer to an allocated dword space within the local thread *)
  161. (* memory area. Pointer to the real memory block allocated for *)
  162. (* thread vars in this block is then stored in this dword. *)
  163. DataIndex: PPointer = nil;
  164. type
  165. (* If Thread Local Memory Area (TLMA) and the respective API functions are *)
  166. (* not available (OS/2 version 2.x) then handle the memory using array *)
  167. (* of pointers indexed by Thread ID - pointer to this array is then stored *)
  168. (* in DataIndex (typecasted using the following types). *)
  169. TTLSPointers = array [0..4095] of pointer;
  170. PTLSPointers = ^TTLSPointers;
  171. procedure SysInitThreadvar (var Offset: dword; Size: dword);
  172. begin
  173. Offset := ThreadVarBlockSize;
  174. Inc (ThreadVarBlockSize, Size);
  175. end;
  176. procedure SysAllocateThreadVars;
  177. var
  178. RC: cardinal;
  179. begin
  180. { we've to allocate the memory from the OS }
  181. { because the FPC heap management uses }
  182. { exceptions which use threadvars but }
  183. { these aren't allocated yet ... }
  184. { allocate room on the heap for the thread vars }
  185. if TLSAPISupported then
  186. RC := DosAllocMem (DataIndex^, ThreadVarBlockSize, pag_Read or pag_Write
  187. or pag_Commit)
  188. else
  189. begin
  190. if PTLSPointers (DataIndex)^ [ThreadID] <> nil then
  191. begin
  192. RC := DosFreeMem (PTLSPointers (DataIndex)^ [ThreadID]);
  193. if RC <> 0 then
  194. OSErrorWatch (RC);
  195. end;
  196. RC := DosAllocMem (PTLSPointers (DataIndex)^ [ThreadID], ThreadVarBlockSize,
  197. pag_Read or pag_Write or pag_Commit);
  198. end;
  199. if RC <> 0 then
  200. begin
  201. OSErrorWatch (RC);
  202. HandleError (8);
  203. end;
  204. { The Windows API apparently provides a way to fill the allocated memory with }
  205. { zeros; we probably need to do it ourselves for compatibility. }
  206. FillChar (DataIndex^^, 0, ThreadVarBlockSize);
  207. end;
  208. function SysRelocateThreadVar (Offset: dword): pointer;
  209. begin
  210. { DataIndex itself not checked for not being nil - expected that this should }
  211. { not be necessary because the equivalent check (i.e. TlsKey not being set) }
  212. { is not performed by the Windows implementation. }
  213. if PTLSPointers (DataIndex)^ [ThreadID] = nil then
  214. begin
  215. SysAllocateThreadVars;
  216. InitThread ($1000000);
  217. end;
  218. SysRelocateThreadVar := PTLSPointers (DataIndex)^ [ThreadID] + Offset;
  219. end;
  220. function OS2RelocateThreadVar (Offset: dword): pointer;
  221. begin
  222. { DataIndex itself not checked for not being nil - expected that this should }
  223. { not be necessary because the equivalent check (i.e. TlsKey not being set) }
  224. { is not performed by the Windows implementation. }
  225. if DataIndex^ = nil then
  226. begin
  227. SysAllocateThreadVars;
  228. InitThread ($1000000);
  229. end;
  230. OS2RelocateThreadVar := DataIndex^ + Offset;
  231. end;
  232. procedure SysInitMultithreading;
  233. var
  234. RC: cardinal;
  235. begin
  236. { do not check IsMultiThread, as program could have altered it, out of Delphi habit }
  237. { the thread attach/detach code uses locks to avoid multiple calls of this }
  238. if DataIndex = nil then
  239. begin
  240. { We're still running in single thread mode, setup the TLS }
  241. RC := DosAllocThreadLocalMemory (1, DataIndex);
  242. if RC = 0 then
  243. begin
  244. (* Avoid the need for checking TLSAPISupported on every call *)
  245. (* to RelocateThreadVar - ensure using the right version. *)
  246. OS2ThreadManager.RelocateThreadVar := @OS2RelocateThreadVar;
  247. CurrentTM.RelocateThreadVar := @OS2RelocateThreadVar;
  248. InitThreadVars (@OS2RelocateThreadvar);
  249. end
  250. else
  251. begin
  252. OSErrorWatch (RC);
  253. (* We can still try using the internal solution for older OS/2 versions... *)
  254. TLSAPISupported := false;
  255. RC := DosAllocMem (DataIndex, SizeOf (TTLSPointers),
  256. pag_Read or pag_Write or pag_Commit);
  257. if RC = 0 then
  258. InitThreadVars (@SysRelocateThreadvar)
  259. else
  260. begin
  261. OSErrorWatch (RC);
  262. RunError (8);
  263. end;
  264. end;
  265. IsMultiThread := true;
  266. end;
  267. end;
  268. procedure SysFiniMultithreading;
  269. var
  270. RC: cardinal;
  271. begin
  272. if IsMultiThread then
  273. begin
  274. if TLSAPISupported then
  275. RC := DosFreeThreadLocalMemory (DataIndex)
  276. else
  277. RC := DosFreeMem (DataIndex);
  278. if RC <> 0 then
  279. begin
  280. {??? What to do if releasing fails?}
  281. OSErrorWatch (RC);
  282. end;
  283. DataIndex := nil;
  284. end;
  285. end;
  286. procedure SysReleaseThreadVars;
  287. var
  288. RC: cardinal;
  289. (* TID serves for storing ThreadID before freeing the memory allocated *)
  290. (* to threadvars to avoid accessing a threadvar ThreadID afterwards. *)
  291. TID: cardinal;
  292. begin
  293. if TLSAPISupported then
  294. begin
  295. RC := DosFreeMem (DataIndex^);
  296. DataIndex^ := nil;
  297. end
  298. else
  299. begin
  300. TID := ThreadID;
  301. RC := DosFreeMem (PTLSPointers (DataIndex)^ [TID]);
  302. PTLSPointers (DataIndex)^ [TID] := nil;
  303. end;
  304. if RC <> 0 then
  305. OSErrorWatch (RC);
  306. end;
  307. (* procedure InitThreadVars;
  308. begin
  309. { allocate one ThreadVar entry from the OS, we use this entry }
  310. { for a pointer to our threadvars }
  311. if DosAllocThreadLocalMemory (1, DataIndex) <> 0 then HandleError (8);
  312. { initialize threadvars }
  313. init_all_unit_threadvars;
  314. { allocate mem for main thread threadvars }
  315. SysAllocateThreadVars;
  316. { copy main thread threadvars }
  317. copy_all_unit_threadvars;
  318. { install threadvar handler }
  319. fpc_threadvar_relocate_proc := @SysRelocateThreadvar;
  320. end;
  321. *)
  322. {*****************************************************************************
  323. Thread starting
  324. *****************************************************************************}
  325. type
  326. pthreadinfo = ^tthreadinfo;
  327. tthreadinfo = record
  328. f : tthreadfunc;
  329. p : pointer;
  330. stklen : cardinal;
  331. end;
  332. (* procedure InitThread(stklen:cardinal);
  333. begin
  334. SysResetFPU;
  335. SysInitFPU;
  336. { ExceptAddrStack and ExceptObjectStack are threadvars }
  337. { so every thread has its on exception handling capabilities }
  338. SysInitExceptions;
  339. { Open all stdio fds again }
  340. SysInitStdio;
  341. InOutRes:=0;
  342. // ErrNo:=0;
  343. { Stack checking }
  344. StackLength:=stklen;
  345. StackBottom:=Sptr - StackLength;
  346. end;
  347. *)
  348. function ThreadMain(param : pointer) : pointer;cdecl;
  349. var
  350. ti : tthreadinfo;
  351. begin
  352. { Allocate local thread vars, this must be the first thing,
  353. because the exception management and io depends on threadvars }
  354. SysAllocateThreadVars;
  355. { Copy parameter to local data }
  356. {$ifdef DEBUG_MT}
  357. writeln('New thread started, initialising ...');
  358. {$endif DEBUG_MT}
  359. ti:=pthreadinfo(param)^;
  360. dispose(pthreadinfo(param));
  361. { Initialize thread }
  362. InitThread(ti.stklen);
  363. { Start thread function }
  364. {$ifdef DEBUG_MT}
  365. writeln('Jumping to thread function');
  366. {$endif DEBUG_MT}
  367. ThreadMain:=pointer(ti.f(ti.p));
  368. end;
  369. function SysBeginThread (SA: pointer; StackSize : PtrUInt;
  370. ThreadFunction: TThreadFunc; P: pointer;
  371. CreationFlags: cardinal; var ThreadId: TThreadID): DWord;
  372. var
  373. TI: PThreadInfo;
  374. RC: cardinal;
  375. begin
  376. { WriteLn is not a good idea before thread initialization...
  377. $ifdef DEBUG_MT
  378. WriteLn ('Creating new thread');
  379. $endif DEBUG_MT}
  380. { Initialize multithreading if not done }
  381. SysInitMultithreading;
  382. { the only way to pass data to the newly created thread
  383. in a MT safe way, is to use the heap }
  384. New (TI);
  385. TI^.F := ThreadFunction;
  386. TI^.P := P;
  387. TI^.StkLen := StackSize;
  388. ThreadID := 0;
  389. {$ifdef DEBUG_MT}
  390. WriteLn ('Starting new thread');
  391. {$endif DEBUG_MT}
  392. RC := DosCreateThread (cardinal (ThreadID), @ThreadMain, TI,
  393. CreationFlags, StackSize);
  394. if RC = 0 then
  395. SysBeginThread := ThreadID
  396. else
  397. begin
  398. SysBeginThread := 0;
  399. {$IFDEF DEBUG_MT}
  400. WriteLn ('Thread creation failed');
  401. {$ENDIF DEBUG_MT}
  402. Dispose (TI);
  403. OSErrorWatch (RC);
  404. end;
  405. end;
  406. procedure SysEndThread (ExitCode: cardinal);
  407. begin
  408. DoneThread;
  409. DosExit (0, ExitCode);
  410. end;
  411. procedure SysThreadSwitch;
  412. begin
  413. DosSleep (0);
  414. end;
  415. function SysSuspendThread (ThreadHandle: dword): dword;
  416. var
  417. RC: cardinal;
  418. begin
  419. {$WARNING Check expected return value}
  420. RC := DosSuspendThread (ThreadHandle);
  421. SysSuspendThread := RC;
  422. if RC <> 0 then
  423. OSErrorWatch (RC);
  424. end;
  425. function SysResumeThread (ThreadHandle: dword): dword;
  426. var
  427. RC: cardinal;
  428. begin
  429. {$WARNING Check expected return value}
  430. RC := DosResumeThread (ThreadHandle);
  431. SysResumeThread := RC;
  432. if RC <> 0 then
  433. OSErrorWatch (RC);
  434. end;
  435. function SysKillThread (ThreadHandle: dword): dword;
  436. var
  437. RC: cardinal;
  438. begin
  439. RC := DosKillThread (ThreadHandle);
  440. SysKillThread := RC;
  441. if RC <> 0 then
  442. OSErrorWatch (RC);
  443. end;
  444. {$PUSH}
  445. {$WARNINGS OFF}
  446. function SysCloseThread (ThreadHandle: TThreadID): dword;
  447. begin
  448. { Probably not relevant under OS/2? }
  449. // SysCloseThread:=CloseHandle(threadHandle);
  450. end;
  451. {$POP}
  452. function SysWaitForThreadTerminate (ThreadHandle: dword;
  453. TimeoutMs: longint): dword;
  454. var
  455. RC, RC2: cardinal;
  456. const
  457. { Wait at most 100 ms before next check for thread termination }
  458. WaitTime = 100;
  459. begin
  460. if TimeoutMs = 0 then
  461. begin
  462. RC := DosWaitThread (ThreadHandle, dcWW_Wait);
  463. if RC <> 0 then
  464. OSErrorWatch (RC);
  465. end
  466. else
  467. repeat
  468. RC := DosWaitThread (ThreadHandle, dcWW_NoWait);
  469. if RC = 294 then
  470. begin
  471. if TimeoutMs > WaitTime then
  472. DosSleep (WaitTime)
  473. else
  474. begin
  475. DosSleep (TimeoutMs);
  476. RC2 := DosWaitThread (ThreadHandle, dcWW_NoWait);
  477. if RC2 <> 0 then
  478. OSErrorWatch (RC2);
  479. end;
  480. Dec (TimeoutMs, WaitTime);
  481. end
  482. else if RC <> 0 then
  483. OSErrorWatch (RC);
  484. until (RC <> 294) or (TimeoutMs <= 0);
  485. SysWaitForThreadTerminate := RC;
  486. end;
  487. function GetOS2ThreadPriority (ThreadHandle: dword): cardinal;
  488. const
  489. BufSize = 32768; (* Sufficient space for > 1000 threads (for one process!) *)
  490. var
  491. PPtrRec: PQSPtrRec;
  492. PTRec: PQSTRec;
  493. BufEnd: PtrUInt;
  494. RC: cardinal;
  495. begin
  496. GetOS2ThreadPriority := cardinal (-1);
  497. GetMem (PPtrRec, BufSize);
  498. if PPtrRec = nil then
  499. begin
  500. FreeMem (PPtrRec, BufSize);
  501. FPC_ThreadError;
  502. end
  503. else
  504. begin
  505. RC := DosQuerySysState (qs_Process, 0, ProcessID, 0, PPtrRec^, BufSize);
  506. if RC <> 0 then
  507. OSErrorWatch (RC)
  508. else if (PPtrRec^.PProcRec <> nil)
  509. and (PPtrRec^.PProcRec^.PThrdRec <> nil) then
  510. begin
  511. BufEnd := PtrUInt (PPtrRec) + BufSize;
  512. PTRec := PPtrRec^.PProcRec^.PThrdRec;
  513. while (PTRec^.RecType = qs_Thread) and (PTRec^.TID <> ThreadHandle) and
  514. (PtrUInt (PTRec) + SizeOf (PTRec^) < BufEnd) do
  515. Inc (PTRec);
  516. if (PTRec^.RecType = qs_Thread) and (PTRec^.TID = ThreadHandle) then
  517. GetOS2ThreadPriority := PTRec^.Priority;
  518. end;
  519. FreeMem (PPtrRec, BufSize);
  520. end;
  521. end;
  522. type
  523. TPrio = packed record
  524. PrioLevel: byte;
  525. PrioClass: byte;
  526. Padding: word;
  527. end;
  528. function SysThreadSetPriority (ThreadHandle: dword; Prio: longint): boolean;
  529. {-15..+15, 0=normal}
  530. var
  531. Delta: longint;
  532. Priority: cardinal;
  533. RC: cardinal;
  534. begin
  535. Priority := GetOS2ThreadPriority (ThreadHandle);
  536. if Priority > High (word) then
  537. SysThreadSetPriority := false
  538. else
  539. begin
  540. Delta := Prio * 2;
  541. if Delta + TPrio (Priority).PrioLevel < 0 then
  542. Delta := - TPrio (Priority).PrioLevel
  543. else if Delta + TPrio (Priority).PrioLevel > 31 then
  544. Delta := 31 - TPrio (Priority).PrioLevel;
  545. RC := DosSetPriority (dpThread, dpSameClass, Delta, ThreadHandle);
  546. if RC <> 0 then
  547. OSErrorWatch (RC);
  548. SysThreadSetPriority := RC = 0;
  549. end;
  550. end;
  551. function SysThreadGetPriority (ThreadHandle: dword): longint;
  552. var
  553. Priority: cardinal;
  554. begin
  555. Priority := GetOS2ThreadPriority (ThreadHandle);
  556. (*
  557. Windows priority levels follow a fairly strange logic; let's mimic at least
  558. the part related to the idle priority returning negative numbers.
  559. Result range (based on Windows behaviour) is -15..+15.
  560. *)
  561. if TPrio (Priority).PrioClass = 1 then
  562. SysThreadGetPriority := TPrio (Priority).PrioLevel div 2 - 15
  563. else
  564. SysThreadGetPriority := TPrio (Priority).PrioLevel div 2;
  565. end;
  566. function SysGetCurrentThreadID: dword;
  567. var
  568. TIB: PThreadInfoBlock;
  569. begin
  570. DosGetInfoBlocks (@TIB, nil);
  571. SysGetCurrentThreadID := TIB^.TIB2^.TID;
  572. end;
  573. {*****************************************************************************
  574. Delphi/Win32 compatibility
  575. *****************************************************************************}
  576. procedure SysInitCriticalSection (var CS);
  577. var
  578. RC: cardinal;
  579. begin
  580. RC := DosCreateMutExSem (nil, THandle (CS), 0, 0);
  581. if RC <> 0 then
  582. begin
  583. OSErrorWatch (RC);
  584. FPC_ThreadError;
  585. end;
  586. end;
  587. procedure SysDoneCriticalSection (var CS);
  588. var
  589. RC: cardinal;
  590. begin
  591. (* Trying to release first since this might apparently be the expected *)
  592. (* behaviour in Delphi according to comment in the Unix implementation. *)
  593. repeat
  594. until DosReleaseMutExSem (THandle (CS)) <> 0;
  595. RC := DosCloseMutExSem (THandle (CS));
  596. if RC <> 0 then
  597. begin
  598. OSErrorWatch (RC);
  599. FPC_ThreadError;
  600. end;
  601. end;
  602. procedure SysEnterCriticalSection (var CS);
  603. var
  604. RC: cardinal;
  605. begin
  606. RC := DosRequestMutExSem (THandle (CS), cardinal (-1));
  607. if RC <> 0 then
  608. begin
  609. OSErrorWatch (RC);
  610. FPC_ThreadError;
  611. end;
  612. end;
  613. function SysTryEnterCriticalSection (var CS): longint;
  614. begin
  615. if DosRequestMutExSem (THandle (CS), 0) = 0 then
  616. Result := 1
  617. else
  618. Result := 0;
  619. end;
  620. procedure SysLeaveCriticalSection (var CS);
  621. var
  622. RC: cardinal;
  623. begin
  624. RC := DosReleaseMutExSem (THandle (CS));
  625. if RC <> 0 then
  626. begin
  627. OSErrorWatch (RC);
  628. FPC_ThreadError;
  629. end;
  630. end;
  631. type
  632. TBasicEventState = record
  633. FHandle: THandle;
  634. FLastError: longint;
  635. end;
  636. PLocalEventRec = ^TBasicEventState;
  637. const
  638. wrSignaled = 0;
  639. wrTimeout = 1;
  640. wrAbandoned = 2; (* This cannot happen for an event semaphore with OS/2? *)
  641. wrError = 3;
  642. Error_Timeout = 640;
  643. OS2SemNamePrefix = '\SEM32\';
  644. function SysBasicEventCreate (EventAttributes: Pointer;
  645. AManualReset, InitialState: boolean; const Name: ansistring): PEventState;
  646. var
  647. RC: cardinal;
  648. Name2: ansistring;
  649. Attr: cardinal;
  650. begin
  651. New (PLocalEventRec (Result));
  652. if (Name <> '') and (UpCase (Copy (Name, 1, 7)) <> OS2SemNamePrefix) then
  653. Name2 := OS2SemNamePrefix + Name
  654. else
  655. Name2 := Name;
  656. if AManualReset then
  657. Attr := 0
  658. else
  659. Attr := DCE_AutoReset;
  660. if Name2 = '' then
  661. RC := DosCreateEventSem (nil, PLocalEventRec (Result)^.FHandle,
  662. Attr, cardinal (InitialState))
  663. else
  664. RC := DosCreateEventSem (PChar (Name2), PLocalEventRec (Result)^.FHandle,
  665. Attr, cardinal (InitialState));
  666. if RC <> 0 then
  667. begin
  668. Dispose (PLocalEventRec (Result));
  669. OSErrorWatch (RC);
  670. FPC_ThreadError;
  671. end;
  672. end;
  673. procedure SysBasicEventDestroy (State: PEventState);
  674. var
  675. RC: cardinal;
  676. begin
  677. if State = nil then
  678. FPC_ThreadError
  679. else
  680. begin
  681. RC := DosCloseEventSem (PLocalEventRec (State)^.FHandle);
  682. if RC <> 0 then
  683. OSErrorWatch (RC);
  684. Dispose (PLocalEventRec (State));
  685. end;
  686. end;
  687. procedure SysBasicEventResetEvent (State: PEventState);
  688. var
  689. PostCount: cardinal;
  690. RC: cardinal;
  691. begin
  692. if State = nil then
  693. FPC_ThreadError
  694. else
  695. begin
  696. (* In case of later addition of error checking: *)
  697. (* RC 300 = Error_Already_Reset which would be OK. *)
  698. RC := DosResetEventSem (PLocalEventRec (State)^.FHandle, PostCount);
  699. if (RC <> 0) and (RC <> 300) then
  700. OSErrorWatch (RC);
  701. end;
  702. end;
  703. procedure SysBasicEventSetEvent (State: PEventState);
  704. var
  705. RC: cardinal;
  706. begin
  707. if State = nil then
  708. FPC_ThreadError
  709. else
  710. begin
  711. RC := DosPostEventSem (PLocalEventRec (State)^.FHandle);
  712. if RC <> 0 then
  713. OSErrorWatch (RC);
  714. end;
  715. end;
  716. function SysBasicEventWaitFor (Timeout: Cardinal; State: PEventState): longint;
  717. var
  718. RC: cardinal;
  719. begin
  720. if State = nil then
  721. FPC_ThreadError
  722. else
  723. begin
  724. RC := DosWaitEventSem (PLocalEventRec (State)^.FHandle, Timeout);
  725. case RC of
  726. 0: Result := wrSignaled;
  727. Error_Timeout: Result := wrTimeout;
  728. else
  729. begin
  730. Result := wrError;
  731. OSErrorWatch (RC);
  732. PLocalEventRec (State)^.FLastError := RC;
  733. end;
  734. end;
  735. end;
  736. end;
  737. function SysRTLEventCreate: PRTLEvent;
  738. var
  739. RC: cardinal;
  740. begin
  741. Result := PRTLEvent (-1);
  742. RC := DosCreateEventSem (nil, THandle (Result), dce_AutoReset, 0);
  743. if RC <> 0 then
  744. OSErrorWatch (RC);
  745. end;
  746. procedure SysRTLEventDestroy (AEvent: PRTLEvent);
  747. var
  748. RC: cardinal;
  749. begin
  750. RC := DosCloseEventSem (THandle (AEvent));
  751. if RC <> 0 then
  752. OSErrorWatch (RC);
  753. end;
  754. procedure SysRTLEventSetEvent (AEvent: PRTLEvent);
  755. var
  756. RC: cardinal;
  757. begin
  758. RC := DosPostEventSem (THandle (AEvent));
  759. if RC <> 0 then
  760. OSErrorWatch (RC);
  761. end;
  762. procedure SysRTLEventWaitFor (AEvent: PRTLEvent);
  763. var
  764. RC: cardinal;
  765. begin
  766. RC := DosWaitEventSem (THandle (AEvent), cardinal (-1));
  767. if RC <> 0 then
  768. OSErrorWatch (RC);
  769. end;
  770. procedure SysRTLEventWaitForTimeout (AEvent: PRTLEvent; Timeout: longint);
  771. var
  772. RC: cardinal;
  773. begin
  774. RC := DosWaitEventSem (THandle (AEvent), Timeout);
  775. if RC <> 0 then
  776. OSErrorWatch (RC);
  777. end;
  778. procedure SysRTLEventResetEvent (AEvent: PRTLEvent);
  779. var
  780. PostCount: cardinal;
  781. RC: cardinal;
  782. begin
  783. RC := DosResetEventSem (THandle (AEvent), PostCount);
  784. if RC <> 0 then
  785. OSErrorWatch (RC);
  786. end;
  787. {$DEFINE HAS_GETCPUCOUNT}
  788. function GetCPUCount: LongWord;
  789. const
  790. svNumProcessors = 26;
  791. var
  792. ProcNum: cardinal;
  793. RC: cardinal;
  794. begin
  795. GetCPUCount := 1;
  796. RC := DosQuerySysInfo (svNumProcessors, svNumProcessors, ProcNum,
  797. SizeOf (ProcNum));
  798. if RC = 0 then
  799. GetCPUCount := ProcNum
  800. else
  801. OSErrorWatch (RC);
  802. end;
  803. procedure InitSystemThreads;
  804. begin
  805. with OS2ThreadManager do
  806. begin
  807. InitManager :=Nil;
  808. DoneManager :=Nil;
  809. BeginThread :=@SysBeginThread;
  810. EndThread :=@SysEndThread;
  811. SuspendThread :=@SysSuspendThread;
  812. ResumeThread :=@SysResumeThread;
  813. KillThread :=@SysKillThread;
  814. CloseThread :=@SysCloseThread;
  815. ThreadSwitch :=@SysThreadSwitch;
  816. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  817. ThreadSetPriority :=@SysThreadSetPriority;
  818. ThreadGetPriority :=@SysThreadGetPriority;
  819. GetCurrentThreadId :=@SysGetCurrentThreadId;
  820. InitCriticalSection :=@SysInitCriticalSection;
  821. DoneCriticalSection :=@SysDoneCriticalSection;
  822. EnterCriticalSection :=@SysEnterCriticalSection;
  823. TryEnterCriticalSection:=@SysTryEnterCriticalSection;
  824. LeaveCriticalSection :=@SysLeaveCriticalSection;
  825. InitThreadVar :=@SysInitThreadVar;
  826. RelocateThreadVar :=@SysRelocateThreadVar;
  827. AllocateThreadVars :=@SysAllocateThreadVars;
  828. ReleaseThreadVars :=@SysReleaseThreadVars;
  829. BasicEventCreate :=@SysBasicEventCreate;
  830. BasicEventDestroy :=@SysBasicEventDestroy;
  831. BasicEventSetEvent :=@SysBasicEventSetEvent;
  832. BasicEventResetEvent :=@SysBasicEventResetEvent;
  833. BasiceventWaitFor :=@SysBasiceventWaitFor;
  834. RTLEventCreate :=@SysRTLEventCreate;
  835. RTLEventDestroy :=@SysRTLEventDestroy;
  836. RTLEventSetEvent :=@SysRTLEventSetEvent;
  837. RTLEventResetEvent :=@SysRTLEventResetEvent;
  838. RTLEventWaitFor :=@SysRTLEventWaitFor;
  839. RTLEventWaitForTimeout :=@SysRTLEventWaitForTimeout;
  840. end;
  841. SetThreadManager (OS2ThreadManager);
  842. end;