systhrds.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. {*****************************************************************************
  34. Generic overloaded
  35. *****************************************************************************}
  36. { Include generic overloaded routines }
  37. {$i thread.inc}
  38. {*****************************************************************************
  39. Local WINApi imports
  40. *****************************************************************************}
  41. const
  42. { GlobalAlloc, GlobalFlags }
  43. GMEM_FIXED = 0;
  44. GMEM_ZEROINIT = 64;
  45. function TlsAlloc : DWord;
  46. stdcall;external 'kernel32' name 'TlsAlloc';
  47. function TlsGetValue(dwTlsIndex : DWord) : pointer;
  48. stdcall;external 'kernel32' name 'TlsGetValue';
  49. function TlsSetValue(dwTlsIndex : DWord;lpTlsValue : pointer) : LongBool;
  50. stdcall;external 'kernel32' name 'TlsSetValue';
  51. function TlsFree(dwTlsIndex : DWord) : LongBool;
  52. stdcall;external 'kernel32' name 'TlsFree';
  53. function CreateThread(lpThreadAttributes : pointer;
  54. dwStackSize : DWord; lpStartAddress : pointer;lpParameter : pointer;
  55. dwCreationFlags : DWord;var lpThreadId : DWord) : Dword;
  56. stdcall;external 'kernel32' name 'CreateThread';
  57. procedure ExitThread(dwExitCode : DWord);
  58. stdcall;external 'kernel32' name 'ExitThread';
  59. function GlobalAlloc(uFlags:DWord; dwBytes:DWORD):Pointer;
  60. stdcall;external 'kernel32' name 'GlobalAlloc';
  61. function GlobalFree(hMem : Pointer):Pointer; stdcall;external 'kernel32' name 'GlobalFree';
  62. procedure Sleep(dwMilliseconds: DWord); stdcall;external 'kernel32' name 'Sleep';
  63. function WinSuspendThread (threadHandle : dword) : dword; stdcall;external 'kernel32' name 'SuspendThread';
  64. function WinResumeThread (threadHandle : dword) : dword; stdcall;external 'kernel32' name 'ResumeThread';
  65. function TerminateThread (threadHandle : dword; var exitCode : dword) : boolean; stdcall;external 'kernel32' name 'TerminateThread';
  66. function GetLastError : dword; stdcall;external 'kernel32' name 'GetLastError';
  67. function WaitForSingleObject (hHandle,Milliseconds: dword): dword; stdcall;external 'kernel32' name 'WaitForSingleObject';
  68. function WinThreadSetPriority (threadHandle : dword; Prio: longint): boolean; stdcall;external 'kernel32' name 'SetThreadPriority';
  69. function WinThreadGetPriority (threadHandle : dword): Integer; stdcall;external 'kernel32' name 'GetThreadPriority';
  70. function WinGetCurrentThreadId : dword; stdcall;external 'kernel32' name 'GetCurrentThread';
  71. {*****************************************************************************
  72. Threadvar support
  73. *****************************************************************************}
  74. {$ifdef HASTHREADVAR}
  75. const
  76. threadvarblocksize : dword = 0;
  77. var
  78. TLSKey : Dword;
  79. procedure SysInitThreadvar(var offset : dword;size : dword);
  80. begin
  81. offset:=threadvarblocksize;
  82. inc(threadvarblocksize,size);
  83. end;
  84. function SysRelocateThreadvar(offset : dword) : pointer;
  85. begin
  86. SysRelocateThreadvar:=TlsGetValue(tlskey)+Offset;
  87. end;
  88. procedure SysAllocateThreadVars;
  89. var
  90. dataindex : pointer;
  91. begin
  92. { we've to allocate the memory from system }
  93. { because the FPC heap management uses }
  94. { exceptions which use threadvars but }
  95. { these aren't allocated yet ... }
  96. { allocate room on the heap for the thread vars }
  97. dataindex:=pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,threadvarblocksize));
  98. TlsSetValue(tlskey,dataindex);
  99. end;
  100. procedure SysReleaseThreadVars;
  101. begin
  102. GlobalFree(TlsGetValue(tlskey));
  103. end;
  104. { Include OS independent Threadvar initialization }
  105. {$i threadvr.inc}
  106. {$endif HASTHREADVAR}
  107. {*****************************************************************************
  108. Thread starting
  109. *****************************************************************************}
  110. type
  111. pthreadinfo = ^tthreadinfo;
  112. tthreadinfo = record
  113. f : tthreadfunc;
  114. p : pointer;
  115. stklen : cardinal;
  116. end;
  117. procedure DoneThread;
  118. begin
  119. { Release Threadvars }
  120. {$ifdef HASTHREADVAR}
  121. SysReleaseThreadVars;
  122. {$endif HASTHREADVAR}
  123. end;
  124. function ThreadMain(param : pointer) : pointer;cdecl;
  125. var
  126. ti : tthreadinfo;
  127. begin
  128. {$ifdef HASTHREADVAR}
  129. { Allocate local thread vars, this must be the first thing,
  130. because the exception management and io depends on threadvars }
  131. SysAllocateThreadVars;
  132. {$endif HASTHREADVAR}
  133. { Copy parameter to local data }
  134. {$ifdef DEBUG_MT}
  135. writeln('New thread started, initialising ...');
  136. {$endif DEBUG_MT}
  137. ti:=pthreadinfo(param)^;
  138. dispose(pthreadinfo(param));
  139. { Initialize thread }
  140. InitThread(ti.stklen);
  141. { Start thread function }
  142. {$ifdef DEBUG_MT}
  143. writeln('Jumping to thread function');
  144. {$endif DEBUG_MT}
  145. ThreadMain:=pointer(ti.f(ti.p));
  146. end;
  147. function SysBeginThread(sa : Pointer;stacksize : dword;
  148. ThreadFunction : tthreadfunc;p : pointer;
  149. creationFlags : dword; var ThreadId : DWord) : DWord;
  150. var
  151. ti : pthreadinfo;
  152. begin
  153. {$ifdef DEBUG_MT}
  154. writeln('Creating new thread');
  155. {$endif DEBUG_MT}
  156. { Initialize multithreading if not done }
  157. if not IsMultiThread then
  158. begin
  159. {$ifdef HASTHREADVAR}
  160. { We're still running in single thread mode, setup the TLS }
  161. TLSKey:=TlsAlloc;
  162. InitThreadVars(@SysRelocateThreadvar);
  163. {$endif HASTHREADVAR}
  164. IsMultiThread:=true;
  165. end;
  166. { the only way to pass data to the newly created thread
  167. in a MT safe way, is to use the heap }
  168. new(ti);
  169. ti^.f:=ThreadFunction;
  170. ti^.p:=p;
  171. ti^.stklen:=stacksize;
  172. { call pthread_create }
  173. {$ifdef DEBUG_MT}
  174. writeln('Starting new thread');
  175. {$endif DEBUG_MT}
  176. SysBeginThread:=CreateThread(sa,stacksize,@ThreadMain,ti,creationflags,threadid);
  177. end;
  178. procedure SysEndThread(ExitCode : DWord);
  179. begin
  180. DoneThread;
  181. ExitThread(ExitCode);
  182. end;
  183. procedure SysThreadSwitch;
  184. begin
  185. Sleep(0);
  186. end;
  187. function SysSuspendThread (threadHandle : dword) : dword;
  188. begin
  189. SysSuspendThread:=WinSuspendThread(threadHandle);
  190. end;
  191. function SysResumeThread (threadHandle : dword) : dword;
  192. begin
  193. SysResumeThread:=WinResumeThread(threadHandle);
  194. end;
  195. function SysKillThread (threadHandle : dword) : dword;
  196. var exitCode : dword;
  197. begin
  198. if not TerminateThread (threadHandle, exitCode) then
  199. SysKillThread := GetLastError
  200. else
  201. SysKillThread := 0;
  202. end;
  203. function SysWaitForThreadTerminate (threadHandle : dword; TimeoutMs : longint) : dword;
  204. begin
  205. if timeoutMs = 0 then dec (timeoutMs); // $ffffffff is INFINITE
  206. SysWaitForThreadTerminate := WaitForSingleObject(threadHandle, TimeoutMs);
  207. end;
  208. function SysThreadSetPriority (threadHandle : dword; Prio: longint): boolean; {-15..+15, 0=normal}
  209. begin
  210. SysThreadSetPriority:=WinThreadSetPriority(threadHandle,Prio);
  211. end;
  212. function SysThreadGetPriority (threadHandle : dword): Integer;
  213. begin
  214. SysThreadGetPriority:=WinThreadGetPriority(threadHandle);
  215. end;
  216. function SysGetCurrentThreadId : dword;
  217. begin
  218. SysGetCurrentThreadId:=WinGetCurrentThreadId;
  219. end;
  220. {*****************************************************************************
  221. Delphi/Win32 compatibility
  222. *****************************************************************************}
  223. procedure WinInitCriticalSection(var cs : TRTLCriticalSection);
  224. stdcall;external 'kernel32' name 'InitializeCriticalSection';
  225. procedure WinDoneCriticalSection(var cs : TRTLCriticalSection);
  226. stdcall;external 'kernel32' name 'DeleteCriticalSection';
  227. procedure WinEnterCriticalSection(var cs : TRTLCriticalSection);
  228. stdcall;external 'kernel32' name 'EnterCriticalSection';
  229. procedure WinLeaveCriticalSection(var cs : TRTLCriticalSection);
  230. stdcall;external 'kernel32' name 'LeaveCriticalSection';
  231. procedure SySInitCriticalSection(var cs);
  232. begin
  233. WinInitCriticalSection(PRTLCriticalSection(@cs)^);
  234. end;
  235. procedure SysDoneCriticalSection(var cs);
  236. begin
  237. WinDoneCriticalSection(PRTLCriticalSection(@cs)^);
  238. end;
  239. procedure SysEnterCriticalSection(var cs);
  240. begin
  241. WinEnterCriticalSection(PRTLCriticalSection(@cs)^);
  242. end;
  243. procedure SySLeaveCriticalSection(var cs);
  244. begin
  245. WinLeaveCriticalSection(PRTLCriticalSection(@cs)^);
  246. end;
  247. {*****************************************************************************
  248. Heap Mutex Protection
  249. *****************************************************************************}
  250. var
  251. HeapMutex : TRTLCriticalSection;
  252. procedure Win32HeapMutexInit;
  253. begin
  254. InitCriticalSection(heapmutex);
  255. end;
  256. procedure Win32HeapMutexDone;
  257. begin
  258. DoneCriticalSection(heapmutex);
  259. end;
  260. procedure Win32HeapMutexLock;
  261. begin
  262. EnterCriticalSection(heapmutex);
  263. end;
  264. procedure Win32HeapMutexUnlock;
  265. begin
  266. LeaveCriticalSection(heapmutex);
  267. end;
  268. const
  269. Win32MemoryMutexManager : TMemoryMutexManager = (
  270. MutexInit : @Win32HeapMutexInit;
  271. MutexDone : @Win32HeapMutexDone;
  272. MutexLock : @Win32HeapMutexLock;
  273. MutexUnlock : @Win32HeapMutexUnlock;
  274. );
  275. procedure InitHeapMutexes;
  276. begin
  277. SetMemoryMutexManager(Win32MemoryMutexManager);
  278. end;
  279. Var
  280. WinThreadManager : TThreadManager;
  281. Procedure SetWinThreadManager;
  282. begin
  283. With WinThreadManager do
  284. begin
  285. InitManager :=Nil;
  286. DoneManager :=Nil;
  287. BeginThread :=@SysBeginThread;
  288. EndThread :=@SysEndThread;
  289. SuspendThread :=@SysSuspendThread;
  290. ResumeThread :=@SysResumeThread;
  291. KillThread :=@SysKillThread;
  292. ThreadSwitch :=@SysThreadSwitch;
  293. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  294. ThreadSetPriority :=@SysThreadSetPriority;
  295. ThreadGetPriority :=@SysThreadGetPriority;
  296. GetCurrentThreadId :=@SysGetCurrentThreadId;
  297. InitCriticalSection :=@SysInitCriticalSection;
  298. DoneCriticalSection :=@SysDoneCriticalSection;
  299. EnterCriticalSection :=@SysEnterCriticalSection;
  300. LeaveCriticalSection :=@SysLeaveCriticalSection;
  301. {$ifdef HASTHREADVAR}
  302. InitThreadVar :=@SysInitThreadVar;
  303. RelocateThreadVar :=@SysRelocateThreadVar;
  304. AllocateThreadVars :=@SysAllocateThreadVars;
  305. ReleaseThreadVars :=@SysReleaseThreadVars;
  306. {$endif HASTHREADVAR}
  307. end;
  308. SetThreadManager(WinThreadManager);
  309. InitHeapMutexes;
  310. end;
  311. initialization
  312. SetWinThreadManager;
  313. end.
  314. {
  315. $Log$
  316. Revision 1.9 2003-11-29 17:34:53 michael
  317. + Removed dummy variable from SetCthreadManager
  318. Revision 1.8 2003/11/27 10:28:41 michael
  319. + Patch from peter to fix make cycle
  320. Revision 1.7 2003/11/26 20:10:59 michael
  321. + New threadmanager implementation
  322. Revision 1.6 2003/10/01 21:00:09 peter
  323. * GetCurrentThreadHandle renamed to GetCurrentThreadId
  324. Revision 1.5 2003/09/17 15:06:36 peter
  325. * stdcall patch
  326. Revision 1.4 2003/03/27 17:14:27 armin
  327. * more platform independent thread routines, needs to be implemented for unix
  328. Revision 1.3 2003/03/24 16:12:01 jonas
  329. * BeginThread() now returns the thread handle instead of the threadid
  330. (needed because you have to free the handle after your thread is
  331. finished, and the threadid is already returned via a var-parameter)
  332. Revision 1.2 2002/10/31 13:45:44 carl
  333. * threadvar.inc -> threadvr.inc
  334. Revision 1.1 2002/10/16 06:27:30 michael
  335. + Renamed thread unit to systhrds
  336. Revision 1.1 2002/10/14 19:39:18 peter
  337. * threads unit added for thread support
  338. }