cthreads.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  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 : DWord) : 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 ',BeginThread);
  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. Writeln('Entering InitThreads.');
  294. {$ifndef dynpthreads}
  295. Result:=True;
  296. {$else}
  297. Result:=LoadPthreads;
  298. {$endif}
  299. ThreadID := SizeUInt (pthread_self);
  300. Writeln('InitThreads : ',Result);
  301. end;
  302. Function CDoneThreads : Boolean;
  303. begin
  304. {$ifndef dynpthreads}
  305. Result:=True;
  306. {$else}
  307. Result:=UnloadPthreads;
  308. {$endif}
  309. end;
  310. Var
  311. CThreadManager : TThreadManager;
  312. Procedure SetCThreadManager;
  313. begin
  314. With CThreadManager do
  315. begin
  316. InitManager :=@CInitThreads;
  317. DoneManager :=@CDoneThreads;
  318. BeginThread :=@CBeginThread;
  319. EndThread :=@CEndThread;
  320. SuspendThread :=@CSuspendThread;
  321. ResumeThread :=@CResumeThread;
  322. KillThread :=@CKillThread;
  323. ThreadSwitch :=@CThreadSwitch;
  324. WaitForThreadTerminate :=@CWaitForThreadTerminate;
  325. ThreadSetPriority :=@CThreadSetPriority;
  326. ThreadGetPriority :=@CThreadGetPriority;
  327. GetCurrentThreadId :=@CGetCurrentThreadId;
  328. InitCriticalSection :=@CInitCriticalSection;
  329. DoneCriticalSection :=@CDoneCriticalSection;
  330. EnterCriticalSection :=@CEnterCriticalSection;
  331. LeaveCriticalSection :=@CLeaveCriticalSection;
  332. {$ifdef hasthreadvar}
  333. InitThreadVar :=@CInitThreadVar;
  334. RelocateThreadVar :=@CRelocateThreadVar;
  335. AllocateThreadVars :=@CAllocateThreadVars;
  336. ReleaseThreadVars :=@CReleaseThreadVars;
  337. {$endif}
  338. end;
  339. SetThreadManager(CThreadManager);
  340. InitHeapMutexes;
  341. end;
  342. initialization
  343. SetCThreadManager;
  344. end.
  345. {
  346. $Log$
  347. Revision 1.8 2004-02-15 16:33:32 marco
  348. * linklibs fixed for new pthread mechanism on FreeBSD
  349. Revision 1.7 2004/01/20 23:13:53 hajny
  350. * ExecuteProcess fixes, ProcessID and ThreadID added
  351. Revision 1.6 2004/01/07 17:40:56 jonas
  352. * Darwin does not have a lib_r, libc itself is already reentrant
  353. Revision 1.5 2003/12/16 09:43:04 daniel
  354. * Use of 0 instead of nil fixed
  355. Revision 1.4 2003/11/29 17:34:14 michael
  356. + Removed dummy variable from SetCthreadManager
  357. Revision 1.3 2003/11/27 20:24:53 michael
  358. + Compiles on BSD too now
  359. Revision 1.2 2003/11/27 20:16:59 michael
  360. + Make works with 1.0.10 too
  361. Revision 1.1 2003/11/26 20:10:59 michael
  362. + New threadmanager implementation
  363. Revision 1.20 2003/11/19 10:54:32 marco
  364. * some simple restructures
  365. Revision 1.19 2003/11/18 22:36:12 marco
  366. * Last patch was ok, problem was somewhere else. Moved *BSD part of pthreads to freebsd/pthreads.inc
  367. Revision 1.18 2003/11/18 22:35:09 marco
  368. * Last patch was ok, problem was somewhere else. Moved *BSD part of pthreads to freebsd/pthreads.inc
  369. Revision 1.17 2003/11/17 10:05:51 marco
  370. * threads for FreeBSD. Not working tho
  371. Revision 1.16 2003/11/17 08:27:50 marco
  372. * pthreads based ttread from Johannes Berg
  373. Revision 1.15 2003/10/01 21:00:09 peter
  374. * GetCurrentThreadHandle renamed to GetCurrentThreadId
  375. Revision 1.14 2003/10/01 20:53:08 peter
  376. * GetCurrentThreadId implemented
  377. Revision 1.13 2003/09/20 12:38:29 marco
  378. * FCL now compiles for FreeBSD with new 1.1. Now Linux.
  379. Revision 1.12 2003/09/16 13:17:03 marco
  380. * Wat cleanup, ouwe syscalls nu via baseunix e.d.
  381. Revision 1.11 2003/09/16 13:00:02 marco
  382. * small BSD gotcha removed (typing mmap params)
  383. Revision 1.10 2003/09/15 20:08:49 marco
  384. * small fixes. FreeBSD now cycles
  385. Revision 1.9 2003/09/14 20:15:01 marco
  386. * Unix reform stage two. Remove all calls from Unix that exist in Baseunix.
  387. Revision 1.8 2003/03/27 17:14:27 armin
  388. * more platform independent thread routines, needs to be implemented for unix
  389. Revision 1.7 2003/01/05 19:11:32 marco
  390. * small changes originating from introduction of Baseunix to FreeBSD
  391. Revision 1.6 2002/11/11 21:41:06 marco
  392. * syscall.inc -> syscallo.inc
  393. Revision 1.5 2002/10/31 13:45:21 carl
  394. * threadvar.inc -> threadvr.inc
  395. Revision 1.4 2002/10/26 18:27:52 marco
  396. * First series POSIX calls commits. Including getcwd.
  397. Revision 1.3 2002/10/18 18:05:06 marco
  398. * $I pthread.inc instead of pthreads.inc
  399. Revision 1.2 2002/10/18 12:19:59 marco
  400. * Fixes to get the generic *BSD RTL compiling again + fixes for thread
  401. support. Still problems left in fexpand. (inoutres?) Therefore fixed
  402. sysposix not yet commited
  403. Revision 1.1 2002/10/16 06:22:56 michael
  404. Threads renamed from threads to systhrds
  405. Revision 1.1 2002/10/14 19:39:17 peter
  406. * threads unit added for thread support
  407. }