2
0

systhrd.inc 15 KB

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