thread.inc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team.
  5. Multithreading implementation for Win32
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$ifdef MT}
  13. const
  14. threadvarblocksize : dword = 0;
  15. type
  16. tthreadinfo = record
  17. f : tthreadfunc;
  18. p : pointer;
  19. end;
  20. pthreadinfo = ^tthreadinfo;
  21. var
  22. dataindex : dword;
  23. { import the necessary stuff from windows }
  24. function TlsAlloc : DWord;
  25. external 'kernel32' name 'TlsAlloc';
  26. function TlsGetValue(dwTlsIndex : DWord) : pointer;
  27. external 'kernel32' name 'TlsGetValue';
  28. function TlsSetValue(dwTlsIndex : DWord;lpTlsValue : pointer) : LongBool;
  29. external 'kernel32' name 'TlsSetValue';
  30. function TlsFree(dwTlsIndex : DWord) : LongBool;
  31. external 'kernel32' name 'TlsFree';
  32. function CreateThread(lpThreadAttributes : pointer;
  33. dwStackSize : DWord; lpStartAddress : pointer;lpParameter : pointer;
  34. dwCreationFlags : DWord;var lpThreadId : DWord) : THandle;
  35. external 'kernel32' name 'CreateThread';
  36. procedure ExitThread(dwExitCode : DWord);
  37. external 'kernel32' name 'ExitThread';
  38. function GlobalAlloc(uFlags:UINT; dwBytes:DWORD):Pointer;
  39. external 'kernel32' name 'GlobalAlloc';
  40. function GlobalFree(hMem : Pointer):Pointer; external 'kernel32' name 'GlobalFree';
  41. const
  42. { GlobalAlloc, GlobalFlags }
  43. GMEM_FIXED = 0;
  44. GMEM_ZEROINIT = 64;
  45. procedure init_threadvar(var offset : dword;size : dword);[public,alias: 'FPC_INIT_THREADVAR'];
  46. begin
  47. offset:=threadvarblocksize;
  48. inc(threadvarblocksize,size);
  49. end;
  50. type
  51. ltvInitEntry = packed record
  52. varaddr : pdword;
  53. size : longint;
  54. end;
  55. pltvInitEntry = ^ltvInitEntry;
  56. procedure init_unit_threadvars (tableEntry : pltvInitEntry);
  57. begin
  58. while tableEntry^.varaddr <> nil do
  59. begin
  60. init_threadvar (tableEntry^.varaddr^, tableEntry^.size);
  61. inc (pchar (tableEntry), sizeof (tableEntry^));
  62. end;
  63. end;
  64. type TltvInitTablesTable =
  65. record
  66. count : dword;
  67. tables: array [1..32767] of pltvInitEntry;
  68. end;
  69. var
  70. ThreadvarTablesTable : TltvInitTablesTable; external name 'FPC_LOCALTHREADVARTABLES';
  71. procedure init_all_unit_threadvars; [public,alias: 'FPC_INITIALIZELOCALTHREADVARS'];
  72. var i : integer;
  73. begin
  74. {$ifdef DEBUG_MT}
  75. WriteLn ('init_all_unit_threadvars (%d) units',ThreadvarTablesTable.count);
  76. {$endif}
  77. for i := 1 to ThreadvarTablesTable.count do
  78. init_unit_threadvars (ThreadvarTablesTable.tables[i]);
  79. end;
  80. function relocate_threadvar(offset : dword) : pointer;[public,alias: 'FPC_RELOCATE_THREADVAR'];
  81. begin
  82. asm
  83. pushal
  84. end;
  85. relocate_threadvar:=TlsGetValue(dataindex)+offset;
  86. asm
  87. popal
  88. end;
  89. end;
  90. procedure AllocateThreadVars;
  91. var
  92. threadvars : pointer;
  93. begin
  94. { we've to allocate the memory from windows }
  95. { because the FPC heap management uses }
  96. { exceptions which use threadvars but }
  97. { these aren't allocated yet ... }
  98. { allocate room on the heap for the thread vars }
  99. threadvars:=pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,
  100. threadvarblocksize));
  101. TlsSetValue(dataindex,threadvars);
  102. end;
  103. procedure ReleaseThreadVars;
  104. var
  105. threadvars : pointer;
  106. begin
  107. { release thread vars }
  108. threadvars:=TlsGetValue(dataindex);
  109. GlobalFree(threadvars);
  110. end;
  111. procedure InitThread;
  112. begin
  113. InitFPU;
  114. { we don't need to set the data to 0 because we did this with }
  115. { the fillchar above, but it looks nicer }
  116. { ExceptAddrStack and ExceptObjectStack are threadvars }
  117. { so every thread has its own exception handling capabilities }
  118. InitExceptions;
  119. InOutRes:=0;
  120. // ErrNo:=0;
  121. end;
  122. procedure DoneThread;
  123. begin
  124. { release thread vars }
  125. ReleaseThreadVars;
  126. end;
  127. function ThreadMain(param : pointer) : dword;stdcall;
  128. var
  129. ti : tthreadinfo;
  130. begin
  131. {$ifdef DEBUG_MT}
  132. writeln('New thread started, initialising ...');
  133. {$endif DEBUG_MT}
  134. AllocateThreadVars;
  135. InitThread;
  136. ti:=pthreadinfo(param)^;
  137. dispose(pthreadinfo(param));
  138. {$ifdef DEBUG_MT}
  139. writeln('Jumping to thread function');
  140. {$endif DEBUG_MT}
  141. ThreadMain:=ti.f(ti.p);
  142. DoneThread;
  143. end;
  144. function BeginThread(sa : Pointer;stacksize : dword;
  145. ThreadFunction : tthreadfunc;p : pointer;creationFlags : dword;
  146. var ThreadId : DWord) : DWord;
  147. var
  148. ti : pthreadinfo;
  149. begin
  150. {$ifdef DEBUG_MT}
  151. writeln('Creating new thread');
  152. {$endif DEBUG_MT}
  153. IsMultithread:=true;
  154. { the only way to pass data to the newly created thread }
  155. { in a MT safe way, is to use the heap }
  156. new(ti);
  157. ti^.f:=ThreadFunction;
  158. ti^.p:=p;
  159. {$ifdef DEBUG_MT}
  160. writeln('Starting new thread');
  161. {$endif DEBUG_MT}
  162. BeginThread:=CreateThread(sa,stacksize,@ThreadMain,ti,
  163. creationflags,threadid);
  164. end;
  165. function BeginThread(ThreadFunction : tthreadfunc) : DWord;
  166. var
  167. dummy : dword;
  168. begin
  169. BeginThread:=BeginThread(nil,0,ThreadFunction,nil,0,dummy);
  170. end;
  171. function BeginThread(ThreadFunction : tthreadfunc;p : pointer) : DWord;
  172. var
  173. dummy : dword;
  174. begin
  175. BeginThread:=BeginThread(nil,0,ThreadFunction,p,0,dummy);
  176. end;
  177. function BeginThread(ThreadFunction : tthreadfunc;p : pointer;
  178. var ThreadId : DWord) : DWord;
  179. begin
  180. BeginThread:=BeginThread(nil,0,ThreadFunction,p,0,ThreadId);
  181. end;
  182. function BeginThread(ThreadFunction : tthreadfunc;p : pointer;
  183. var ThreadId : Longint) : DWord;
  184. begin
  185. BeginThread:=BeginThread(nil,0,ThreadFunction,p,0,DWord(ThreadId));
  186. end;
  187. function BeginThread(sa : Pointer;stacksize : dword;
  188. ThreadFunction : tthreadfunc;p : pointer;creationFlags : dword;
  189. var ThreadId : Longint) : DWord;
  190. begin
  191. BeginThread:=BeginThread(sa,stacksize,ThreadFunction,p,creationflags,DWord(threadid));
  192. end;
  193. procedure EndThread(ExitCode : DWord);
  194. begin
  195. DoneThread;
  196. ExitThread(ExitCode);
  197. end;
  198. procedure EndThread;
  199. begin
  200. EndThread(0);
  201. end;
  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. {$endif MT}
  213. {
  214. $Log$
  215. Revision 1.10 2002-09-07 16:01:29 peter
  216. * old logs removed and tabs fixed
  217. Revision 1.9 2002/07/28 20:43:50 florian
  218. * several fixes for linux/powerpc
  219. * several fixes to MT
  220. Revision 1.8 2002/03/31 10:03:13 armin
  221. + call to DoneThread was missing
  222. Revision 1.7 2002/03/28 16:31:35 armin
  223. + initialize threadvars defined local in units
  224. }