threads.pp 18 KB

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