systhrds.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2002 by 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. unit systhrds;
  13. interface
  14. {$S-}
  15. type
  16. { the fields of this record are os dependent }
  17. { and they shouldn't be used in a program }
  18. { only the type TCriticalSection is important }
  19. PRTLCriticalSection = ^TRTLCriticalSection;
  20. TRTLCriticalSection = packed record
  21. DebugInfo : pointer;
  22. LockCount : longint;
  23. RecursionCount : longint;
  24. OwningThread : DWord;
  25. LockSemaphore : DWord;
  26. Reserved : DWord;
  27. end;
  28. { Include generic thread interface }
  29. {$i threadh.inc}
  30. implementation
  31. {*****************************************************************************
  32. Generic overloaded
  33. *****************************************************************************}
  34. { Include generic overloaded routines }
  35. {$i thread.inc}
  36. {*****************************************************************************
  37. Local Api imports
  38. *****************************************************************************}
  39. const
  40. pag_Read = 1;
  41. pag_Write = 2;
  42. pag_Execute = 4;
  43. pag_Guard = 8;
  44. pag_Commit = $10;
  45. obj_Tile = $40;
  46. sem_Indefinite_Wait = -1;
  47. dtSuspended = 1;
  48. dtStack_Commited = 2;
  49. type
  50. TByteArray = array [0..$ffff] of byte;
  51. PByteArray = ^TByteArray;
  52. TSysThreadIB = record
  53. TID,
  54. Priority,
  55. Version: cardinal;
  56. MCCount,
  57. MCForceFlag: word;
  58. end;
  59. PSysThreadIB = ^TSysThreadIB;
  60. TThreadInfoBlock = record
  61. PExChain,
  62. Stack,
  63. StackLimit: pointer;
  64. TIB2: PSysThreadIB;
  65. Version,
  66. Ordinal: cardinal;
  67. end;
  68. PThreadInfoBlock = ^TThreadInfoBlock;
  69. PPThreadInfoBlock = ^PThreadInfoBlock;
  70. TProcessInfoBlock = record
  71. PID,
  72. ParentPid,
  73. Handle: cardinal;
  74. Cmd,
  75. Env: PByteArray;
  76. Status,
  77. ProcType: cardinal;
  78. end;
  79. PProcessInfoBlock = ^TProcessInfoBlock;
  80. PPProcessInfoBlock = ^PProcessInfoBlock;
  81. { import the necessary stuff from the OS }
  82. function DosAllocThreadLocalMemory (Count: cardinal; var P: pointer): cardinal;
  83. cdecl; external 'DOSCALLS' index 454;
  84. function DosFreeThreadLocalMemory (P: pointer): cardinal; cdecl;
  85. external 'DOSCALLS' index 455;
  86. function DosCreateThread (var TID: cardinal; Address: pointer;
  87. (* TThreadFunc *)
  88. aParam: pointer; Flags: cardinal; StackSize: cardinal): cardinal; cdecl;
  89. external 'DOSCALLS' index 311;
  90. procedure DosExit (Action, Result: cardinal); cdecl;
  91. external 'DOSCALLS' index 234;
  92. function DosCreateMutExSem (Name: PChar; var Handle: longint; Attr: cardinal;
  93. State: boolean): cardinal; cdecl; external 'DOSCALLS' index 331;
  94. function DosCloseMutExSem (Handle: longint): cardinal; cdecl;
  95. external 'DOSCALLS' index 333;
  96. function DosQueryMutExSem (Handle: longint; var PID, TID, Count: cardinal):
  97. cardinal; cdecl; external 'DOSCALLS' index 336;
  98. function DosRequestMutExSem (Handle:longint; Timeout: cardinal): cardinal; cdecl;
  99. external 'DOSCALLS' index 334;
  100. function DosReleaseMutExSem (Handle: longint): cardinal; cdecl;
  101. external 'DOSCALLS' index 335;
  102. function DosAllocMem (var P: pointer; Size, Flag: cardinal): cardinal; cdecl;
  103. external 'DOSCALLS' index 299;
  104. function DosFreeMem (P: pointer): cardinal; cdecl;
  105. external 'DOSCALLS' index 304;
  106. {
  107. function DosEnterCritSec:cardinal; cdecl; external 'DOSCALLS' index 232;
  108. function DosExitCritSec:cardinal; cdecl; external 'DOSCALLS' index 233;
  109. }
  110. procedure DosGetInfoBlocks (PATIB: PPThreadInfoBlock;
  111. PAPIB: PPProcessInfoBlock); cdecl;
  112. external 'DOSCALLS' index 312;
  113. procedure DosSleep (MSec: cardinal); cdecl; external 'DOSCALLS' index 229;
  114. {*****************************************************************************
  115. Threadvar support
  116. *****************************************************************************}
  117. {$ifdef HASTHREADVAR}
  118. const
  119. ThreadVarBlockSize: dword = 0;
  120. var
  121. (* Pointer to an allocated dword space within the local thread *)
  122. (* memory area. Pointer to the real memory block allocated for *)
  123. (* thread vars in this block is then stored in this dword. *)
  124. DataIndex: PPointer;
  125. procedure SysInitThreadvar (var Offset: dword; Size: dword);
  126. begin
  127. Offset := ThreadVarBlockSize;
  128. Inc (ThreadVarBlockSize, Size);
  129. end;
  130. function SysRelocateThreadVar (Offset: dword): pointer;
  131. begin
  132. SysRelocateThreadVar := DataIndex^ + Offset;
  133. end;
  134. procedure SysAllocateThreadVars;
  135. begin
  136. { we've to allocate the memory from the OS }
  137. { because the FPC heap management uses }
  138. { exceptions which use threadvars but }
  139. { these aren't allocated yet ... }
  140. { allocate room on the heap for the thread vars }
  141. if DosAllocMem (DataIndex^, ThreadVarBlockSize, pag_Read or pag_Write
  142. or pag_Commit) <> 0 then HandleError (8);
  143. end;
  144. procedure SysReleaseThreadVars;
  145. begin
  146. { release thread vars }
  147. DosFreeMem (DataIndex^);
  148. end;
  149. { Include OS independent Threadvar initialization }
  150. {$i threadvar.inc}
  151. (* procedure InitThreadVars;
  152. begin
  153. { allocate one ThreadVar entry from the OS, we use this entry }
  154. { for a pointer to our threadvars }
  155. if DosAllocThreadLocalMemory (1, DataIndex) <> 0 then HandleError (8);
  156. { initialize threadvars }
  157. init_all_unit_threadvars;
  158. { allocate mem for main thread threadvars }
  159. SysAllocateThreadVars;
  160. { copy main thread threadvars }
  161. copy_all_unit_threadvars;
  162. { install threadvar handler }
  163. fpc_threadvar_relocate_proc := @SysRelocateThreadvar;
  164. end;
  165. *)
  166. {$endif HASTHREADVAR}
  167. {*****************************************************************************
  168. Thread starting
  169. *****************************************************************************}
  170. const
  171. DefaultStackSize = 32768; { including 16384 margin for stackchecking }
  172. type
  173. pthreadinfo = ^tthreadinfo;
  174. tthreadinfo = record
  175. f : tthreadfunc;
  176. p : pointer;
  177. stklen : cardinal;
  178. end;
  179. (* procedure InitThread(stklen:cardinal);
  180. begin
  181. SysResetFPU;
  182. { ExceptAddrStack and ExceptObjectStack are threadvars }
  183. { so every thread has its on exception handling capabilities }
  184. SysInitExceptions;
  185. { Open all stdio fds again }
  186. SysInitStdio;
  187. InOutRes:=0;
  188. // ErrNo:=0;
  189. { Stack checking }
  190. StackLength:=stklen;
  191. StackBottom:=Sptr - StackLength;
  192. end;
  193. *)
  194. procedure DoneThread;
  195. begin
  196. { Release Threadvars }
  197. {$ifdef HASTHREADVAR}
  198. SysReleaseThreadVars;
  199. {$endif HASTHREADVAR}
  200. end;
  201. function ThreadMain(param : pointer) : pointer;cdecl;
  202. var
  203. ti : tthreadinfo;
  204. begin
  205. {$ifdef HASTHREADVAR}
  206. { Allocate local thread vars, this must be the first thing,
  207. because the exception management and io depends on threadvars }
  208. SysAllocateThreadVars;
  209. {$endif HASTHREADVAR}
  210. { Copy parameter to local data }
  211. {$ifdef DEBUG_MT}
  212. writeln('New thread started, initialising ...');
  213. {$endif DEBUG_MT}
  214. ti:=pthreadinfo(param)^;
  215. dispose(pthreadinfo(param));
  216. { Initialize thread }
  217. InitThread(ti.stklen);
  218. { Start thread function }
  219. {$ifdef DEBUG_MT}
  220. writeln('Jumping to thread function');
  221. {$endif DEBUG_MT}
  222. ThreadMain:=pointer(ti.f(ti.p));
  223. end;
  224. function SysBeginThread (SA: pointer; StackSize: cardinal;
  225. ThreadFunction: TThreadFunc; P: pointer;
  226. CreationFlags: cardinal; var ThreadId: cardinal): cardinal;
  227. var
  228. TI: PThreadInfo;
  229. begin
  230. {$ifdef DEBUG_MT}
  231. writeln('Creating new thread');
  232. {$endif DEBUG_MT}
  233. { Initialize multithreading if not done }
  234. if not IsMultiThread then
  235. begin
  236. {$ifdef HASTHREADVAR}
  237. if DosAllocThreadLocalMemory (1, DataIndex) <> 0
  238. then RunError (8);
  239. InitThreadVars;
  240. {$endif HASTHREADVAR}
  241. IsMultiThread:=true;
  242. end;
  243. { the only way to pass data to the newly created thread
  244. in a MT safe way, is to use the heap }
  245. New (TI);
  246. TI^.F := ThreadFunction;
  247. TI^.P := P;
  248. TI^.StkLen := StackSize;
  249. { call pthread_create }
  250. {$ifdef DEBUG_MT}
  251. writeln('Starting new thread');
  252. {$endif DEBUG_MT}
  253. SysBeginThread := DosCreateThread (ThreadID, @ThreadMain, SA,
  254. CreationFlags, StackSize: cardinal);
  255. end;
  256. procedure SysEndThread (ExitCode : DWord);
  257. begin
  258. DoneThread;
  259. DosExit (1, ExitCode);
  260. end;
  261. procedure SysThreadSwitch;
  262. begin
  263. DosSleep (0);
  264. end;
  265. function SysSuspendThread (ThreadHandle: dword): dword;
  266. begin
  267. {$WARNING TODO!}
  268. { SysSuspendThread := WinSuspendThread(threadHandle);
  269. }
  270. end;
  271. function SysResumeThread (ThreadHandle: dword): dword;
  272. begin
  273. {$WARNING TODO!}
  274. { SysResumeThread := WinResumeThread(threadHandle);
  275. }
  276. end;
  277. function SysKillThread (ThreadHandle: dword): dword;
  278. var
  279. ExitCode: dword;
  280. begin
  281. {$WARNING TODO!}
  282. {
  283. if not TerminateThread (ThreadHandle, ExitCode) then
  284. SysKillThread := GetLastError
  285. else
  286. SysKillThread := 0;
  287. }
  288. end;
  289. function SysWaitForThreadTerminate (ThreadHandle: dword;
  290. TimeoutMs: longint): dword;
  291. begin
  292. {$WARNING TODO!}
  293. {
  294. if TimeoutMs = 0 then dec (timeoutMs); // $ffffffff is INFINITE
  295. SysWaitForThreadTerminate := WaitForSingleObject(threadHandle, TimeoutMs);
  296. }
  297. end;
  298. function SysThreadSetPriority (ThreadHandle: dword;
  299. Prio: longint): boolean;
  300. {-15..+15, 0=normal}
  301. begin
  302. {$WARNING TODO!}
  303. {
  304. SysThreadSetPriority:=WinThreadSetPriority(threadHandle,Prio);
  305. }
  306. end;
  307. function SysThreadGetPriority (ThreadHandle: dword): integer;
  308. begin
  309. {$WARNING TODO!}
  310. {
  311. SysThreadGetPriority:=WinThreadGetPriority(threadHandle);
  312. }
  313. end;
  314. function SysGetCurrentThreadID: dword;
  315. begin
  316. {$WARNING TODO!}
  317. {
  318. SysGetCurrentThreadId:=WinGetCurrentThreadId;
  319. }
  320. end;
  321. {*****************************************************************************
  322. Delphi/Win32 compatibility
  323. *****************************************************************************}
  324. { DosEnter/ExitCritSec have quite a few limitations, so let's try to avoid
  325. them. I'm not sure whether mutex semaphores are SMP-safe, though... :-( }
  326. procedure SysInitCriticalSection(var CS: TRTLCriticalSection);
  327. begin
  328. {$WARNING TODO!}
  329. end;
  330. procedure SysDoneCriticalSection (var CS: TRTLCriticalSection);
  331. begin
  332. {$WARNING TODO!}
  333. end;
  334. procedure EnterCriticalSection (var CS: TRTLCriticalSection);
  335. begin
  336. {$WARNING TODO!}
  337. end;
  338. procedure LeaveCriticalSection (var CS: TRTLCriticalSection);
  339. begin
  340. {$WARNING TODO!}
  341. end;
  342. {*****************************************************************************
  343. Heap Mutex Protection
  344. *****************************************************************************}
  345. var
  346. HeapMutex: TRTLCriticalSection;
  347. procedure OS2HeapMutexInit;
  348. begin
  349. InitCriticalSection (HeapMutex);
  350. end;
  351. procedure OS2HeapMutexDone;
  352. begin
  353. DoneCriticalSection (HeapMutex);
  354. end;
  355. procedure OS2HeapMutexLock;
  356. begin
  357. EnterCriticalSection (HeapMutex);
  358. end;
  359. procedure OS2HeapMutexUnlock;
  360. begin
  361. LeaveCriticalSection (HeapMutex);
  362. end;
  363. const
  364. OS2MemoryMutexManager : TMemoryMutexManager = (
  365. MutexInit : @OS2HeapMutexInit;
  366. MutexDone : @OS2HeapMutexDone;
  367. MutexLock : @OS2HeapMutexLock;
  368. MutexUnlock : @OS2HeapMutexUnlock;
  369. );
  370. procedure InitHeapMutexes;
  371. begin
  372. SetMemoryMutexManager (OS2MemoryMutexManager);
  373. end;
  374. type
  375. TBasicEventState = record
  376. FHandle: THandle;
  377. FLastError: longint;
  378. end;
  379. PLocalEventRec = ^TBasicEventState;
  380. function IntBasicEventCreate (EventAttributes: Pointer;
  381. AManualReset, InitialState: Boolean; const Name: ansistring): PEventState;
  382. begin
  383. New (PLocalEventRec (Result));
  384. {$WARNING TODO!}
  385. {
  386. PLocalEventrec (Result)^.FHandle :=
  387. CreateEvent (EventAttributes, AManualReset, InitialState,PChar(Name));
  388. }
  389. end;
  390. procedure IntBasicEventDestroy (State: PEventState);
  391. begin
  392. {$WARNING TODO!}
  393. {
  394. closehandle(plocaleventrec(state)^.fhandle);
  395. }
  396. Dispose (PLocalEventRec (State));
  397. end;
  398. procedure IntBasicEventResetEvent (State: PEventState);
  399. begin
  400. {$WARNING TODO!}
  401. {
  402. ResetEvent(plocaleventrec(state)^.FHandle)
  403. }
  404. end;
  405. procedure IntBasicEventSetEvent (State: PEventState);
  406. begin
  407. {$WARNING TODO!}
  408. {
  409. SetEvent(plocaleventrec(state)^.FHandle);
  410. }
  411. end;
  412. function IntBasicEventWaitFor (Timeout: Cardinal; State: PEventState): longint;
  413. begin
  414. {$WARNING TODO!}
  415. {
  416. case WaitForSingleObject(plocaleventrec(state)^.fHandle, Timeout) of
  417. WAIT_ABANDONED: Result := wrAbandoned;
  418. WAIT_OBJECT_0: Result := wrSignaled;
  419. WAIT_TIMEOUT: Result := wrTimeout;
  420. WAIT_FAILED:
  421. begin
  422. Result := wrError;
  423. plocaleventrec(state)^.FLastError := GetLastError;
  424. end;
  425. else
  426. Result := wrError;
  427. end;
  428. }
  429. end;
  430. function IntRTLEventCreate: PRTLEvent;
  431. begin
  432. {$WARNING TODO!}
  433. {
  434. Result := PRTLEVENT(CreateEvent(nil, false, false, nil));
  435. }
  436. end;
  437. procedure IntRTLEventDestroy (AEvent: PRTLEvent);
  438. begin
  439. {$WARNING TODO!}
  440. {
  441. CloseHandle(THANDLE(AEvent));
  442. }
  443. end;
  444. procedure IntRTLEventSetEvent (AEvent: PRTLEvent);
  445. begin
  446. {$WARNING TODO!}
  447. {
  448. PulseEvent(THANDLE(AEvent));
  449. }
  450. end;
  451. CONST INFINITE=-1;
  452. procedure IntRTLEventStartWait (AEvent: PRTLEvent);
  453. begin
  454. {$WARNING TODO!}
  455. // nothing to do, win32 events stay signalled after being set
  456. end;
  457. procedure IntRTLEventWaitFor (AEvent: PRTLEvent);
  458. begin
  459. {$WARNING TODO!}
  460. {
  461. WaitForSingleObject(THANDLE(AEvent), INFINITE);
  462. }
  463. end;
  464. var
  465. OS2ThreadManager: TThreadManager;
  466. procedure SetOS2ThreadManager;
  467. begin
  468. with OS2ThreadManager do
  469. begin
  470. InitManager :=Nil;
  471. DoneManager :=Nil;
  472. BeginThread :=@SysBeginThread;
  473. EndThread :=@SysEndThread;
  474. SuspendThread :=@SysSuspendThread;
  475. ResumeThread :=@SysResumeThread;
  476. KillThread :=@SysKillThread;
  477. ThreadSwitch :=@SysThreadSwitch;
  478. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  479. ThreadSetPriority :=@SysThreadSetPriority;
  480. ThreadGetPriority :=@SysThreadGetPriority;
  481. GetCurrentThreadId :=@SysGetCurrentThreadId;
  482. InitCriticalSection :=@SysInitCriticalSection;
  483. DoneCriticalSection :=@SysDoneCriticalSection;
  484. EnterCriticalSection :=@SysEnterCriticalSection;
  485. LeaveCriticalSection :=@SysLeaveCriticalSection;
  486. {$ifdef HASTHREADVAR}
  487. InitThreadVar :=@SysInitThreadVar;
  488. RelocateThreadVar :=@SysRelocateThreadVar;
  489. AllocateThreadVars :=@SysAllocateThreadVars;
  490. ReleaseThreadVars :=@SysReleaseThreadVars;
  491. {$endif HASTHREADVAR}
  492. BasicEventCreate :=@IntBasicEventCreate;
  493. BasicEventDestroy :=@IntBasicEventDestroy;
  494. BasicEventResetEvent :=@IntBasicEventResetEvent;
  495. BasicEventSetEvent :=@IntBasicEventSetEvent;
  496. BasiceventWaitFor :=@IntBasiceventWaitFor;
  497. RTLEventCreate :=@IntRTLEventCreate;
  498. RTLEventDestroy :=@IntRTLEventDestroy;
  499. RTLEventSetEvent :=@IntRTLEventSetEvent;
  500. RTLEventStartWait :=@IntRTLEventStartWait;
  501. RTLEventWaitFor :=@IntRTLEventWaitFor;
  502. end;
  503. SetThreadManager (OS2ThreadManager);
  504. InitHeapMutexes;
  505. end;
  506. finalization
  507. DosFreeThreadLocalMemory (DataIndex);
  508. end;
  509. initialization
  510. SetOS2ThreadManager;
  511. end.
  512. {
  513. $Log$
  514. Revision 1.3 2005-01-27 22:14:54 hajny
  515. * first part of compilation fixes
  516. Revision 1.2 2003/10/13 21:17:31 hajny
  517. * longint to cardinal corrections
  518. Revision 1.1 2002/11/17 22:31:46 hajny
  519. + first (incomplete) version of systhrds
  520. Revision 1.1 2002/10/14 19:39:18 peter
  521. * threads unit added for thread support
  522. }