systhrd.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2002 by Peter Vreman,
  4. member of the Free Pascal development team.
  5. Linux (pthreads) 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 WINApi imports
  14. *****************************************************************************}
  15. const
  16. { LocalAlloc flags }
  17. LMEM_FIXED = 0;
  18. LMEM_ZEROINIT = 64;
  19. {$ifndef WINCE}
  20. function TlsAlloc : DWord;
  21. stdcall;external KernelDLL name 'TlsAlloc';
  22. function TlsFree(dwTlsIndex : DWord) : LongBool;
  23. stdcall;external KernelDLL name 'TlsFree';
  24. {$endif WINCE}
  25. function TlsGetValue(dwTlsIndex : DWord) : pointer;
  26. stdcall;external KernelDLL name 'TlsGetValue';
  27. function TlsSetValue(dwTlsIndex : DWord;lpTlsValue : pointer) : LongBool;
  28. stdcall;external KernelDLL name 'TlsSetValue';
  29. function CreateThread(lpThreadAttributes : pointer;
  30. dwStackSize : SIZE_T; lpStartAddress : pointer;lpParameter : pointer;
  31. dwCreationFlags : DWord;var lpThreadId : DWord) : THandle;
  32. stdcall;external KernelDLL name 'CreateThread';
  33. procedure ExitThread(dwExitCode : DWord);
  34. stdcall;external KernelDLL name 'ExitThread';
  35. function LocalAlloc(uFlags:DWord; dwBytes:DWORD):Pointer;
  36. stdcall;external KernelDLL name 'LocalAlloc';
  37. function LocalFree(hMem : Pointer):Pointer; stdcall;external KernelDLL name 'LocalFree';
  38. procedure Sleep(dwMilliseconds: DWord); stdcall;external KernelDLL name 'Sleep';
  39. function WinSuspendThread (threadHandle : THandle) : dword; stdcall;external KernelDLL name 'SuspendThread';
  40. function WinResumeThread (threadHandle : THandle) : dword; stdcall;external KernelDLL name 'ResumeThread';
  41. function TerminateThread (threadHandle : THandle; var exitCode : dword) : boolean; stdcall;external KernelDLL name 'TerminateThread';
  42. function WaitForSingleObject (hHandle : THandle;Milliseconds: dword): dword; stdcall;external KernelDLL name 'WaitForSingleObject';
  43. function WinThreadSetPriority (threadHandle : THandle; Prio: longint): boolean; stdcall;external KernelDLL name 'SetThreadPriority';
  44. function WinThreadGetPriority (threadHandle : THandle): LongInt; stdcall;external KernelDLL name 'GetThreadPriority';
  45. {$ifndef WINCE}
  46. function CreateEvent(lpEventAttributes:pointer;bManualReset:longbool;bInitialState:longbool;lpName:pchar): THandle; stdcall; external KernelDLL name 'CreateEventA';
  47. function ResetEvent(hEvent:THandle):LONGBOOL; stdcall; external KernelDLL name 'ResetEvent';
  48. function SetEvent(hEvent:THandle):LONGBOOL; stdcall; external KernelDLL name 'SetEvent';
  49. {$endif WINCE}
  50. CONST
  51. WAIT_OBJECT_0 = 0;
  52. WAIT_ABANDONED_0 = $80;
  53. WAIT_TIMEOUT = $102;
  54. WAIT_IO_COMPLETION = $c0;
  55. WAIT_ABANDONED = $80;
  56. WAIT_FAILED = $ffffffff;
  57. {*****************************************************************************
  58. Threadvar support
  59. *****************************************************************************}
  60. const
  61. threadvarblocksize : dword = 0;
  62. var
  63. TLSKey : Dword;
  64. procedure SysInitThreadvar(var offset : dword;size : dword);
  65. begin
  66. offset:=threadvarblocksize;
  67. {$ifdef CPUARM}
  68. // Data must be allocated at 4 bytes boundary for ARM
  69. size:=(size + 3) and not dword(3);
  70. {$endif CPUARM}
  71. inc(threadvarblocksize,size);
  72. end;
  73. function SysRelocateThreadvar(offset : dword) : pointer;
  74. begin
  75. SysRelocateThreadvar:=TlsGetValue(tlskey)+Offset;
  76. end;
  77. procedure SysAllocateThreadVars;
  78. var
  79. dataindex : pointer;
  80. begin
  81. { we've to allocate the memory from system }
  82. { because the FPC heap management uses }
  83. { exceptions which use threadvars but }
  84. { these aren't allocated yet ... }
  85. { allocate room on the heap for the thread vars }
  86. dataindex:=pointer(LocalAlloc(LMEM_FIXED or LMEM_ZEROINIT,threadvarblocksize));
  87. TlsSetValue(tlskey,dataindex);
  88. end;
  89. procedure SysReleaseThreadVars;
  90. begin
  91. LocalFree(TlsGetValue(tlskey));
  92. end;
  93. {*****************************************************************************
  94. Thread starting
  95. *****************************************************************************}
  96. type
  97. pthreadinfo = ^tthreadinfo;
  98. tthreadinfo = record
  99. f : tthreadfunc;
  100. p : pointer;
  101. stklen : cardinal;
  102. end;
  103. procedure DoneThread;
  104. begin
  105. { Release Threadvars }
  106. SysReleaseThreadVars;
  107. end;
  108. function ThreadMain(param : pointer) : Longint; stdcall;
  109. var
  110. ti : tthreadinfo;
  111. begin
  112. { Allocate local thread vars, this must be the first thing,
  113. because the exception management and io depends on threadvars }
  114. SysAllocateThreadVars;
  115. { Copy parameter to local data }
  116. {$ifdef DEBUG_MT}
  117. writeln('New thread started, initialising ...');
  118. {$endif DEBUG_MT}
  119. ti:=pthreadinfo(param)^;
  120. dispose(pthreadinfo(param));
  121. { Initialize thread }
  122. InitThread(ti.stklen);
  123. { Start thread function }
  124. {$ifdef DEBUG_MT}
  125. writeln('Jumping to thread function');
  126. {$endif DEBUG_MT}
  127. ThreadMain:=ti.f(ti.p);
  128. end;
  129. function SysBeginThread(sa : Pointer;stacksize : ptruint;
  130. ThreadFunction : tthreadfunc;p : pointer;
  131. creationFlags : dword;var ThreadId : TThreadID) : TThreadID;
  132. var
  133. ti : pthreadinfo;
  134. _threadid : DWord;
  135. begin
  136. {$ifdef DEBUG_MT}
  137. writeln('Creating new thread');
  138. {$endif DEBUG_MT}
  139. { Initialize multithreading if not done }
  140. if not IsMultiThread then
  141. begin
  142. { We're still running in single thread mode, setup the TLS }
  143. TLSKey:=TlsAlloc;
  144. InitThreadVars(@SysRelocateThreadvar);
  145. IsMultiThread:=true;
  146. end;
  147. { the only way to pass data to the newly created thread
  148. in a MT safe way, is to use the heap }
  149. new(ti);
  150. ti^.f:=ThreadFunction;
  151. ti^.p:=p;
  152. ti^.stklen:=stacksize;
  153. { call pthread_create }
  154. {$ifdef DEBUG_MT}
  155. writeln('Starting new thread');
  156. {$endif DEBUG_MT}
  157. _threadid:=ThreadID;
  158. SysBeginThread:=CreateThread(sa,stacksize,@ThreadMain,ti,creationflags,_threadid);
  159. ThreadID:=_threadid;
  160. end;
  161. procedure SysEndThread(ExitCode : DWord);
  162. begin
  163. DoneThread;
  164. ExitThread(ExitCode);
  165. end;
  166. procedure SysThreadSwitch;
  167. begin
  168. Sleep(0);
  169. end;
  170. function SysSuspendThread (threadHandle : TThreadID) : dword;
  171. begin
  172. SysSuspendThread:=WinSuspendThread(threadHandle);
  173. end;
  174. function SysResumeThread (threadHandle : TThreadID) : dword;
  175. begin
  176. SysResumeThread:=WinResumeThread(threadHandle);
  177. end;
  178. function SysKillThread (threadHandle : TThreadID) : dword;
  179. var exitCode : dword;
  180. begin
  181. if not TerminateThread (threadHandle, exitCode) then
  182. SysKillThread := GetLastError
  183. else
  184. SysKillThread := 0;
  185. end;
  186. function SysWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;
  187. begin
  188. if timeoutMs = 0 then dec (timeoutMs); // $ffffffff is INFINITE
  189. SysWaitForThreadTerminate := WaitForSingleObject(threadHandle, TimeoutMs);
  190. end;
  191. function SysThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
  192. begin
  193. SysThreadSetPriority:=WinThreadSetPriority(threadHandle,Prio);
  194. end;
  195. function SysThreadGetPriority (threadHandle : TThreadID): longint;
  196. begin
  197. SysThreadGetPriority:=WinThreadGetPriority(threadHandle);
  198. end;
  199. function SysGetCurrentThreadId : TThreadID;
  200. begin
  201. SysGetCurrentThreadId:=Win32GetCurrentThreadId;
  202. end;
  203. {*****************************************************************************
  204. Delphi/Win32 compatibility
  205. *****************************************************************************}
  206. procedure WinInitCriticalSection(var cs : TRTLCriticalSection);
  207. stdcall;external KernelDLL name 'InitializeCriticalSection';
  208. procedure WinDoneCriticalSection(var cs : TRTLCriticalSection);
  209. stdcall;external KernelDLL name 'DeleteCriticalSection';
  210. procedure WinEnterCriticalSection(var cs : TRTLCriticalSection);
  211. stdcall;external KernelDLL name 'EnterCriticalSection';
  212. procedure WinLeaveCriticalSection(var cs : TRTLCriticalSection);
  213. stdcall;external KernelDLL name 'LeaveCriticalSection';
  214. procedure SySInitCriticalSection(var cs);
  215. begin
  216. WinInitCriticalSection(PRTLCriticalSection(@cs)^);
  217. end;
  218. procedure SysDoneCriticalSection(var cs);
  219. begin
  220. WinDoneCriticalSection(PRTLCriticalSection(@cs)^);
  221. end;
  222. procedure SysEnterCriticalSection(var cs);
  223. begin
  224. WinEnterCriticalSection(PRTLCriticalSection(@cs)^);
  225. end;
  226. procedure SySLeaveCriticalSection(var cs);
  227. begin
  228. WinLeaveCriticalSection(PRTLCriticalSection(@cs)^);
  229. end;
  230. {*****************************************************************************
  231. Heap Mutex Protection
  232. *****************************************************************************}
  233. var
  234. HeapMutex : TRTLCriticalSection;
  235. procedure Win32HeapMutexInit;
  236. begin
  237. InitCriticalSection(heapmutex);
  238. end;
  239. procedure Win32HeapMutexDone;
  240. begin
  241. DoneCriticalSection(heapmutex);
  242. end;
  243. procedure Win32HeapMutexLock;
  244. begin
  245. EnterCriticalSection(heapmutex);
  246. end;
  247. procedure Win32HeapMutexUnlock;
  248. begin
  249. LeaveCriticalSection(heapmutex);
  250. end;
  251. const
  252. Win32MemoryMutexManager : TMemoryMutexManager = (
  253. MutexInit : @Win32HeapMutexInit;
  254. MutexDone : @Win32HeapMutexDone;
  255. MutexLock : @Win32HeapMutexLock;
  256. MutexUnlock : @Win32HeapMutexUnlock;
  257. );
  258. procedure InitHeapMutexes;
  259. begin
  260. SetMemoryMutexManager(Win32MemoryMutexManager);
  261. end;
  262. Const
  263. wrSignaled = 0;
  264. wrTimeout = 1;
  265. wrAbandoned= 2;
  266. wrError = 3;
  267. type Tbasiceventstate=record
  268. fhandle : THandle;
  269. flasterror : longint;
  270. end;
  271. plocaleventrec= ^tbasiceventstate;
  272. function intBasicEventCreate(EventAttributes : Pointer;
  273. AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  274. begin
  275. new(plocaleventrec(result));
  276. plocaleventrec(result)^.FHandle := CreateEvent(EventAttributes, AManualReset, InitialState,PChar(Name));
  277. end;
  278. procedure intbasiceventdestroy(state:peventstate);
  279. begin
  280. closehandle(plocaleventrec(state)^.fhandle);
  281. dispose(plocaleventrec(state));
  282. end;
  283. procedure intbasiceventResetEvent(state:peventstate);
  284. begin
  285. ResetEvent(plocaleventrec(state)^.FHandle)
  286. end;
  287. procedure intbasiceventSetEvent(state:peventstate);
  288. begin
  289. SetEvent(plocaleventrec(state)^.FHandle);
  290. end;
  291. function intbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  292. begin
  293. case WaitForSingleObject(plocaleventrec(state)^.fHandle, Timeout) of
  294. WAIT_ABANDONED: Result := wrAbandoned;
  295. WAIT_OBJECT_0: Result := wrSignaled;
  296. WAIT_TIMEOUT: Result := wrTimeout;
  297. WAIT_FAILED:
  298. begin
  299. Result := wrError;
  300. plocaleventrec(state)^.FLastError := GetLastError;
  301. end;
  302. else
  303. Result := wrError;
  304. end;
  305. end;
  306. function intRTLEventCreate: PRTLEvent;
  307. begin
  308. Result := PRTLEVENT(CreateEvent(nil, false, false, nil));
  309. end;
  310. procedure intRTLEventDestroy(AEvent: PRTLEvent);
  311. begin
  312. CloseHandle(THANDLE(AEvent));
  313. end;
  314. procedure intRTLEventSetEvent(AEvent: PRTLEvent);
  315. begin
  316. SetEvent(THANDLE(AEvent));
  317. end;
  318. procedure intRTLEventResetEvent(AEvent: PRTLEvent);
  319. begin
  320. ResetEvent(THANDLE(AEvent));
  321. end;
  322. procedure intRTLEventStartWait(AEvent: PRTLEvent);
  323. begin
  324. { this is to get at least some common behaviour on unix and win32:
  325. events before startwait are lost on unix, so reset the event on
  326. win32 as well }
  327. ResetEvent(THANDLE(AEvent));
  328. end;
  329. procedure intRTLEventWaitFor(AEvent: PRTLEvent);
  330. const
  331. INFINITE=-1;
  332. begin
  333. WaitForSingleObject(THANDLE(AEvent), INFINITE);
  334. end;
  335. procedure intRTLEventWaitForTimeout(AEvent: PRTLEvent;timeout : longint);
  336. begin
  337. WaitForSingleObject(THANDLE(AEvent), timeout);
  338. end;
  339. Var
  340. WinThreadManager : TThreadManager;
  341. Procedure InitSystemThreads;
  342. begin
  343. With WinThreadManager do
  344. begin
  345. InitManager :=Nil;
  346. DoneManager :=Nil;
  347. BeginThread :=@SysBeginThread;
  348. EndThread :=@SysEndThread;
  349. SuspendThread :=@SysSuspendThread;
  350. ResumeThread :=@SysResumeThread;
  351. KillThread :=@SysKillThread;
  352. ThreadSwitch :=@SysThreadSwitch;
  353. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  354. ThreadSetPriority :=@SysThreadSetPriority;
  355. ThreadGetPriority :=@SysThreadGetPriority;
  356. GetCurrentThreadId :=@SysGetCurrentThreadId;
  357. InitCriticalSection :=@SysInitCriticalSection;
  358. DoneCriticalSection :=@SysDoneCriticalSection;
  359. EnterCriticalSection :=@SysEnterCriticalSection;
  360. LeaveCriticalSection :=@SysLeaveCriticalSection;
  361. InitThreadVar :=@SysInitThreadVar;
  362. RelocateThreadVar :=@SysRelocateThreadVar;
  363. AllocateThreadVars :=@SysAllocateThreadVars;
  364. ReleaseThreadVars :=@SysReleaseThreadVars;
  365. BasicEventCreate :=@intBasicEventCreate;
  366. BasicEventDestroy :=@intBasicEventDestroy;
  367. BasicEventResetEvent :=@intBasicEventResetEvent;
  368. BasicEventSetEvent :=@intBasicEventSetEvent;
  369. BasiceventWaitFor :=@intBasiceventWaitFor;
  370. RTLEventCreate :=@intRTLEventCreate;
  371. RTLEventDestroy :=@intRTLEventDestroy;
  372. RTLEventSetEvent :=@intRTLEventSetEvent;
  373. RTLEventResetEvent :=@intRTLEventResetEvent;
  374. RTLEventStartWait :=@intRTLEventStartWait;
  375. RTLEventWaitFor :=@intRTLEventWaitFor;
  376. RTLEventWaitForTimeout :=@intRTLEventWaitForTimeout;
  377. end;
  378. SetThreadManager(WinThreadManager);
  379. InitHeapMutexes;
  380. ThreadID := GetCurrentThreadID;
  381. end;