cthreads.pp 14 KB

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