systhrds.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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. Linux (pthreads) 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. {$ifndef BSD}
  17. {$linklib c}
  18. {$linklib pthread}
  19. {$else}
  20. // Link reentrant libc with pthreads
  21. {$linklib c_r}
  22. {$endif}
  23. type
  24. PRTLCriticalSection = ^TRTLCriticalSection;
  25. TRTLCriticalSection = record
  26. m_spinlock : longint;
  27. m_count : longint;
  28. m_owner : pointer {pthread_t};
  29. m_kind : longint;
  30. m_waiting : record
  31. head,tail : pointer;
  32. end; {_pthread_queue}
  33. end;
  34. { Include generic thread interface }
  35. {$i threadh.inc}
  36. implementation
  37. Uses BaseUnix,unix;
  38. {*****************************************************************************
  39. Generic overloaded
  40. *****************************************************************************}
  41. { Include generic overloaded routines }
  42. {$i thread.inc}
  43. { Include OS specific parts.
  44. {$i pthread.inc}
  45. {*****************************************************************************
  46. System dependent memory allocation
  47. *****************************************************************************}
  48. {$ifndef BSD}
  49. Const
  50. { Constants for MMAP }
  51. MAP_PRIVATE =2;
  52. MAP_ANONYMOUS =$20;
  53. {$else}
  54. {$ifdef FreeBSD}
  55. CONST
  56. { Constants for MMAP. These are still private for *BSD }
  57. MAP_PRIVATE =2;
  58. MAP_ANONYMOUS =$1000;
  59. {$ELSE}
  60. {$ENTER ME}
  61. {$ENDIF}
  62. {$ENDIF}
  63. {*****************************************************************************
  64. Threadvar support
  65. *****************************************************************************}
  66. {$ifdef HASTHREADVAR}
  67. const
  68. threadvarblocksize : dword = 0;
  69. var
  70. TLSKey : pthread_key_t;
  71. procedure SysInitThreadvar(var offset : dword;size : dword);
  72. begin
  73. offset:=threadvarblocksize;
  74. inc(threadvarblocksize,size);
  75. end;
  76. function SysRelocateThreadvar(offset : dword) : pointer;
  77. begin
  78. SysRelocateThreadvar:=pthread_getspecific(tlskey)+Offset;
  79. end;
  80. procedure SysAllocateThreadVars;
  81. var
  82. dataindex : pointer;
  83. begin
  84. { we've to allocate the memory from system }
  85. { because the FPC heap management uses }
  86. { exceptions which use threadvars but }
  87. { these aren't allocated yet ... }
  88. { allocate room on the heap for the thread vars }
  89. DataIndex:=Pointer(Fpmmap(0,threadvarblocksize,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0));
  90. FillChar(DataIndex^,threadvarblocksize,0);
  91. pthread_setspecific(tlskey,dataindex);
  92. end;
  93. procedure SysReleaseThreadVars;
  94. begin
  95. {$ifdef ver1_0}
  96. Fpmunmap(longint(pthread_getspecific(tlskey)),threadvarblocksize);
  97. {$else}
  98. Fpmunmap(pointer(pthread_getspecific(tlskey)),threadvarblocksize);
  99. {$endif}
  100. end;
  101. { Include OS independent Threadvar initialization }
  102. {$i threadvr.inc}
  103. {$endif HASTHREADVAR}
  104. {*****************************************************************************
  105. Thread starting
  106. *****************************************************************************}
  107. type
  108. pthreadinfo = ^tthreadinfo;
  109. tthreadinfo = record
  110. f : tthreadfunc;
  111. p : pointer;
  112. stklen : cardinal;
  113. end;
  114. procedure DoneThread;
  115. begin
  116. { Release Threadvars }
  117. {$ifdef HASTHREADVAR}
  118. SysReleaseThreadVars;
  119. {$endif HASTHREADVAR}
  120. end;
  121. function ThreadMain(param : pointer) : pointer;cdecl;
  122. var
  123. ti : tthreadinfo;
  124. {$ifdef DEBUG_MT}
  125. // in here, don't use write/writeln before having called
  126. // InitThread! I wonder if anyone ever debugged these routines,
  127. // because they will have crashed if DEBUG_MT was enabled!
  128. // this took me the good part of an hour to figure out
  129. // why it was crashing all the time!
  130. // this is kind of a workaround, we simply write(2) to fd 0
  131. s: string[100]; // not an ansistring
  132. {$endif DEBUG_MT}
  133. begin
  134. {$ifdef DEBUG_MT}
  135. s := 'New thread started, initing threadvars'#10;
  136. fpwrite(0,s[1],length(s));
  137. {$endif DEBUG_MT}
  138. {$ifdef HASTHREADVAR}
  139. { Allocate local thread vars, this must be the first thing,
  140. because the exception management and io depends on threadvars }
  141. SysAllocateThreadVars;
  142. {$endif HASTHREADVAR}
  143. { Copy parameter to local data }
  144. {$ifdef DEBUG_MT}
  145. s := 'New thread started, initialising ...'#10;
  146. fpwrite(0,s[1],length(s));
  147. {$endif DEBUG_MT}
  148. ti:=pthreadinfo(param)^;
  149. dispose(pthreadinfo(param));
  150. { Initialize thread }
  151. InitThread(ti.stklen);
  152. { Start thread function }
  153. {$ifdef DEBUG_MT}
  154. writeln('Jumping to thread function');
  155. {$endif DEBUG_MT}
  156. ThreadMain:=pointer(ti.f(ti.p));
  157. DoneThread;
  158. pthread_detach(pointer(pthread_self));
  159. end;
  160. function BeginThread(sa : Pointer;stacksize : dword;
  161. ThreadFunction : tthreadfunc;p : pointer;
  162. creationFlags : dword; var ThreadId : DWord) : DWord;
  163. var
  164. ti : pthreadinfo;
  165. thread_attr : pthread_attr_t;
  166. begin
  167. {$ifdef DEBUG_MT}
  168. writeln('Creating new thread');
  169. {$endif DEBUG_MT}
  170. { Initialize multithreading if not done }
  171. if not IsMultiThread then
  172. begin
  173. {$ifdef HASTHREADVAR}
  174. { We're still running in single thread mode, setup the TLS }
  175. pthread_key_create(@TLSKey,nil);
  176. InitThreadVars(@SysRelocateThreadvar);
  177. {$endif HASTHREADVAR}
  178. IsMultiThread:=true;
  179. end;
  180. { the only way to pass data to the newly created thread
  181. in a MT safe way, is to use the heap }
  182. new(ti);
  183. ti^.f:=ThreadFunction;
  184. ti^.p:=p;
  185. ti^.stklen:=stacksize;
  186. { call pthread_create }
  187. {$ifdef DEBUG_MT}
  188. writeln('Starting new thread');
  189. {$endif DEBUG_MT}
  190. pthread_attr_init(@thread_attr);
  191. pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
  192. // will fail under linux -- apparently unimplemented
  193. pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
  194. // don't create detached, we need to be able to join (waitfor) on
  195. // the newly created thread!
  196. //pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
  197. if pthread_create(@threadid, @thread_attr, @ThreadMain,ti) <> 0 then begin
  198. threadid := 0;
  199. end;
  200. BeginThread:=threadid;
  201. {$ifdef DEBUG_MT}
  202. writeln('BeginThread returning ',BeginThread);
  203. {$endif DEBUG_MT}
  204. end;
  205. procedure EndThread(ExitCode : DWord);
  206. begin
  207. DoneThread;
  208. pthread_detach(pointer(pthread_self));
  209. pthread_exit(pointer(ExitCode));
  210. end;
  211. function SuspendThread (threadHandle : dword) : dword;
  212. begin
  213. {$Warning SuspendThread needs to be implemented}
  214. end;
  215. function ResumeThread (threadHandle : dword) : dword;
  216. begin
  217. {$Warning ResumeThread needs to be implemented}
  218. end;
  219. procedure ThreadSwitch; {give time to other threads}
  220. begin
  221. {extern int pthread_yield (void) __THROW;}
  222. {$Warning ThreadSwitch needs to be implemented}
  223. end;
  224. function KillThread (threadHandle : dword) : dword;
  225. begin
  226. pthread_detach(pointer(threadHandle));
  227. KillThread := pthread_cancel(Pointer(threadHandle));
  228. end;
  229. function WaitForThreadTerminate (threadHandle : dword; TimeoutMs : longint) : dword; {0=no timeout}
  230. var
  231. LResultP: Pointer;
  232. LResult: DWord;
  233. begin
  234. LResult := 0;
  235. LResultP := @LResult;
  236. pthread_join(Pointer(threadHandle), @LResultP);
  237. WaitForThreadTerminate := LResult;
  238. end;
  239. function ThreadSetPriority (threadHandle : dword; Prio: longint): boolean; {-15..+15, 0=normal}
  240. begin
  241. {$Warning ThreadSetPriority needs to be implemented}
  242. end;
  243. function ThreadGetPriority (threadHandle : dword): Integer;
  244. begin
  245. {$Warning ThreadGetPriority needs to be implemented}
  246. end;
  247. function GetCurrentThreadId : dword;
  248. begin
  249. GetCurrentThreadId:=dword(pthread_self);
  250. end;
  251. {*****************************************************************************
  252. Delphi/Win32 compatibility
  253. *****************************************************************************}
  254. procedure InitCriticalSection(var CS:TRTLCriticalSection);
  255. begin
  256. cs.m_spinlock:=0;
  257. cs.m_count:=0;
  258. cs.m_owner:=0;
  259. cs.m_kind:=1;
  260. cs.m_waiting.head:=0;
  261. cs.m_waiting.tail:=0;
  262. pthread_mutex_init(@CS,NIL);
  263. end;
  264. procedure EnterCriticalSection(var CS:TRTLCriticalSection);
  265. begin
  266. pthread_mutex_lock(@CS);
  267. end;
  268. procedure LeaveCriticalSection(var CS:TRTLCriticalSection);
  269. begin
  270. pthread_mutex_unlock(@CS);
  271. end;
  272. procedure DoneCriticalSection(var CS:TRTLCriticalSection);
  273. begin
  274. pthread_mutex_destroy(@CS);
  275. end;
  276. {*****************************************************************************
  277. Heap Mutex Protection
  278. *****************************************************************************}
  279. var
  280. HeapMutex : pthread_mutex_t;
  281. procedure PThreadHeapMutexInit;
  282. begin
  283. pthread_mutex_init(@heapmutex,nil);
  284. end;
  285. procedure PThreadHeapMutexDone;
  286. begin
  287. pthread_mutex_destroy(@heapmutex);
  288. end;
  289. procedure PThreadHeapMutexLock;
  290. begin
  291. pthread_mutex_lock(@heapmutex);
  292. end;
  293. procedure PThreadHeapMutexUnlock;
  294. begin
  295. pthread_mutex_unlock(@heapmutex);
  296. end;
  297. const
  298. PThreadMemoryMutexManager : TMemoryMutexManager = (
  299. MutexInit : @PThreadHeapMutexInit;
  300. MutexDone : @PThreadHeapMutexDone;
  301. MutexLock : @PThreadHeapMutexLock;
  302. MutexUnlock : @PThreadHeapMutexUnlock;
  303. );
  304. procedure InitHeapMutexes;
  305. begin
  306. SetMemoryMutexManager(PThreadMemoryMutexManager);
  307. end;
  308. initialization
  309. InitHeapMutexes;
  310. end.
  311. {
  312. $Log$
  313. Revision 1.18 2003-11-18 22:35:09 marco
  314. * Last patch was ok, problem was somewhere else. Moved *BSD part of pthreads to freebsd/pthreads.inc
  315. Revision 1.17 2003/11/17 10:05:51 marco
  316. * threads for FreeBSD. Not working tho
  317. Revision 1.16 2003/11/17 08:27:50 marco
  318. * pthreads based ttread from Johannes Berg
  319. Revision 1.15 2003/10/01 21:00:09 peter
  320. * GetCurrentThreadHandle renamed to GetCurrentThreadId
  321. Revision 1.14 2003/10/01 20:53:08 peter
  322. * GetCurrentThreadId implemented
  323. Revision 1.13 2003/09/20 12:38:29 marco
  324. * FCL now compiles for FreeBSD with new 1.1. Now Linux.
  325. Revision 1.12 2003/09/16 13:17:03 marco
  326. * Wat cleanup, ouwe syscalls nu via baseunix e.d.
  327. Revision 1.11 2003/09/16 13:00:02 marco
  328. * small BSD gotcha removed (typing mmap params)
  329. Revision 1.10 2003/09/15 20:08:49 marco
  330. * small fixes. FreeBSD now cycles
  331. Revision 1.9 2003/09/14 20:15:01 marco
  332. * Unix reform stage two. Remove all calls from Unix that exist in Baseunix.
  333. Revision 1.8 2003/03/27 17:14:27 armin
  334. * more platform independent thread routines, needs to be implemented for unix
  335. Revision 1.7 2003/01/05 19:11:32 marco
  336. * small changes originating from introduction of Baseunix to FreeBSD
  337. Revision 1.6 2002/11/11 21:41:06 marco
  338. * syscall.inc -> syscallo.inc
  339. Revision 1.5 2002/10/31 13:45:21 carl
  340. * threadvar.inc -> threadvr.inc
  341. Revision 1.4 2002/10/26 18:27:52 marco
  342. * First series POSIX calls commits. Including getcwd.
  343. Revision 1.3 2002/10/18 18:05:06 marco
  344. * $I pthread.inc instead of pthreads.inc
  345. Revision 1.2 2002/10/18 12:19:59 marco
  346. * Fixes to get the generic *BSD RTL compiling again + fixes for thread
  347. support. Still problems left in fexpand. (inoutres?) Therefore fixed
  348. sysposix not yet commited
  349. Revision 1.1 2002/10/16 06:22:56 michael
  350. Threads renamed from threads to systhrds
  351. Revision 1.1 2002/10/14 19:39:17 peter
  352. * threads unit added for thread support
  353. }