systhrd.inc 14 KB

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