systhrds.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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 syscall.inc}
  94. Function Sys_mmap(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. Sys_mmap:=syscall(syscall_nr_mmap,t);
  116. end;
  117. Function Sys_munmap(adr,len:longint):longint;
  118. var
  119. t : syscallregs;
  120. begin
  121. t.reg2:=adr;
  122. t.reg3:=len;
  123. Sys_munmap:=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. // *BSD POSIX. Include headers to syscalls.
  131. {$I bsdsysch.inc}
  132. {$endif}
  133. {*****************************************************************************
  134. Threadvar support
  135. *****************************************************************************}
  136. {$ifdef HASTHREADVAR}
  137. const
  138. threadvarblocksize : dword = 0;
  139. var
  140. TLSKey : pthread_key_t;
  141. procedure SysInitThreadvar(var offset : dword;size : dword);
  142. begin
  143. offset:=threadvarblocksize;
  144. inc(threadvarblocksize,size);
  145. end;
  146. function SysRelocateThreadvar(offset : dword) : pointer;
  147. begin
  148. SysRelocateThreadvar:=pthread_getspecific(tlskey)+Offset;
  149. end;
  150. procedure SysAllocateThreadVars;
  151. var
  152. dataindex : pointer;
  153. begin
  154. { we've to allocate the memory from system }
  155. { because the FPC heap management uses }
  156. { exceptions which use threadvars but }
  157. { these aren't allocated yet ... }
  158. { allocate room on the heap for the thread vars }
  159. DataIndex:=Pointer(Sys_mmap(0,threadvarblocksize,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0));
  160. FillChar(DataIndex^,threadvarblocksize,0);
  161. pthread_setspecific(tlskey,dataindex);
  162. end;
  163. procedure SysReleaseThreadVars;
  164. begin
  165. Sys_munmap(longint(pthread_getspecific(tlskey)),threadvarblocksize);
  166. end;
  167. { Include OS independent Threadvar initialization }
  168. {$i threadvar.inc}
  169. {$endif HASTHREADVAR}
  170. {*****************************************************************************
  171. Thread starting
  172. *****************************************************************************}
  173. type
  174. pthreadinfo = ^tthreadinfo;
  175. tthreadinfo = record
  176. f : tthreadfunc;
  177. p : pointer;
  178. stklen : cardinal;
  179. end;
  180. procedure DoneThread;
  181. begin
  182. { Release Threadvars }
  183. {$ifdef HASTHREADVAR}
  184. SysReleaseThreadVars;
  185. {$endif HASTHREADVAR}
  186. end;
  187. function ThreadMain(param : pointer) : pointer;cdecl;
  188. var
  189. ti : tthreadinfo;
  190. begin
  191. {$ifdef HASTHREADVAR}
  192. { Allocate local thread vars, this must be the first thing,
  193. because the exception management and io depends on threadvars }
  194. SysAllocateThreadVars;
  195. {$endif HASTHREADVAR}
  196. { Copy parameter to local data }
  197. {$ifdef DEBUG_MT}
  198. writeln('New thread started, initialising ...');
  199. {$endif DEBUG_MT}
  200. ti:=pthreadinfo(param)^;
  201. dispose(pthreadinfo(param));
  202. { Initialize thread }
  203. InitThread(ti.stklen);
  204. { Start thread function }
  205. {$ifdef DEBUG_MT}
  206. writeln('Jumping to thread function');
  207. {$endif DEBUG_MT}
  208. ThreadMain:=pointer(ti.f(ti.p));
  209. end;
  210. function BeginThread(sa : Pointer;stacksize : dword;
  211. ThreadFunction : tthreadfunc;p : pointer;
  212. creationFlags : dword; var ThreadId : DWord) : DWord;
  213. var
  214. ti : pthreadinfo;
  215. thread_attr : pthread_attr_t;
  216. begin
  217. {$ifdef DEBUG_MT}
  218. writeln('Creating new thread');
  219. {$endif DEBUG_MT}
  220. { Initialize multithreading if not done }
  221. if not IsMultiThread then
  222. begin
  223. {$ifdef HASTHREADVAR}
  224. { We're still running in single thread mode, setup the TLS }
  225. pthread_key_create(@TLSKey,nil);
  226. InitThreadVars(@SysRelocateThreadvar);
  227. {$endif HASTHREADVAR}
  228. IsMultiThread:=true;
  229. end;
  230. { the only way to pass data to the newly created thread
  231. in a MT safe way, is to use the heap }
  232. new(ti);
  233. ti^.f:=ThreadFunction;
  234. ti^.p:=p;
  235. ti^.stklen:=stacksize;
  236. { call pthread_create }
  237. {$ifdef DEBUG_MT}
  238. writeln('Starting new thread');
  239. {$endif DEBUG_MT}
  240. pthread_attr_init(@thread_attr);
  241. pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
  242. pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
  243. pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
  244. pthread_create(@threadid, @thread_attr, @ThreadMain,ti);
  245. BeginThread:=threadid;
  246. end;
  247. procedure EndThread(ExitCode : DWord);
  248. begin
  249. DoneThread;
  250. pthread_exit(pointer(ExitCode));
  251. end;
  252. {*****************************************************************************
  253. Delphi/Win32 compatibility
  254. *****************************************************************************}
  255. procedure InitCriticalSection(var CS:TRTLCriticalSection);
  256. begin
  257. cs.m_spinlock:=0;
  258. cs.m_count:=0;
  259. cs.m_owner:=0;
  260. cs.m_kind:=1;
  261. cs.m_waiting.head:=0;
  262. cs.m_waiting.tail:=0;
  263. pthread_mutex_init(@CS,NIL);
  264. end;
  265. procedure EnterCriticalSection(var CS:TRTLCriticalSection);
  266. begin
  267. pthread_mutex_lock(@CS);
  268. end;
  269. procedure LeaveCriticalSection(var CS:TRTLCriticalSection);
  270. begin
  271. pthread_mutex_unlock(@CS);
  272. end;
  273. procedure DoneCriticalSection(var CS:TRTLCriticalSection);
  274. begin
  275. pthread_mutex_destroy(@CS);
  276. end;
  277. {*****************************************************************************
  278. Heap Mutex Protection
  279. *****************************************************************************}
  280. var
  281. HeapMutex : pthread_mutex_t;
  282. procedure PThreadHeapMutexInit;
  283. begin
  284. pthread_mutex_init(@heapmutex,nil);
  285. end;
  286. procedure PThreadHeapMutexDone;
  287. begin
  288. pthread_mutex_destroy(@heapmutex);
  289. end;
  290. procedure PThreadHeapMutexLock;
  291. begin
  292. pthread_mutex_lock(@heapmutex);
  293. end;
  294. procedure PThreadHeapMutexUnlock;
  295. begin
  296. pthread_mutex_unlock(@heapmutex);
  297. end;
  298. const
  299. PThreadMemoryMutexManager : TMemoryMutexManager = (
  300. MutexInit : @PThreadHeapMutexInit;
  301. MutexDone : @PThreadHeapMutexDone;
  302. MutexLock : @PThreadHeapMutexLock;
  303. MutexUnlock : @PThreadHeapMutexUnlock;
  304. );
  305. procedure InitHeapMutexes;
  306. begin
  307. SetMemoryMutexManager(PThreadMemoryMutexManager);
  308. end;
  309. initialization
  310. InitHeapMutexes;
  311. end.
  312. {
  313. $Log$
  314. Revision 1.3 2002-10-18 18:05:06 marco
  315. * $I pthread.inc instead of pthreads.inc
  316. Revision 1.2 2002/10/18 12:19:59 marco
  317. * Fixes to get the generic *BSD RTL compiling again + fixes for thread
  318. support. Still problems left in fexpand. (inoutres?) Therefore fixed
  319. sysposix not yet commited
  320. Revision 1.1 2002/10/16 06:22:56 michael
  321. Threads renamed from threads to systhrds
  322. Revision 1.1 2002/10/14 19:39:17 peter
  323. * threads unit added for thread support
  324. }