2
0

systhrds.pp 13 KB

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