cthreads.pp 14 KB

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