systhrd.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2002-5 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 = -1;
  23. dtSuspended = 1;
  24. dtStack_Commited = 2;
  25. { import the necessary stuff from the OS }
  26. function DosAllocThreadLocalMemory (Count: cardinal; var P: pointer): cardinal;
  27. cdecl; external 'DOSCALLS' index 454;
  28. function DosFreeThreadLocalMemory (P: pointer): cardinal; cdecl;
  29. external 'DOSCALLS' index 455;
  30. function DosCreateThread (var TID: cardinal; Address: pointer;
  31. (* TThreadFunc *)
  32. aParam: pointer; Flags: cardinal; StackSize: cardinal): cardinal; cdecl;
  33. external 'DOSCALLS' index 311;
  34. function DosCreateMutExSem (Name: PChar; var Handle: longint; Attr: cardinal;
  35. State: boolean): cardinal; cdecl; external 'DOSCALLS' index 331;
  36. function DosCloseMutExSem (Handle: longint): cardinal; cdecl;
  37. external 'DOSCALLS' index 333;
  38. function DosQueryMutExSem (Handle: longint; var PID, TID, Count: cardinal):
  39. cardinal; cdecl; external 'DOSCALLS' index 336;
  40. function DosRequestMutExSem (Handle:longint; Timeout: cardinal): cardinal; cdecl;
  41. external 'DOSCALLS' index 334;
  42. function DosReleaseMutExSem (Handle: longint): cardinal; cdecl;
  43. external 'DOSCALLS' index 335;
  44. {
  45. function DosEnterCritSec:cardinal; cdecl; external 'DOSCALLS' index 232;
  46. function DosExitCritSec:cardinal; cdecl; external 'DOSCALLS' index 233;
  47. }
  48. procedure DosSleep (MSec: cardinal); cdecl; external 'DOSCALLS' index 229;
  49. {*****************************************************************************
  50. Threadvar support
  51. *****************************************************************************}
  52. const
  53. ThreadVarBlockSize: dword = 0;
  54. var
  55. (* Pointer to an allocated dword space within the local thread *)
  56. (* memory area. Pointer to the real memory block allocated for *)
  57. (* thread vars in this block is then stored in this dword. *)
  58. DataIndex: PPointer;
  59. procedure SysInitThreadvar (var Offset: dword; Size: dword);
  60. begin
  61. Offset := ThreadVarBlockSize;
  62. Inc (ThreadVarBlockSize, Size);
  63. end;
  64. function SysRelocateThreadVar (Offset: dword): pointer;
  65. begin
  66. SysRelocateThreadVar := DataIndex^ + Offset;
  67. end;
  68. procedure SysAllocateThreadVars;
  69. begin
  70. { we've to allocate the memory from the OS }
  71. { because the FPC heap management uses }
  72. { exceptions which use threadvars but }
  73. { these aren't allocated yet ... }
  74. { allocate room on the heap for the thread vars }
  75. if DosAllocMem (DataIndex^, ThreadVarBlockSize, pag_Read or pag_Write
  76. or pag_Commit) <> 0 then HandleError (8);
  77. end;
  78. procedure SysReleaseThreadVars;
  79. begin
  80. { release thread vars }
  81. DosFreeMem (DataIndex^);
  82. DosFreeThreadLocalMemory (DataIndex);
  83. end;
  84. (* procedure InitThreadVars;
  85. begin
  86. { allocate one ThreadVar entry from the OS, we use this entry }
  87. { for a pointer to our threadvars }
  88. if DosAllocThreadLocalMemory (1, DataIndex) <> 0 then HandleError (8);
  89. { initialize threadvars }
  90. init_all_unit_threadvars;
  91. { allocate mem for main thread threadvars }
  92. SysAllocateThreadVars;
  93. { copy main thread threadvars }
  94. copy_all_unit_threadvars;
  95. { install threadvar handler }
  96. fpc_threadvar_relocate_proc := @SysRelocateThreadvar;
  97. end;
  98. *)
  99. {*****************************************************************************
  100. Thread starting
  101. *****************************************************************************}
  102. type
  103. pthreadinfo = ^tthreadinfo;
  104. tthreadinfo = record
  105. f : tthreadfunc;
  106. p : pointer;
  107. stklen : cardinal;
  108. end;
  109. (* procedure InitThread(stklen:cardinal);
  110. begin
  111. SysResetFPU;
  112. { ExceptAddrStack and ExceptObjectStack are threadvars }
  113. { so every thread has its on exception handling capabilities }
  114. SysInitExceptions;
  115. { Open all stdio fds again }
  116. SysInitStdio;
  117. InOutRes:=0;
  118. // ErrNo:=0;
  119. { Stack checking }
  120. StackLength:=stklen;
  121. StackBottom:=Sptr - StackLength;
  122. end;
  123. *)
  124. procedure DoneThread;
  125. begin
  126. { Release Threadvars }
  127. SysReleaseThreadVars;
  128. end;
  129. function ThreadMain(param : pointer) : pointer;cdecl;
  130. var
  131. ti : tthreadinfo;
  132. begin
  133. { Allocate local thread vars, this must be the first thing,
  134. because the exception management and io depends on threadvars }
  135. SysAllocateThreadVars;
  136. { Copy parameter to local data }
  137. {$ifdef DEBUG_MT}
  138. writeln('New thread started, initialising ...');
  139. {$endif DEBUG_MT}
  140. ti:=pthreadinfo(param)^;
  141. dispose(pthreadinfo(param));
  142. { Initialize thread }
  143. InitThread(ti.stklen);
  144. { Start thread function }
  145. {$ifdef DEBUG_MT}
  146. writeln('Jumping to thread function');
  147. {$endif DEBUG_MT}
  148. ThreadMain:=pointer(ti.f(ti.p));
  149. end;
  150. function SysBeginThread(sa : Pointer;stacksize : SizeUInt;
  151. ThreadFunction : tthreadfunc;p : pointer;
  152. creationFlags : dword; var ThreadId : TThreadID) : DWord;
  153. var
  154. TI: PThreadInfo;
  155. begin
  156. {$ifdef DEBUG_MT}
  157. writeln('Creating new thread');
  158. {$endif DEBUG_MT}
  159. { Initialize multithreading if not done }
  160. if not IsMultiThread then
  161. begin
  162. if DosAllocThreadLocalMemory (1, DataIndex) <> 0
  163. then RunError (8);
  164. InitThreadVars(@SysRelocateThreadVar);
  165. IsMultiThread:=true;
  166. end;
  167. { the only way to pass data to the newly created thread
  168. in a MT safe way, is to use the heap }
  169. New (TI);
  170. TI^.F := ThreadFunction;
  171. TI^.P := P;
  172. TI^.StkLen := StackSize;
  173. { call pthread_create }
  174. {$ifdef DEBUG_MT}
  175. writeln('Starting new thread');
  176. {$endif DEBUG_MT}
  177. if DosCreateThread (DWord (ThreadID), @ThreadMain, SA,
  178. CreationFlags, StackSize) = 0 then
  179. SysBeginThread := ThreadID else SysBeginThread := 0;
  180. end;
  181. procedure SysEndThread (ExitCode : DWord);
  182. begin
  183. DoneThread;
  184. DosExit (1, ExitCode);
  185. end;
  186. procedure SysThreadSwitch;
  187. begin
  188. DosSleep (0);
  189. end;
  190. function SysSuspendThread (ThreadHandle: dword): dword;
  191. begin
  192. {$WARNING TODO!}
  193. { SysSuspendThread := WinSuspendThread(threadHandle);
  194. }
  195. end;
  196. function SysResumeThread (ThreadHandle: dword): dword;
  197. begin
  198. {$WARNING TODO!}
  199. { SysResumeThread := WinResumeThread(threadHandle);
  200. }
  201. end;
  202. function SysKillThread (ThreadHandle: dword): dword;
  203. var
  204. ExitCode: dword;
  205. begin
  206. {$WARNING TODO!}
  207. {
  208. if not TerminateThread (ThreadHandle, ExitCode) then
  209. SysKillThread := GetLastError
  210. else
  211. SysKillThread := 0;
  212. }
  213. end;
  214. function SysWaitForThreadTerminate (ThreadHandle: dword;
  215. TimeoutMs: longint): dword;
  216. begin
  217. {$WARNING TODO!}
  218. {
  219. if TimeoutMs = 0 then dec (timeoutMs); // $ffffffff is INFINITE
  220. SysWaitForThreadTerminate := WaitForSingleObject(threadHandle, TimeoutMs);
  221. }
  222. end;
  223. function SysThreadSetPriority (ThreadHandle: dword;
  224. Prio: longint): boolean;
  225. {-15..+15, 0=normal}
  226. begin
  227. {$WARNING TODO!}
  228. {
  229. SysThreadSetPriority:=WinThreadSetPriority(threadHandle,Prio);
  230. }
  231. end;
  232. function SysThreadGetPriority (ThreadHandle: dword): longint;
  233. begin
  234. {$WARNING TODO!}
  235. {
  236. SysThreadGetPriority:=WinThreadGetPriority(threadHandle);
  237. }
  238. end;
  239. function SysGetCurrentThreadID: dword;
  240. begin
  241. {$WARNING TODO!}
  242. {
  243. SysGetCurrentThreadId:=WinGetCurrentThreadId;
  244. }
  245. end;
  246. {*****************************************************************************
  247. Delphi/Win32 compatibility
  248. *****************************************************************************}
  249. { DosEnter/ExitCritSec have quite a few limitations, so let's try to avoid
  250. them. I'm not sure whether mutex semaphores are SMP-safe, though... :-( }
  251. procedure SysInitCriticalSection(var CS);
  252. begin
  253. {$WARNING TODO!}
  254. end;
  255. procedure SysDoneCriticalSection (var CS);
  256. begin
  257. {$WARNING TODO!}
  258. end;
  259. procedure SysEnterCriticalSection (var CS);
  260. begin
  261. {$WARNING TODO!}
  262. end;
  263. procedure SysLeaveCriticalSection (var CS);
  264. begin
  265. {$WARNING TODO!}
  266. end;
  267. {*****************************************************************************
  268. Heap Mutex Protection
  269. *****************************************************************************}
  270. var
  271. HeapMutex: TRTLCriticalSection;
  272. procedure OS2HeapMutexInit;
  273. begin
  274. InitCriticalSection (HeapMutex);
  275. end;
  276. procedure OS2HeapMutexDone;
  277. begin
  278. DoneCriticalSection (HeapMutex);
  279. end;
  280. procedure OS2HeapMutexLock;
  281. begin
  282. EnterCriticalSection (HeapMutex);
  283. end;
  284. procedure OS2HeapMutexUnlock;
  285. begin
  286. LeaveCriticalSection (HeapMutex);
  287. end;
  288. const
  289. OS2MemoryMutexManager : TMemoryMutexManager = (
  290. MutexInit : @OS2HeapMutexInit;
  291. MutexDone : @OS2HeapMutexDone;
  292. MutexLock : @OS2HeapMutexLock;
  293. MutexUnlock : @OS2HeapMutexUnlock;
  294. );
  295. procedure InitHeapMutexes;
  296. begin
  297. SetMemoryMutexManager (OS2MemoryMutexManager);
  298. end;
  299. type
  300. TBasicEventState = record
  301. FHandle: THandle;
  302. FLastError: longint;
  303. end;
  304. PLocalEventRec = ^TBasicEventState;
  305. function IntBasicEventCreate (EventAttributes: Pointer;
  306. AManualReset, InitialState: Boolean; const Name: ansistring): PEventState;
  307. begin
  308. New (PLocalEventRec (Result));
  309. {$WARNING TODO!}
  310. {
  311. PLocalEventrec (Result)^.FHandle :=
  312. CreateEvent (EventAttributes, AManualReset, InitialState,PChar(Name));
  313. }
  314. end;
  315. procedure IntBasicEventDestroy (State: PEventState);
  316. begin
  317. {$WARNING TODO!}
  318. {
  319. closehandle(plocaleventrec(state)^.fhandle);
  320. }
  321. Dispose (PLocalEventRec (State));
  322. end;
  323. procedure IntBasicEventResetEvent (State: PEventState);
  324. begin
  325. {$WARNING TODO!}
  326. {
  327. ResetEvent(plocaleventrec(state)^.FHandle)
  328. }
  329. end;
  330. procedure IntBasicEventSetEvent (State: PEventState);
  331. begin
  332. {$WARNING TODO!}
  333. {
  334. SetEvent(plocaleventrec(state)^.FHandle);
  335. }
  336. end;
  337. function IntBasicEventWaitFor (Timeout: Cardinal; State: PEventState): longint;
  338. begin
  339. {$WARNING TODO!}
  340. {
  341. case WaitForSingleObject(plocaleventrec(state)^.fHandle, Timeout) of
  342. WAIT_ABANDONED: Result := wrAbandoned;
  343. WAIT_OBJECT_0: Result := wrSignaled;
  344. WAIT_TIMEOUT: Result := wrTimeout;
  345. WAIT_FAILED:
  346. begin
  347. Result := wrError;
  348. plocaleventrec(state)^.FLastError := GetLastError;
  349. end;
  350. else
  351. Result := wrError;
  352. end;
  353. }
  354. end;
  355. function IntRTLEventCreate: PRTLEvent;
  356. begin
  357. {$WARNING TODO!}
  358. {
  359. Result := PRTLEVENT(CreateEvent(nil, false, false, nil));
  360. }
  361. end;
  362. procedure IntRTLEventDestroy (AEvent: PRTLEvent);
  363. begin
  364. {$WARNING TODO!}
  365. {
  366. CloseHandle(THANDLE(AEvent));
  367. }
  368. end;
  369. procedure IntRTLEventSetEvent (AEvent: PRTLEvent);
  370. begin
  371. {$WARNING TODO!}
  372. {
  373. SetEvent(THANDLE(AEvent));
  374. }
  375. end;
  376. CONST INFINITE=-1;
  377. procedure IntRTLEventWaitFor (AEvent: PRTLEvent);
  378. begin
  379. {$WARNING TODO!}
  380. {
  381. WaitForSingleObject(THANDLE(AEvent), INFINITE);
  382. }
  383. end;
  384. var
  385. OS2ThreadManager: TThreadManager;
  386. procedure InitSystemThreads;
  387. begin
  388. with OS2ThreadManager do
  389. begin
  390. InitManager :=Nil;
  391. DoneManager :=Nil;
  392. BeginThread :=@SysBeginThread;
  393. EndThread :=@SysEndThread;
  394. SuspendThread :=@SysSuspendThread;
  395. ResumeThread :=@SysResumeThread;
  396. KillThread :=@SysKillThread;
  397. ThreadSwitch :=@SysThreadSwitch;
  398. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  399. ThreadSetPriority :=@SysThreadSetPriority;
  400. ThreadGetPriority :=@SysThreadGetPriority;
  401. GetCurrentThreadId :=@SysGetCurrentThreadId;
  402. InitCriticalSection :=@SysInitCriticalSection;
  403. DoneCriticalSection :=@SysDoneCriticalSection;
  404. EnterCriticalSection :=@SysEnterCriticalSection;
  405. LeaveCriticalSection :=@SysLeaveCriticalSection;
  406. InitThreadVar :=@SysInitThreadVar;
  407. RelocateThreadVar :=@SysRelocateThreadVar;
  408. AllocateThreadVars :=@SysAllocateThreadVars;
  409. ReleaseThreadVars :=@SysReleaseThreadVars;
  410. BasicEventCreate :=@IntBasicEventCreate;
  411. BasicEventDestroy :=@IntBasicEventDestroy;
  412. BasicEventResetEvent :=@IntBasicEventResetEvent;
  413. BasicEventSetEvent :=@IntBasicEventSetEvent;
  414. BasiceventWaitFor :=@IntBasiceventWaitFor;
  415. RTLEventCreate :=@IntRTLEventCreate;
  416. RTLEventDestroy :=@IntRTLEventDestroy;
  417. RTLEventSetEvent :=@IntRTLEventSetEvent;
  418. RTLEventWaitFor :=@IntRTLEventWaitFor;
  419. end;
  420. SetThreadManager (OS2ThreadManager);
  421. InitHeapMutexes;
  422. end;