cthreads.pp 14 KB

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