systhrds.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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. {*****************************************************************************
  38. Generic overloaded
  39. *****************************************************************************}
  40. { Include generic overloaded routines }
  41. {$i thread.inc}
  42. {$ifndef BSD}
  43. {$i pthread.inc}
  44. {$else}
  45. {$i ptypes.inc}
  46. CONST PTHREAD_EXPLICIT_SCHED = 0;
  47. PTHREAD_CREATE_DETACHED = 1;
  48. PTHREAD_SCOPE_PROCESS = 0;
  49. TYPE
  50. pthread_t = pointer;
  51. ppthread_t = ^pthread_t;
  52. pthread_key_t = cint;
  53. ppthread_key_t = ^pthread_key_t;
  54. pthread_mutex_t = pointer;
  55. ppthread_mutex_t= ^pthread_mutex_t;
  56. pthread_attr_t = pointer; // opague
  57. ppthread_attr_t = ^pthread_attr_t; // opague
  58. __destr_func_t = procedure (p :pointer);cdecl;
  59. __startroutine_t= function (p :pointer):pointer;cdecl;
  60. pthread_mutex_attr_t = pointer;
  61. ppthread_mutex_attr_t = ^pthread_mutex_t;
  62. function pthread_getspecific (t : pthread_key_t):pointer; cdecl; external;
  63. function pthread_setspecific (t : pthread_key_t;p:pointer):cint; cdecl; external;
  64. function pthread_key_create (p : ppthread_key_t;f: __destr_func_t):cint; cdecl;external;
  65. function pthread_attr_init (p : ppthread_key_t):cint; cdecl; external;
  66. function pthread_attr_setinheritsched(p : ppthread_attr_t;i:cint):cint; cdecl; external;
  67. function pthread_attr_setscope (p : ppthread_attr_t;i:cint):cint;cdecl;external;
  68. function pthread_attr_setdetachstate (p : ppthread_attr_t;i:cint):cint;cdecl;external;
  69. function pthread_create ( p: ppthread_t;attr : ppthread_attr_t;f:__startroutine_t;arg:pointer):cint;cdecl;external;
  70. procedure pthread_exit ( p: pointer); cdecl;external;
  71. function pthread_mutex_init (p:ppthread_mutex_t;o:ppthread_mutex_attr_t):cint; cdecl;external;
  72. function pthread_mutex_destroy (p:ppthread_mutex_attr_t):cint; cdecl;external;
  73. function pthread_mutex_lock (p:ppthread_mutex_attr_t):cint; cdecl;external;
  74. function pthread_mutex_unlock (p:ppthread_mutex_attr_t):cint; cdecl;external;
  75. {$endif}
  76. {*****************************************************************************
  77. System dependent memory allocation
  78. *****************************************************************************}
  79. {$ifndef BSD}
  80. const
  81. syscall_nr_mmap = 90;
  82. syscall_nr_munmap = 91;
  83. { Constansts for MMAP }
  84. MAP_PRIVATE =2;
  85. MAP_ANONYMOUS =$20;
  86. type
  87. SysCallRegs=record
  88. reg1,reg2,reg3,reg4,reg5,reg6 : longint;
  89. end;
  90. var
  91. Errno : longint;
  92. { Include syscall itself }
  93. {$i syscallo.inc}
  94. Function Fpmmap(adr,len,prot,flags,fdes,off:longint):longint;
  95. type
  96. tmmapargs=packed record
  97. address : longint;
  98. size : longint;
  99. prot : longint;
  100. flags : longint;
  101. fd : longint;
  102. offset : longint;
  103. end;
  104. var
  105. t : syscallregs;
  106. mmapargs : tmmapargs;
  107. begin
  108. mmapargs.address:=adr;
  109. mmapargs.size:=len;
  110. mmapargs.prot:=prot;
  111. mmapargs.flags:=flags;
  112. mmapargs.fd:=fdes;
  113. mmapargs.offset:=off;
  114. t.reg2:=longint(@mmapargs);
  115. Fpmmap:=syscall(syscall_nr_mmap,t);
  116. end;
  117. Function Fpmunmap(adr,len:longint):longint;
  118. var
  119. t : syscallregs;
  120. begin
  121. t.reg2:=adr;
  122. t.reg3:=len;
  123. Fpmunmap:=syscall(syscall_nr_munmap,t);
  124. end;
  125. {$else}
  126. CONST
  127. { Constansts for MMAP. These are still private for *BSD }
  128. MAP_PRIVATE =2;
  129. MAP_ANONYMOUS =$1000;
  130. // include some non posix internal types.
  131. {$i ostypes.inc}
  132. // *BSD POSIX. Include headers to syscalls.
  133. {$I ossysch.inc}
  134. {$endif}
  135. {*****************************************************************************
  136. Threadvar support
  137. *****************************************************************************}
  138. {$ifdef HASTHREADVAR}
  139. const
  140. threadvarblocksize : dword = 0;
  141. var
  142. TLSKey : pthread_key_t;
  143. procedure SysInitThreadvar(var offset : dword;size : dword);
  144. begin
  145. offset:=threadvarblocksize;
  146. inc(threadvarblocksize,size);
  147. end;
  148. function SysRelocateThreadvar(offset : dword) : pointer;
  149. begin
  150. SysRelocateThreadvar:=pthread_getspecific(tlskey)+Offset;
  151. end;
  152. procedure SysAllocateThreadVars;
  153. var
  154. dataindex : pointer;
  155. begin
  156. { we've to allocate the memory from system }
  157. { because the FPC heap management uses }
  158. { exceptions which use threadvars but }
  159. { these aren't allocated yet ... }
  160. { allocate room on the heap for the thread vars }
  161. DataIndex:=Pointer(Fpmmap(0,threadvarblocksize,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0));
  162. FillChar(DataIndex^,threadvarblocksize,0);
  163. pthread_setspecific(tlskey,dataindex);
  164. end;
  165. procedure SysReleaseThreadVars;
  166. begin
  167. Fpmunmap(longint(pthread_getspecific(tlskey)),threadvarblocksize);
  168. end;
  169. { Include OS independent Threadvar initialization }
  170. {$i threadvr.inc}
  171. {$endif HASTHREADVAR}
  172. {*****************************************************************************
  173. Thread starting
  174. *****************************************************************************}
  175. type
  176. pthreadinfo = ^tthreadinfo;
  177. tthreadinfo = record
  178. f : tthreadfunc;
  179. p : pointer;
  180. stklen : cardinal;
  181. end;
  182. procedure DoneThread;
  183. begin
  184. { Release Threadvars }
  185. {$ifdef HASTHREADVAR}
  186. SysReleaseThreadVars;
  187. {$endif HASTHREADVAR}
  188. end;
  189. function ThreadMain(param : pointer) : pointer;cdecl;
  190. var
  191. ti : tthreadinfo;
  192. begin
  193. {$ifdef HASTHREADVAR}
  194. { Allocate local thread vars, this must be the first thing,
  195. because the exception management and io depends on threadvars }
  196. SysAllocateThreadVars;
  197. {$endif HASTHREADVAR}
  198. { Copy parameter to local data }
  199. {$ifdef DEBUG_MT}
  200. writeln('New thread started, initialising ...');
  201. {$endif DEBUG_MT}
  202. ti:=pthreadinfo(param)^;
  203. dispose(pthreadinfo(param));
  204. { Initialize thread }
  205. InitThread(ti.stklen);
  206. { Start thread function }
  207. {$ifdef DEBUG_MT}
  208. writeln('Jumping to thread function');
  209. {$endif DEBUG_MT}
  210. ThreadMain:=pointer(ti.f(ti.p));
  211. end;
  212. function BeginThread(sa : Pointer;stacksize : dword;
  213. ThreadFunction : tthreadfunc;p : pointer;
  214. creationFlags : dword; var ThreadId : DWord) : DWord;
  215. var
  216. ti : pthreadinfo;
  217. thread_attr : pthread_attr_t;
  218. begin
  219. {$ifdef DEBUG_MT}
  220. writeln('Creating new thread');
  221. {$endif DEBUG_MT}
  222. { Initialize multithreading if not done }
  223. if not IsMultiThread then
  224. begin
  225. {$ifdef HASTHREADVAR}
  226. { We're still running in single thread mode, setup the TLS }
  227. pthread_key_create(@TLSKey,nil);
  228. InitThreadVars(@SysRelocateThreadvar);
  229. {$endif HASTHREADVAR}
  230. IsMultiThread:=true;
  231. end;
  232. { the only way to pass data to the newly created thread
  233. in a MT safe way, is to use the heap }
  234. new(ti);
  235. ti^.f:=ThreadFunction;
  236. ti^.p:=p;
  237. ti^.stklen:=stacksize;
  238. { call pthread_create }
  239. {$ifdef DEBUG_MT}
  240. writeln('Starting new thread');
  241. {$endif DEBUG_MT}
  242. pthread_attr_init(@thread_attr);
  243. pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
  244. pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
  245. pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
  246. pthread_create(@threadid, @thread_attr, @ThreadMain,ti);
  247. BeginThread:=threadid;
  248. end;
  249. procedure EndThread(ExitCode : DWord);
  250. begin
  251. DoneThread;
  252. pthread_exit(pointer(ExitCode));
  253. end;
  254. {*****************************************************************************
  255. Delphi/Win32 compatibility
  256. *****************************************************************************}
  257. procedure InitCriticalSection(var CS:TRTLCriticalSection);
  258. begin
  259. cs.m_spinlock:=0;
  260. cs.m_count:=0;
  261. cs.m_owner:=0;
  262. cs.m_kind:=1;
  263. cs.m_waiting.head:=0;
  264. cs.m_waiting.tail:=0;
  265. pthread_mutex_init(@CS,NIL);
  266. end;
  267. procedure EnterCriticalSection(var CS:TRTLCriticalSection);
  268. begin
  269. pthread_mutex_lock(@CS);
  270. end;
  271. procedure LeaveCriticalSection(var CS:TRTLCriticalSection);
  272. begin
  273. pthread_mutex_unlock(@CS);
  274. end;
  275. procedure DoneCriticalSection(var CS:TRTLCriticalSection);
  276. begin
  277. pthread_mutex_destroy(@CS);
  278. end;
  279. {*****************************************************************************
  280. Heap Mutex Protection
  281. *****************************************************************************}
  282. var
  283. HeapMutex : pthread_mutex_t;
  284. procedure PThreadHeapMutexInit;
  285. begin
  286. pthread_mutex_init(@heapmutex,nil);
  287. end;
  288. procedure PThreadHeapMutexDone;
  289. begin
  290. pthread_mutex_destroy(@heapmutex);
  291. end;
  292. procedure PThreadHeapMutexLock;
  293. begin
  294. pthread_mutex_lock(@heapmutex);
  295. end;
  296. procedure PThreadHeapMutexUnlock;
  297. begin
  298. pthread_mutex_unlock(@heapmutex);
  299. end;
  300. const
  301. PThreadMemoryMutexManager : TMemoryMutexManager = (
  302. MutexInit : @PThreadHeapMutexInit;
  303. MutexDone : @PThreadHeapMutexDone;
  304. MutexLock : @PThreadHeapMutexLock;
  305. MutexUnlock : @PThreadHeapMutexUnlock;
  306. );
  307. procedure InitHeapMutexes;
  308. begin
  309. SetMemoryMutexManager(PThreadMemoryMutexManager);
  310. end;
  311. initialization
  312. InitHeapMutexes;
  313. end.
  314. {
  315. $Log$
  316. Revision 1.7 2003-01-05 19:11:32 marco
  317. * small changes originating from introduction of Baseunix to FreeBSD
  318. Revision 1.6 2002/11/11 21:41:06 marco
  319. * syscall.inc -> syscallo.inc
  320. Revision 1.5 2002/10/31 13:45:21 carl
  321. * threadvar.inc -> threadvr.inc
  322. Revision 1.4 2002/10/26 18:27:52 marco
  323. * First series POSIX calls commits. Including getcwd.
  324. Revision 1.3 2002/10/18 18:05:06 marco
  325. * $I pthread.inc instead of pthreads.inc
  326. Revision 1.2 2002/10/18 12:19:59 marco
  327. * Fixes to get the generic *BSD RTL compiling again + fixes for thread
  328. support. Still problems left in fexpand. (inoutres?) Therefore fixed
  329. sysposix not yet commited
  330. Revision 1.1 2002/10/16 06:22:56 michael
  331. Threads renamed from threads to systhrds
  332. Revision 1.1 2002/10/14 19:39:17 peter
  333. * threads unit added for thread support
  334. }