systhrds.pp 11 KB

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