systhrds.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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. {$linklib c}
  17. {$linklib pthread}
  18. type
  19. PRTLCriticalSection = ^TRTLCriticalSection;
  20. TRTLCriticalSection = record
  21. m_spinlock : longint;
  22. m_count : longint;
  23. m_owner : pointer {pthread_t};
  24. m_kind : longint;
  25. m_waiting : record
  26. head,tail : pointer;
  27. end; {_pthread_queue}
  28. end;
  29. { Include generic thread interface }
  30. {$i threadh.inc}
  31. implementation
  32. {*****************************************************************************
  33. Generic overloaded
  34. *****************************************************************************}
  35. { Include generic overloaded routines }
  36. {$i thread.inc}
  37. {*****************************************************************************
  38. Local POSIX Threads (pthread) imports
  39. *****************************************************************************}
  40. { Attributes }
  41. const
  42. THREAD_PRIORITY_IDLE = 1;
  43. THREAD_PRIORITY_LOWEST = 15;
  44. THREAD_PRIORITY_BELOW_NORMAL = 30;
  45. THREAD_PRIORITY_NORMAL = 50;
  46. THREAD_PRIORITY_ABOVE_NORMAL = 70;
  47. THREAD_PRIORITY_HIGHEST = 80;
  48. THREAD_PRIORITY_TIME_CRITICAL = 99;
  49. PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP : array [0..5]of Integer = (0, 0, 0, 1, 0, 0);
  50. type
  51. TThreadPriority = (tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest, tpTimeCritical);
  52. const
  53. Priorities: array [TThreadPriority] of Integer = (
  54. THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,
  55. THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL,
  56. THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL
  57. );
  58. type
  59. psched_param = ^sched_param;
  60. sched_param = record
  61. sched_priority : LongInt;
  62. end;
  63. ptimespec = ^timespec;
  64. timespec = record
  65. tv_sec : LongInt;
  66. tv_nsec : LongInt;
  67. end;
  68. psigset_t = ^sigset_t;
  69. sigset_t = DWORD; // unsigned long 32 bits
  70. const
  71. _POSIX_THREAD_THREADS_MAX = 64;
  72. PTHREAD_THREADS_MAX = 512;
  73. _POSIX_THREAD_KEYS_MAX = 128;
  74. PTHREAD_KEYS_MAX = 128;
  75. type
  76. pthread_t = pointer;
  77. ppthread_t = ^pthread_t;
  78. p_pthread_queue = ^_pthread_queue;
  79. _pthread_queue = record
  80. head : pthread_t;
  81. tail : pthread_t;
  82. end;
  83. ppthread_mutex_t = PRtlCriticalSection;
  84. pthread_mutex_t = TRtlCriticalSection;
  85. ppthread_cond_t = ^pthread_cond_t;
  86. pthread_cond_t = record
  87. c_spinlock : longint;
  88. c_waiting : _pthread_queue;
  89. end;
  90. { Attributes }
  91. const
  92. PTHREAD_CREATE_JOINABLE = 0;
  93. PTHREAD_CREATE_DETACHED = 1;
  94. PTHREAD_INHERIT_SCHED = 0;
  95. PTHREAD_EXPLICIT_SCHED = 1;
  96. PTHREAD_SCOPE_SYSTEM = 0;
  97. PTHREAD_SCOPE_PROCESS = 1;
  98. type
  99. size_t = longint;
  100. ppthread_attr_t = ^pthread_attr_t;
  101. pthread_attr_t = record
  102. detachstate : longint;
  103. schedpolicy : longint;
  104. schedparam : sched_param;
  105. inheritsched : longint;
  106. scope : longint;
  107. __guardsize : size_t;
  108. __stackaddr_set : longint;
  109. __stackaddr : pointer;
  110. __stacksize : size_t;
  111. end;
  112. ppthread_mutexattr_t = ^pthread_mutexattr_t;
  113. pthread_mutexattr_t = record
  114. mutexkind : longint;
  115. end;
  116. ppthread_condattr_t = ^pthread_condattr_t;
  117. pthread_condattr_t = record
  118. dummy : longint;
  119. end;
  120. ppthread_key_t = ^pthread_key_t;
  121. pthread_key_t = cardinal;
  122. ppthread_once_t = ^pthread_once_t;
  123. pthread_once_t = longint;
  124. const
  125. PTHREAD_ONCE_INIT = 0;
  126. type
  127. tpcb_routine = Procedure(P:Pointer); cdecl;
  128. p_pthread_cleanup_buffer = ^_pthread_cleanup_buffer;
  129. _pthread_cleanup_buffer = record
  130. routine : tpcb_routine; { Function to call. }
  131. arg : Pointer; { Its argument. }
  132. canceltype:LongInt; { Saved cancellation type. }
  133. prev : p_pthread_cleanup_buffer; { Chaining of cleanup functions. }
  134. end;
  135. __start_routine_t = function (_para1:pointer):pointer;cdecl;
  136. __destr_function_t = procedure (_para1:pointer);
  137. t_pthread_cleanup_push_routine = procedure (_para1:pointer);
  138. t_pthread_cleanup_push_defer_routine = procedure (_para1:pointer);
  139. function pthread_create(__thread:ppthread_t; __attr:ppthread_attr_t;__start_routine: __start_routine_t;__arg:pointer):longint;cdecl;external;
  140. function pthread_self:pthread_t;cdecl;external;
  141. function pthread_equal(__thread1:pthread_t; __thread2:pthread_t):longint;cdecl;external;
  142. procedure pthread_exit(__retval:pointer);cdecl;external;
  143. function pthread_join(__th:pthread_t; __thread_return:ppointer):longint;cdecl;external;
  144. function pthread_detach(__th:pthread_t):longint;cdecl;external;
  145. function pthread_attr_init(__attr:ppthread_attr_t):longint;cdecl;external;
  146. function pthread_attr_destroy(__attr:ppthread_attr_t):longint;cdecl;external;
  147. function pthread_attr_setdetachstate(__attr:ppthread_attr_t; __detachstate:longint):longint;cdecl;external;
  148. function pthread_attr_getdetachstate(__attr:ppthread_attr_t; __detachstate:plongint):longint;cdecl;external;
  149. function pthread_attr_setschedparam(__attr:ppthread_attr_t; __param:psched_param):longint;cdecl;external;
  150. function pthread_attr_getschedparam(__attr:ppthread_attr_t; __param:psched_param):longint;cdecl;external;
  151. function pthread_attr_setschedpolicy(__attr:ppthread_attr_t; __policy:longint):longint;cdecl;external;
  152. function pthread_attr_getschedpolicy(__attr:ppthread_attr_t; __policy:plongint):longint;cdecl;external;
  153. function pthread_attr_setinheritsched(__attr:ppthread_attr_t; __inherit:longint):longint;cdecl;external;
  154. function pthread_attr_getinheritsched(__attr:ppthread_attr_t; __inherit:plongint):longint;cdecl;external;
  155. function pthread_attr_setscope(__attr:ppthread_attr_t; __scope:longint):longint;cdecl;external;
  156. function pthread_attr_getscope(__attr:ppthread_attr_t; __scope:plongint):longint;cdecl;external;
  157. function pthread_setschedparam(__target_thread:pthread_t; __policy:longint; __param:psched_param):longint;cdecl;external;
  158. function pthread_getschedparam(__target_thread:pthread_t; __policy:plongint; __param:psched_param):longint;cdecl;external;
  159. function pthread_mutex_init(__mutex:ppthread_mutex_t; __mutex_attr:ppthread_mutexattr_t):longint;cdecl;external;
  160. function pthread_mutex_destroy(__mutex:ppthread_mutex_t):longint;cdecl;external;
  161. function pthread_mutex_trylock(__mutex:ppthread_mutex_t):longint;cdecl;external;
  162. function pthread_mutex_lock(__mutex:ppthread_mutex_t):longint;cdecl;external;
  163. function pthread_mutex_unlock(__mutex:ppthread_mutex_t):longint;cdecl;external;
  164. function pthread_mutexattr_init(__attr:ppthread_mutexattr_t):longint;cdecl;external;
  165. function pthread_mutexattr_destroy(__attr:ppthread_mutexattr_t):longint;cdecl;external;
  166. function pthread_mutexattr_setkind_np(__attr:ppthread_mutexattr_t; __kind:longint):longint;cdecl;external;
  167. function pthread_mutexattr_getkind_np(__attr:ppthread_mutexattr_t; __kind:plongint):longint;cdecl;external;
  168. function pthread_cond_init(__cond:ppthread_cond_t; __cond_attr:ppthread_condattr_t):longint;cdecl;external;
  169. function pthread_cond_destroy(__cond:ppthread_cond_t):longint;cdecl;external;
  170. function pthread_cond_signal(__cond:ppthread_cond_t):longint;cdecl;external;
  171. function pthread_cond_broadcast(__cond:ppthread_cond_t):longint;cdecl;external;
  172. function pthread_cond_wait(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t):longint;cdecl;external;
  173. function pthread_cond_timedwait(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t; __abstime:ptimespec):longint;cdecl;external;
  174. function pthread_condattr_init(__attr:ppthread_condattr_t):longint;cdecl;external;
  175. function pthread_condattr_destroy(__attr:ppthread_condattr_t):longint;cdecl;external;
  176. function pthread_key_create(__key:ppthread_key_t; __destr_function:__destr_function_t):longint;cdecl;external;
  177. function pthread_key_delete(__key:pthread_key_t):longint;cdecl;external;
  178. function pthread_setspecific(__key:pthread_key_t; __pointer:pointer):longint;cdecl;external;
  179. function pthread_getspecific(__key:pthread_key_t):pointer;cdecl;external;
  180. function pthread_once(__once_control:ppthread_once_t; __init_routine:tprocedure ):longint;cdecl;external;
  181. function pthread_setcancelstate(__state:longint; __oldstate:plongint):longint;cdecl;external;
  182. function pthread_setcanceltype(__type:longint; __oldtype:plongint):longint;cdecl;external;
  183. function pthread_cancel(__thread:pthread_t):longint;cdecl;external;
  184. procedure pthread_testcancel;cdecl;external;
  185. procedure _pthread_cleanup_push(__buffer:p_pthread_cleanup_buffer;__routine:t_pthread_cleanup_push_routine; __arg:pointer);cdecl;external;
  186. procedure _pthread_cleanup_push_defer(__buffer:p_pthread_cleanup_buffer;__routine:t_pthread_cleanup_push_defer_routine; __arg:pointer);cdecl;external;
  187. function pthread_sigmask(__how:longint; __newmask:psigset_t; __oldmask:psigset_t):longint;cdecl;external;
  188. function pthread_kill(__thread:pthread_t; __signo:longint):longint;cdecl;external;
  189. function sigwait(__set:psigset_t; __sig:plongint):longint;cdecl;external;
  190. function pthread_atfork(__prepare:tprocedure ; __parent:tprocedure ; __child:tprocedure ):longint;cdecl;external;
  191. procedure pthread_kill_other_threads_np;cdecl;external;
  192. {*****************************************************************************
  193. System dependent memory allocation
  194. *****************************************************************************}
  195. const
  196. syscall_nr_mmap = 90;
  197. syscall_nr_munmap = 91;
  198. { Constansts for MMAP }
  199. MAP_PRIVATE =2;
  200. MAP_ANONYMOUS =$20;
  201. type
  202. SysCallRegs=record
  203. reg1,reg2,reg3,reg4,reg5,reg6 : longint;
  204. end;
  205. var
  206. Errno : longint;
  207. { Include syscall itself }
  208. {$i syscall.inc}
  209. Function Sys_mmap(adr,len,prot,flags,fdes,off:longint):longint;
  210. type
  211. tmmapargs=packed record
  212. address : longint;
  213. size : longint;
  214. prot : longint;
  215. flags : longint;
  216. fd : longint;
  217. offset : longint;
  218. end;
  219. var
  220. t : syscallregs;
  221. mmapargs : tmmapargs;
  222. begin
  223. mmapargs.address:=adr;
  224. mmapargs.size:=len;
  225. mmapargs.prot:=prot;
  226. mmapargs.flags:=flags;
  227. mmapargs.fd:=fdes;
  228. mmapargs.offset:=off;
  229. t.reg2:=longint(@mmapargs);
  230. Sys_mmap:=syscall(syscall_nr_mmap,t);
  231. end;
  232. Function Sys_munmap(adr,len:longint):longint;
  233. var
  234. t : syscallregs;
  235. begin
  236. t.reg2:=adr;
  237. t.reg3:=len;
  238. Sys_munmap:=syscall(syscall_nr_munmap,t);
  239. end;
  240. {*****************************************************************************
  241. Threadvar support
  242. *****************************************************************************}
  243. {$ifdef HASTHREADVAR}
  244. const
  245. threadvarblocksize : dword = 0;
  246. var
  247. TLSKey : pthread_key_t;
  248. procedure SysInitThreadvar(var offset : dword;size : dword);
  249. begin
  250. offset:=threadvarblocksize;
  251. inc(threadvarblocksize,size);
  252. end;
  253. function SysRelocateThreadvar(offset : dword) : pointer;
  254. begin
  255. SysRelocateThreadvar:=pthread_getspecific(tlskey)+Offset;
  256. end;
  257. procedure SysAllocateThreadVars;
  258. var
  259. dataindex : pointer;
  260. begin
  261. { we've to allocate the memory from system }
  262. { because the FPC heap management uses }
  263. { exceptions which use threadvars but }
  264. { these aren't allocated yet ... }
  265. { allocate room on the heap for the thread vars }
  266. DataIndex:=Pointer(Sys_mmap(0,threadvarblocksize,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0));
  267. FillChar(DataIndex^,threadvarblocksize,0);
  268. pthread_setspecific(tlskey,dataindex);
  269. end;
  270. procedure SysReleaseThreadVars;
  271. begin
  272. Sys_munmap(longint(pthread_getspecific(tlskey)),threadvarblocksize);
  273. end;
  274. { Include OS independent Threadvar initialization }
  275. {$i threadvar.inc}
  276. {$endif HASTHREADVAR}
  277. {*****************************************************************************
  278. Thread starting
  279. *****************************************************************************}
  280. type
  281. pthreadinfo = ^tthreadinfo;
  282. tthreadinfo = record
  283. f : tthreadfunc;
  284. p : pointer;
  285. stklen : cardinal;
  286. end;
  287. procedure DoneThread;
  288. begin
  289. { Release Threadvars }
  290. {$ifdef HASTHREADVAR}
  291. SysReleaseThreadVars;
  292. {$endif HASTHREADVAR}
  293. end;
  294. function ThreadMain(param : pointer) : pointer;cdecl;
  295. var
  296. ti : tthreadinfo;
  297. begin
  298. {$ifdef HASTHREADVAR}
  299. { Allocate local thread vars, this must be the first thing,
  300. because the exception management and io depends on threadvars }
  301. SysAllocateThreadVars;
  302. {$endif HASTHREADVAR}
  303. { Copy parameter to local data }
  304. {$ifdef DEBUG_MT}
  305. writeln('New thread started, initialising ...');
  306. {$endif DEBUG_MT}
  307. ti:=pthreadinfo(param)^;
  308. dispose(pthreadinfo(param));
  309. { Initialize thread }
  310. InitThread(ti.stklen);
  311. { Start thread function }
  312. {$ifdef DEBUG_MT}
  313. writeln('Jumping to thread function');
  314. {$endif DEBUG_MT}
  315. ThreadMain:=pointer(ti.f(ti.p));
  316. end;
  317. function BeginThread(sa : Pointer;stacksize : dword;
  318. ThreadFunction : tthreadfunc;p : pointer;
  319. creationFlags : dword; var ThreadId : DWord) : DWord;
  320. var
  321. ti : pthreadinfo;
  322. thread_attr : pthread_attr_t;
  323. begin
  324. {$ifdef DEBUG_MT}
  325. writeln('Creating new thread');
  326. {$endif DEBUG_MT}
  327. { Initialize multithreading if not done }
  328. if not IsMultiThread then
  329. begin
  330. {$ifdef HASTHREADVAR}
  331. { We're still running in single thread mode, setup the TLS }
  332. pthread_key_create(@TLSKey,nil);
  333. InitThreadVars(@SysRelocateThreadvar);
  334. {$endif HASTHREADVAR}
  335. IsMultiThread:=true;
  336. end;
  337. { the only way to pass data to the newly created thread
  338. in a MT safe way, is to use the heap }
  339. new(ti);
  340. ti^.f:=ThreadFunction;
  341. ti^.p:=p;
  342. ti^.stklen:=stacksize;
  343. { call pthread_create }
  344. {$ifdef DEBUG_MT}
  345. writeln('Starting new thread');
  346. {$endif DEBUG_MT}
  347. pthread_attr_init(@thread_attr);
  348. pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
  349. pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
  350. pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
  351. pthread_create(@threadid, @thread_attr, @ThreadMain,ti);
  352. BeginThread:=threadid;
  353. end;
  354. procedure EndThread(ExitCode : DWord);
  355. begin
  356. DoneThread;
  357. pthread_exit(pointer(ExitCode));
  358. end;
  359. {*****************************************************************************
  360. Delphi/Win32 compatibility
  361. *****************************************************************************}
  362. procedure InitCriticalSection(var CS:TRTLCriticalSection);
  363. begin
  364. cs.m_spinlock:=0;
  365. cs.m_count:=0;
  366. cs.m_owner:=0;
  367. cs.m_kind:=1;
  368. cs.m_waiting.head:=0;
  369. cs.m_waiting.tail:=0;
  370. pthread_mutex_init(@CS,NIL);
  371. end;
  372. procedure EnterCriticalSection(var CS:TRTLCriticalSection);
  373. begin
  374. pthread_mutex_lock(@CS);
  375. end;
  376. procedure LeaveCriticalSection(var CS:TRTLCriticalSection);
  377. begin
  378. pthread_mutex_unlock(@CS);
  379. end;
  380. procedure DoneCriticalSection(var CS:TRTLCriticalSection);
  381. begin
  382. pthread_mutex_destroy(@CS);
  383. end;
  384. {*****************************************************************************
  385. Heap Mutex Protection
  386. *****************************************************************************}
  387. var
  388. HeapMutex : pthread_mutex_t;
  389. procedure PThreadHeapMutexInit;
  390. begin
  391. pthread_mutex_init(@heapmutex,nil);
  392. end;
  393. procedure PThreadHeapMutexDone;
  394. begin
  395. pthread_mutex_destroy(@heapmutex);
  396. end;
  397. procedure PThreadHeapMutexLock;
  398. begin
  399. pthread_mutex_lock(@heapmutex);
  400. end;
  401. procedure PThreadHeapMutexUnlock;
  402. begin
  403. pthread_mutex_unlock(@heapmutex);
  404. end;
  405. const
  406. PThreadMemoryMutexManager : TMemoryMutexManager = (
  407. MutexInit : @PThreadHeapMutexInit;
  408. MutexDone : @PThreadHeapMutexDone;
  409. MutexLock : @PThreadHeapMutexLock;
  410. MutexUnlock : @PThreadHeapMutexUnlock;
  411. );
  412. procedure InitHeapMutexes;
  413. begin
  414. SetMemoryMutexManager(PThreadMemoryMutexManager);
  415. end;
  416. initialization
  417. InitHeapMutexes;
  418. end.
  419. {
  420. $Log$
  421. Revision 1.1 2002-10-16 06:22:56 michael
  422. Threads renamed from threads to systhrds
  423. Revision 1.1 2002/10/14 19:39:17 peter
  424. * threads unit added for thread support
  425. }