systhrds.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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. external 'kernel32' name 'TlsAlloc';
  46. function TlsGetValue(dwTlsIndex : DWord) : pointer;
  47. external 'kernel32' name 'TlsGetValue';
  48. function TlsSetValue(dwTlsIndex : DWord;lpTlsValue : pointer) : LongBool;
  49. external 'kernel32' name 'TlsSetValue';
  50. function TlsFree(dwTlsIndex : DWord) : LongBool;
  51. external 'kernel32' name 'TlsFree';
  52. function CreateThread(lpThreadAttributes : pointer;
  53. dwStackSize : DWord; lpStartAddress : pointer;lpParameter : pointer;
  54. dwCreationFlags : DWord;var lpThreadId : DWord) : Dword;
  55. external 'kernel32' name 'CreateThread';
  56. procedure ExitThread(dwExitCode : DWord);
  57. external 'kernel32' name 'ExitThread';
  58. function GlobalAlloc(uFlags:DWord; dwBytes:DWORD):Pointer;
  59. external 'kernel32' name 'GlobalAlloc';
  60. function GlobalFree(hMem : Pointer):Pointer; external 'kernel32' name 'GlobalFree';
  61. procedure Sleep(dwMilliseconds: DWord); external 'kernel32' name 'Sleep';
  62. function SuspendThread (threadHandle : dword) : dword; external 'kernel32' name 'SuspendThread';
  63. function ResumeThread (threadHandle : dword) : dword; external 'kernel32' name 'ResumeThread';
  64. function TerminateThread (threadHandle : dword; var exitCode : dword) : boolean; external 'kernel32' name 'TerminateThread';
  65. function GetLastError : dword; external 'kernel32' name 'GetLastError';
  66. function WaitForSingleObject (hHandle,Milliseconds: dword): dword; external 'kernel32' name 'WaitForSingleObject';
  67. function ThreadSetPriority (threadHandle : dword; Prio: longint): boolean; external 'kernel32' name 'SetThreadPriority';
  68. function ThreadGetPriority (threadHandle : dword): Integer; external 'kernel32' name 'GetThreadPriority';
  69. function GetCurrentThreadHandle : dword; 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 KillThread (threadHandle : dword) : dword;
  187. var exitCode : dword;
  188. begin
  189. if not TerminateThread (threadHandle, exitCode) then
  190. KillThread := GetLastError
  191. else
  192. KillThread := 0;
  193. end;
  194. function WaitForThreadTerminate (threadHandle : dword; TimeoutMs : longint) : dword;
  195. begin
  196. if timeoutMs = 0 then dec (timeoutMs); // $ffffffff is INFINITE
  197. WaitForThreadTerminate := WaitForSingleObject(threadHandle, TimeoutMs);
  198. end;
  199. {*****************************************************************************
  200. Delphi/Win32 compatibility
  201. *****************************************************************************}
  202. { we implement these procedures for win32 by importing them }
  203. { directly from windows }
  204. procedure InitCriticalSection(var cs : TRTLCriticalSection);
  205. external 'kernel32' name 'InitializeCriticalSection';
  206. procedure DoneCriticalSection(var cs : TRTLCriticalSection);
  207. external 'kernel32' name 'DeleteCriticalSection';
  208. procedure EnterCriticalSection(var cs : TRTLCriticalSection);
  209. external 'kernel32' name 'EnterCriticalSection';
  210. procedure LeaveCriticalSection(var cs : TRTLCriticalSection);
  211. external 'kernel32' name 'LeaveCriticalSection';
  212. {*****************************************************************************
  213. Heap Mutex Protection
  214. *****************************************************************************}
  215. var
  216. HeapMutex : TRTLCriticalSection;
  217. procedure Win32HeapMutexInit;
  218. begin
  219. InitCriticalSection(heapmutex);
  220. end;
  221. procedure Win32HeapMutexDone;
  222. begin
  223. DoneCriticalSection(heapmutex);
  224. end;
  225. procedure Win32HeapMutexLock;
  226. begin
  227. EnterCriticalSection(heapmutex);
  228. end;
  229. procedure Win32HeapMutexUnlock;
  230. begin
  231. LeaveCriticalSection(heapmutex);
  232. end;
  233. const
  234. Win32MemoryMutexManager : TMemoryMutexManager = (
  235. MutexInit : @Win32HeapMutexInit;
  236. MutexDone : @Win32HeapMutexDone;
  237. MutexLock : @Win32HeapMutexLock;
  238. MutexUnlock : @Win32HeapMutexUnlock;
  239. );
  240. procedure InitHeapMutexes;
  241. begin
  242. SetMemoryMutexManager(Win32MemoryMutexManager);
  243. end;
  244. initialization
  245. InitHeapMutexes;
  246. end.
  247. {
  248. $Log$
  249. Revision 1.4 2003-03-27 17:14:27 armin
  250. * more platform independent thread routines, needs to be implemented for unix
  251. Revision 1.3 2003/03/24 16:12:01 jonas
  252. * BeginThread() now returns the thread handle instead of the threadid
  253. (needed because you have to free the handle after your thread is
  254. finished, and the threadid is already returned via a var-parameter)
  255. Revision 1.2 2002/10/31 13:45:44 carl
  256. * threadvar.inc -> threadvr.inc
  257. Revision 1.1 2002/10/16 06:27:30 michael
  258. + Renamed thread unit to systhrds
  259. Revision 1.1 2002/10/14 19:39:18 peter
  260. * threads unit added for thread support
  261. }