systhrds.pp 14 KB

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