systhrds.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  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. Win32 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. {$mode objfpc}
  14. unit systhrds;
  15. interface
  16. {$S-}
  17. type
  18. { the fields of this record are os dependent }
  19. { and they shouldn't be used in a program }
  20. { only the type TCriticalSection is important }
  21. PRTLCriticalSection = ^TRTLCriticalSection;
  22. TRTLCriticalSection = packed record
  23. DebugInfo : pointer;
  24. LockCount : longint;
  25. RecursionCount : longint;
  26. OwningThread : DWord;
  27. LockSemaphore : DWord;
  28. Reserved : DWord;
  29. end;
  30. { Include generic thread interface }
  31. {$i threadh.inc}
  32. implementation
  33. function SysGetCurrentThreadId : dword;forward;
  34. {*****************************************************************************
  35. Generic overloaded
  36. *****************************************************************************}
  37. { Include generic overloaded routines }
  38. {$i thread.inc}
  39. {*****************************************************************************
  40. Local WINApi imports
  41. *****************************************************************************}
  42. const
  43. { GlobalAlloc, GlobalFlags }
  44. GMEM_FIXED = 0;
  45. GMEM_ZEROINIT = 64;
  46. function TlsAlloc : DWord;
  47. stdcall;external 'kernel32' name 'TlsAlloc';
  48. function TlsGetValue(dwTlsIndex : DWord) : pointer;
  49. stdcall;external 'kernel32' name 'TlsGetValue';
  50. function TlsSetValue(dwTlsIndex : DWord;lpTlsValue : pointer) : LongBool;
  51. stdcall;external 'kernel32' name 'TlsSetValue';
  52. function TlsFree(dwTlsIndex : DWord) : LongBool;
  53. stdcall;external 'kernel32' name 'TlsFree';
  54. function CreateThread(lpThreadAttributes : pointer;
  55. dwStackSize : DWord; lpStartAddress : pointer;lpParameter : pointer;
  56. dwCreationFlags : DWord;var lpThreadId : DWord) : Dword;
  57. stdcall;external 'kernel32' name 'CreateThread';
  58. procedure ExitThread(dwExitCode : DWord);
  59. stdcall;external 'kernel32' name 'ExitThread';
  60. function GlobalAlloc(uFlags:DWord; dwBytes:DWORD):Pointer;
  61. stdcall;external 'kernel32' name 'GlobalAlloc';
  62. function GlobalFree(hMem : Pointer):Pointer; stdcall;external 'kernel32' name 'GlobalFree';
  63. procedure Sleep(dwMilliseconds: DWord); stdcall;external 'kernel32' name 'Sleep';
  64. function WinSuspendThread (threadHandle : dword) : dword; stdcall;external 'kernel32' name 'SuspendThread';
  65. function WinResumeThread (threadHandle : dword) : dword; stdcall;external 'kernel32' name 'ResumeThread';
  66. function TerminateThread (threadHandle : dword; var exitCode : dword) : boolean; stdcall;external 'kernel32' name 'TerminateThread';
  67. function GetLastError : dword; stdcall;external 'kernel32' name 'GetLastError';
  68. function WaitForSingleObject (hHandle,Milliseconds: dword): dword; stdcall;external 'kernel32' name 'WaitForSingleObject';
  69. function WinThreadSetPriority (threadHandle : dword; Prio: longint): boolean; stdcall;external 'kernel32' name 'SetThreadPriority';
  70. function WinThreadGetPriority (threadHandle : dword): Integer; stdcall;external 'kernel32' name 'GetThreadPriority';
  71. function WinGetCurrentThreadId : dword; stdcall;external 'kernel32' name 'GetCurrentThread';
  72. function CreateEvent(lpEventAttributes:pointer;bManualReset:longbool;bInitialState:longbool;lpName:pchar):CARDINAL; external 'kernel32' name 'CreateEventA';
  73. function CloseHandle(hObject:CARDINAL):LONGBOOL; external 'kernel32' name 'CloseHandle';
  74. function ResetEvent(hEvent:CARDINAL):LONGBOOL; external 'kernel32' name 'ResetEvent';
  75. function SetEvent(hEvent:CARDINAL):LONGBOOL; external 'kernel32' name 'SetEvent';
  76. CONST
  77. WAIT_OBJECT_0 = 0;
  78. WAIT_ABANDONED_0 = $80;
  79. WAIT_TIMEOUT = $102;
  80. WAIT_IO_COMPLETION = $c0;
  81. WAIT_ABANDONED = $80;
  82. WAIT_FAILED = $ffffffff;
  83. {*****************************************************************************
  84. Threadvar support
  85. *****************************************************************************}
  86. {$ifdef HASTHREADVAR}
  87. const
  88. threadvarblocksize : dword = 0;
  89. var
  90. TLSKey : Dword;
  91. procedure SysInitThreadvar(var offset : dword;size : dword);
  92. begin
  93. offset:=threadvarblocksize;
  94. inc(threadvarblocksize,size);
  95. end;
  96. function SysRelocateThreadvar(offset : dword) : pointer;
  97. begin
  98. SysRelocateThreadvar:=TlsGetValue(tlskey)+Offset;
  99. end;
  100. procedure SysAllocateThreadVars;
  101. var
  102. dataindex : pointer;
  103. begin
  104. { we've to allocate the memory from system }
  105. { because the FPC heap management uses }
  106. { exceptions which use threadvars but }
  107. { these aren't allocated yet ... }
  108. { allocate room on the heap for the thread vars }
  109. dataindex:=pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,threadvarblocksize));
  110. TlsSetValue(tlskey,dataindex);
  111. end;
  112. procedure SysReleaseThreadVars;
  113. begin
  114. GlobalFree(TlsGetValue(tlskey));
  115. end;
  116. { Include OS independent Threadvar initialization }
  117. {$i threadvr.inc}
  118. {$endif HASTHREADVAR}
  119. {*****************************************************************************
  120. Thread starting
  121. *****************************************************************************}
  122. type
  123. pthreadinfo = ^tthreadinfo;
  124. tthreadinfo = record
  125. f : tthreadfunc;
  126. p : pointer;
  127. stklen : cardinal;
  128. end;
  129. procedure DoneThread;
  130. begin
  131. { Release Threadvars }
  132. {$ifdef HASTHREADVAR}
  133. SysReleaseThreadVars;
  134. {$endif HASTHREADVAR}
  135. end;
  136. function ThreadMain(param : pointer) : pointer;cdecl;
  137. var
  138. ti : tthreadinfo;
  139. begin
  140. {$ifdef HASTHREADVAR}
  141. { Allocate local thread vars, this must be the first thing,
  142. because the exception management and io depends on threadvars }
  143. SysAllocateThreadVars;
  144. {$endif HASTHREADVAR}
  145. { Copy parameter to local data }
  146. {$ifdef DEBUG_MT}
  147. writeln('New thread started, initialising ...');
  148. {$endif DEBUG_MT}
  149. ti:=pthreadinfo(param)^;
  150. dispose(pthreadinfo(param));
  151. { Initialize thread }
  152. InitThread(ti.stklen);
  153. { Start thread function }
  154. {$ifdef DEBUG_MT}
  155. writeln('Jumping to thread function');
  156. {$endif DEBUG_MT}
  157. ThreadMain:=pointer(ti.f(ti.p));
  158. end;
  159. function SysBeginThread(sa : Pointer;stacksize : dword;
  160. ThreadFunction : tthreadfunc;p : pointer;
  161. creationFlags : dword; var ThreadId : DWord) : DWord;
  162. var
  163. ti : pthreadinfo;
  164. begin
  165. {$ifdef DEBUG_MT}
  166. writeln('Creating new thread');
  167. {$endif DEBUG_MT}
  168. { Initialize multithreading if not done }
  169. if not IsMultiThread then
  170. begin
  171. {$ifdef HASTHREADVAR}
  172. { We're still running in single thread mode, setup the TLS }
  173. TLSKey:=TlsAlloc;
  174. InitThreadVars(@SysRelocateThreadvar);
  175. {$endif HASTHREADVAR}
  176. IsMultiThread:=true;
  177. end;
  178. { the only way to pass data to the newly created thread
  179. in a MT safe way, is to use the heap }
  180. new(ti);
  181. ti^.f:=ThreadFunction;
  182. ti^.p:=p;
  183. ti^.stklen:=stacksize;
  184. { call pthread_create }
  185. {$ifdef DEBUG_MT}
  186. writeln('Starting new thread');
  187. {$endif DEBUG_MT}
  188. SysBeginThread:=CreateThread(sa,stacksize,@ThreadMain,ti,creationflags,threadid);
  189. end;
  190. procedure SysEndThread(ExitCode : DWord);
  191. begin
  192. DoneThread;
  193. ExitThread(ExitCode);
  194. end;
  195. procedure SysThreadSwitch;
  196. begin
  197. Sleep(0);
  198. end;
  199. function SysSuspendThread (threadHandle : dword) : dword;
  200. begin
  201. SysSuspendThread:=WinSuspendThread(threadHandle);
  202. end;
  203. function SysResumeThread (threadHandle : dword) : dword;
  204. begin
  205. SysResumeThread:=WinResumeThread(threadHandle);
  206. end;
  207. function SysKillThread (threadHandle : dword) : dword;
  208. var exitCode : dword;
  209. begin
  210. if not TerminateThread (threadHandle, exitCode) then
  211. SysKillThread := GetLastError
  212. else
  213. SysKillThread := 0;
  214. end;
  215. function SysWaitForThreadTerminate (threadHandle : dword; TimeoutMs : longint) : dword;
  216. begin
  217. if timeoutMs = 0 then dec (timeoutMs); // $ffffffff is INFINITE
  218. SysWaitForThreadTerminate := WaitForSingleObject(threadHandle, TimeoutMs);
  219. end;
  220. function SysThreadSetPriority (threadHandle : dword; Prio: longint): boolean; {-15..+15, 0=normal}
  221. begin
  222. SysThreadSetPriority:=WinThreadSetPriority(threadHandle,Prio);
  223. end;
  224. function SysThreadGetPriority (threadHandle : dword): Integer;
  225. begin
  226. SysThreadGetPriority:=WinThreadGetPriority(threadHandle);
  227. end;
  228. function SysGetCurrentThreadId : dword;
  229. begin
  230. SysGetCurrentThreadId:=WinGetCurrentThreadId;
  231. end;
  232. {*****************************************************************************
  233. Delphi/Win32 compatibility
  234. *****************************************************************************}
  235. procedure WinInitCriticalSection(var cs : TRTLCriticalSection);
  236. stdcall;external 'kernel32' name 'InitializeCriticalSection';
  237. procedure WinDoneCriticalSection(var cs : TRTLCriticalSection);
  238. stdcall;external 'kernel32' name 'DeleteCriticalSection';
  239. procedure WinEnterCriticalSection(var cs : TRTLCriticalSection);
  240. stdcall;external 'kernel32' name 'EnterCriticalSection';
  241. procedure WinLeaveCriticalSection(var cs : TRTLCriticalSection);
  242. stdcall;external 'kernel32' name 'LeaveCriticalSection';
  243. procedure SySInitCriticalSection(var cs);
  244. begin
  245. WinInitCriticalSection(PRTLCriticalSection(@cs)^);
  246. end;
  247. procedure SysDoneCriticalSection(var cs);
  248. begin
  249. WinDoneCriticalSection(PRTLCriticalSection(@cs)^);
  250. end;
  251. procedure SysEnterCriticalSection(var cs);
  252. begin
  253. WinEnterCriticalSection(PRTLCriticalSection(@cs)^);
  254. end;
  255. procedure SySLeaveCriticalSection(var cs);
  256. begin
  257. WinLeaveCriticalSection(PRTLCriticalSection(@cs)^);
  258. end;
  259. {*****************************************************************************
  260. Heap Mutex Protection
  261. *****************************************************************************}
  262. var
  263. HeapMutex : TRTLCriticalSection;
  264. procedure Win32HeapMutexInit;
  265. begin
  266. InitCriticalSection(heapmutex);
  267. end;
  268. procedure Win32HeapMutexDone;
  269. begin
  270. DoneCriticalSection(heapmutex);
  271. end;
  272. procedure Win32HeapMutexLock;
  273. begin
  274. EnterCriticalSection(heapmutex);
  275. end;
  276. procedure Win32HeapMutexUnlock;
  277. begin
  278. LeaveCriticalSection(heapmutex);
  279. end;
  280. const
  281. Win32MemoryMutexManager : TMemoryMutexManager = (
  282. MutexInit : @Win32HeapMutexInit;
  283. MutexDone : @Win32HeapMutexDone;
  284. MutexLock : @Win32HeapMutexLock;
  285. MutexUnlock : @Win32HeapMutexUnlock;
  286. );
  287. procedure InitHeapMutexes;
  288. begin
  289. SetMemoryMutexManager(Win32MemoryMutexManager);
  290. end;
  291. Const
  292. wrSignaled = 0;
  293. wrTimeout = 1;
  294. wrAbandoned= 2;
  295. wrError = 3;
  296. type Tbasiceventstate=record
  297. fhandle : THandle;
  298. flasterror : longint;
  299. end;
  300. plocaleventrec= ^tbasiceventstate;
  301. function intBasicEventCreate(EventAttributes : Pointer;
  302. AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  303. begin
  304. new(plocaleventrec(result));
  305. plocaleventrec(result)^.FHandle := CreateEvent(EventAttributes, AManualReset, InitialState,PChar(Name));
  306. end;
  307. procedure intbasiceventdestroy(state:peventstate);
  308. begin
  309. closehandle(plocaleventrec(state)^.fhandle);
  310. dispose(plocaleventrec(state));
  311. end;
  312. procedure intbasiceventResetEvent(state:peventstate);
  313. begin
  314. ResetEvent(plocaleventrec(state)^.FHandle)
  315. end;
  316. procedure intbasiceventSetEvent(state:peventstate);
  317. begin
  318. SetEvent(plocaleventrec(state)^.FHandle);
  319. end;
  320. function intbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  321. begin
  322. case WaitForSingleObject(plocaleventrec(state)^.fHandle, Timeout) of
  323. WAIT_ABANDONED: Result := wrAbandoned;
  324. WAIT_OBJECT_0: Result := wrSignaled;
  325. WAIT_TIMEOUT: Result := wrTimeout;
  326. WAIT_FAILED:
  327. begin
  328. Result := wrError;
  329. plocaleventrec(state)^.FLastError := GetLastError;
  330. end;
  331. else
  332. Result := wrError;
  333. end;
  334. end;
  335. Var
  336. WinThreadManager : TThreadManager;
  337. Procedure SetWinThreadManager;
  338. begin
  339. With WinThreadManager do
  340. begin
  341. InitManager :=Nil;
  342. DoneManager :=Nil;
  343. BeginThread :=@SysBeginThread;
  344. EndThread :=@SysEndThread;
  345. SuspendThread :=@SysSuspendThread;
  346. ResumeThread :=@SysResumeThread;
  347. KillThread :=@SysKillThread;
  348. ThreadSwitch :=@SysThreadSwitch;
  349. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  350. ThreadSetPriority :=@SysThreadSetPriority;
  351. ThreadGetPriority :=@SysThreadGetPriority;
  352. GetCurrentThreadId :=@SysGetCurrentThreadId;
  353. InitCriticalSection :=@SysInitCriticalSection;
  354. DoneCriticalSection :=@SysDoneCriticalSection;
  355. EnterCriticalSection :=@SysEnterCriticalSection;
  356. LeaveCriticalSection :=@SysLeaveCriticalSection;
  357. {$ifdef HASTHREADVAR}
  358. InitThreadVar :=@SysInitThreadVar;
  359. RelocateThreadVar :=@SysRelocateThreadVar;
  360. AllocateThreadVars :=@SysAllocateThreadVars;
  361. ReleaseThreadVars :=@SysReleaseThreadVars;
  362. {$endif HASTHREADVAR}
  363. BasicEventCreate :=@intBasicEventCreate;
  364. BasicEventDestroy :=@intBasicEventDestroy;
  365. BasicEventResetEvent :=@intBasicEventResetEvent;
  366. BasicEventSetEvent :=@intBasicEventSetEvent;
  367. BasiceventWaitFor :=@intBasiceventWaitFor;
  368. end;
  369. SetThreadManager(WinThreadManager);
  370. InitHeapMutexes;
  371. end;
  372. initialization
  373. SetWinThreadManager;
  374. end.
  375. {
  376. $Log$
  377. Revision 1.11 2004-05-23 15:30:13 marco
  378. * first try
  379. Revision 1.10 2004/01/21 14:15:42 florian
  380. * fixed win32 compilation
  381. Revision 1.9 2003/11/29 17:34:53 michael
  382. + Removed dummy variable from SetCthreadManager
  383. Revision 1.8 2003/11/27 10:28:41 michael
  384. + Patch from peter to fix make cycle
  385. Revision 1.7 2003/11/26 20:10:59 michael
  386. + New threadmanager implementation
  387. Revision 1.6 2003/10/01 21:00:09 peter
  388. * GetCurrentThreadHandle renamed to GetCurrentThreadId
  389. Revision 1.5 2003/09/17 15:06:36 peter
  390. * stdcall patch
  391. Revision 1.4 2003/03/27 17:14:27 armin
  392. * more platform independent thread routines, needs to be implemented for unix
  393. Revision 1.3 2003/03/24 16:12:01 jonas
  394. * BeginThread() now returns the thread handle instead of the threadid
  395. (needed because you have to free the handle after your thread is
  396. finished, and the threadid is already returned via a var-parameter)
  397. Revision 1.2 2002/10/31 13:45:44 carl
  398. * threadvar.inc -> threadvr.inc
  399. Revision 1.1 2002/10/16 06:27:30 michael
  400. + Renamed thread unit to systhrds
  401. Revision 1.1 2002/10/14 19:39:18 peter
  402. * threads unit added for thread support
  403. }