cthreads.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2002 by Peter Vreman,
  4. member of the Free Pascal development team.
  5. Linux (pthreads) threading support implementation
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$ifdef linux}
  14. {$define dynpthreads} // Useless on BSD, since they are in libc
  15. {$endif}
  16. { sem_init is best, since it does not consume any file descriptors. }
  17. { sem_open is second best, since it consumes only one file descriptor }
  18. { per semaphore. }
  19. { If neither is available, pipe is used as fallback, which consumes 2 }
  20. { file descriptors per semaphore. }
  21. { Darwin doesn't support nameless semaphores in at least }
  22. { Mac OS X 10.4.8/Darwin 8.8 }
  23. {$ifndef darwin}
  24. {$define has_sem_init}
  25. {$define has_sem_getvalue}
  26. {$else }
  27. {$ifdef darwin}
  28. {$define has_sem_open}
  29. {$endif}
  30. {$endif}
  31. unit cthreads;
  32. interface
  33. {$S-}
  34. {$ifndef dynpthreads} // If you have problems compiling this on FreeBSD 5.x
  35. {$linklib c} // try adding -Xf
  36. {$ifndef Darwin}
  37. {$linklib pthread}
  38. {$endif darwin}
  39. {$endif}
  40. Procedure SetCThreadManager;
  41. implementation
  42. Uses
  43. BaseUnix,
  44. unix,
  45. unixtype
  46. {$ifdef dynpthreads}
  47. ,dl
  48. {$endif}
  49. ;
  50. {*****************************************************************************
  51. Generic overloaded
  52. *****************************************************************************}
  53. { Include OS specific parts. }
  54. {$i pthread.inc}
  55. Type PINTRTLEvent = ^TINTRTLEvent;
  56. TINTRTLEvent = record
  57. condvar: pthread_cond_t;
  58. mutex: pthread_mutex_t;
  59. isset: boolean;
  60. end;
  61. {*****************************************************************************
  62. Threadvar support
  63. *****************************************************************************}
  64. const
  65. threadvarblocksize : dword = 0;
  66. var
  67. TLSKey : pthread_key_t;
  68. procedure CInitThreadvar(var offset : dword;size : dword);
  69. begin
  70. {$ifdef cpusparc}
  71. threadvarblocksize:=align(threadvarblocksize,16);
  72. {$endif cpusparc}
  73. {$ifdef cpupowerpc}
  74. threadvarblocksize:=align(threadvarblocksize,8);
  75. {$endif cpupowerc}
  76. {$ifdef cpui386}
  77. threadvarblocksize:=align(threadvarblocksize,8);
  78. {$endif cpui386}
  79. {$ifdef cpuarm}
  80. threadvarblocksize:=align(threadvarblocksize,4);
  81. {$endif cpuarm}
  82. {$ifdef cpum68k}
  83. threadvarblocksize:=align(threadvarblocksize,2);
  84. {$endif cpum68k}
  85. {$ifdef cpux86_64}
  86. threadvarblocksize:=align(threadvarblocksize,16);
  87. {$endif cpux86_64}
  88. {$ifdef cpupowerpc64}
  89. threadvarblocksize:=align(threadvarblocksize,16);
  90. {$endif cpupowerpc64}
  91. offset:=threadvarblocksize;
  92. inc(threadvarblocksize,size);
  93. end;
  94. procedure CAllocateThreadVars;
  95. var
  96. dataindex : pointer;
  97. begin
  98. { we've to allocate the memory from system }
  99. { because the FPC heap management uses }
  100. { exceptions which use threadvars but }
  101. { these aren't allocated yet ... }
  102. { allocate room on the heap for the thread vars }
  103. DataIndex:=Pointer(Fpmmap(nil,threadvarblocksize,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0));
  104. FillChar(DataIndex^,threadvarblocksize,0);
  105. pthread_setspecific(tlskey,dataindex);
  106. end;
  107. function CRelocateThreadvar(offset : dword) : pointer;
  108. var
  109. P : Pointer;
  110. begin
  111. P:=pthread_getspecific(tlskey);
  112. if (P=Nil) then
  113. begin
  114. CAllocateThreadvars;
  115. // If this also goes wrong: bye bye threadvars...
  116. P:=pthread_getspecific(tlskey);
  117. end;
  118. CRelocateThreadvar:=P+Offset;
  119. end;
  120. procedure CReleaseThreadVars;
  121. begin
  122. Fpmunmap(pointer(pthread_getspecific(tlskey)),threadvarblocksize);
  123. end;
  124. { Include OS independent Threadvar initialization }
  125. {*****************************************************************************
  126. Thread starting
  127. *****************************************************************************}
  128. type
  129. pthreadinfo = ^tthreadinfo;
  130. tthreadinfo = record
  131. f : tthreadfunc;
  132. p : pointer;
  133. stklen : cardinal;
  134. end;
  135. procedure DoneThread;
  136. begin
  137. { Release Threadvars }
  138. CReleaseThreadVars;
  139. end;
  140. function ThreadMain(param : pointer) : pointer;cdecl;
  141. var
  142. ti : tthreadinfo;
  143. {$ifdef DEBUG_MT}
  144. // in here, don't use write/writeln before having called
  145. // InitThread! I wonder if anyone ever debugged these routines,
  146. // because they will have crashed if DEBUG_MT was enabled!
  147. // this took me the good part of an hour to figure out
  148. // why it was crashing all the time!
  149. // this is kind of a workaround, we simply write(2) to fd 0
  150. s: string[100]; // not an ansistring
  151. {$endif DEBUG_MT}
  152. begin
  153. {$ifdef DEBUG_MT}
  154. s := 'New thread started, initing threadvars'#10;
  155. fpwrite(0,s[1],length(s));
  156. {$endif DEBUG_MT}
  157. { Allocate local thread vars, this must be the first thing,
  158. because the exception management and io depends on threadvars }
  159. CAllocateThreadVars;
  160. { Copy parameter to local data }
  161. {$ifdef DEBUG_MT}
  162. s := 'New thread started, initialising ...'#10;
  163. fpwrite(0,s[1],length(s));
  164. {$endif DEBUG_MT}
  165. ti:=pthreadinfo(param)^;
  166. dispose(pthreadinfo(param));
  167. { Initialize thread }
  168. InitThread(ti.stklen);
  169. { Start thread function }
  170. {$ifdef DEBUG_MT}
  171. writeln('Jumping to thread function');
  172. {$endif DEBUG_MT}
  173. ThreadMain:=pointer(ti.f(ti.p));
  174. DoneThread;
  175. pthread_exit(nil);
  176. end;
  177. function CBeginThread(sa : Pointer;stacksize : PtrUInt;
  178. ThreadFunction : tthreadfunc;p : pointer;
  179. creationFlags : dword; var ThreadId : TThreadId) : TThreadID;
  180. var
  181. ti : pthreadinfo;
  182. thread_attr : pthread_attr_t;
  183. begin
  184. {$ifdef DEBUG_MT}
  185. writeln('Creating new thread');
  186. {$endif DEBUG_MT}
  187. { Initialize multithreading if not done }
  188. if not IsMultiThread then
  189. begin
  190. if (InterLockedExchange(longint(IsMultiThread),ord(true)) = 0) then
  191. begin
  192. { We're still running in single thread mode, setup the TLS }
  193. pthread_key_create(@TLSKey,nil);
  194. InitThreadVars(@CRelocateThreadvar);
  195. end
  196. end;
  197. { the only way to pass data to the newly created thread
  198. in a MT safe way, is to use the heap }
  199. new(ti);
  200. ti^.f:=ThreadFunction;
  201. ti^.p:=p;
  202. ti^.stklen:=stacksize;
  203. { call pthread_create }
  204. {$ifdef DEBUG_MT}
  205. writeln('Starting new thread');
  206. {$endif DEBUG_MT}
  207. pthread_attr_init(@thread_attr);
  208. pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
  209. // will fail under linux -- apparently unimplemented
  210. pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
  211. // don't create detached, we need to be able to join (waitfor) on
  212. // the newly created thread!
  213. //pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
  214. if pthread_create(ppthread_t(@threadid), @thread_attr, @ThreadMain,ti) <> 0 then
  215. begin
  216. dispose(ti);
  217. threadid := TThreadID(0);
  218. end;
  219. CBeginThread:=threadid;
  220. {$ifdef DEBUG_MT}
  221. writeln('BeginThread returning ',ptrint(CBeginThread));
  222. {$endif DEBUG_MT}
  223. end;
  224. procedure CEndThread(ExitCode : DWord);
  225. begin
  226. DoneThread;
  227. pthread_detach(pthread_t(pthread_self()));
  228. pthread_exit(pointer(ptrint(ExitCode)));
  229. end;
  230. function CSuspendThread (threadHandle : TThreadID) : dword;
  231. begin
  232. result := pthread_kill(threadHandle,SIGSTOP);
  233. end;
  234. function CResumeThread (threadHandle : TThreadID) : dword;
  235. begin
  236. result := pthread_kill(threadHandle,SIGCONT);
  237. end;
  238. procedure CThreadSwitch; {give time to other threads}
  239. begin
  240. {extern int pthread_yield (void) __THROW;}
  241. {$Warning ThreadSwitch needs to be implemented}
  242. end;
  243. function CKillThread (threadHandle : TThreadID) : dword;
  244. begin
  245. pthread_detach(pthread_t(threadHandle));
  246. CKillThread := pthread_cancel(pthread_t(threadHandle));
  247. end;
  248. function CWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword; {0=no timeout}
  249. var
  250. LResultP: Pointer;
  251. LResult: DWord;
  252. begin
  253. LResult := 0;
  254. LResultP := @LResult;
  255. pthread_join(pthread_t(threadHandle), @LResultP);
  256. CWaitForThreadTerminate := LResult;
  257. end;
  258. {$warning threadhandle can be larger than a dword}
  259. function CThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
  260. begin
  261. {$Warning ThreadSetPriority needs to be implemented}
  262. end;
  263. {$warning threadhandle can be larger than a dword}
  264. function CThreadGetPriority (threadHandle : TThreadID): Integer;
  265. begin
  266. {$Warning ThreadGetPriority needs to be implemented}
  267. end;
  268. function CGetCurrentThreadId : TThreadID;
  269. begin
  270. CGetCurrentThreadId := TThreadID (pthread_self());
  271. end;
  272. {*****************************************************************************
  273. Delphi/Win32 compatibility
  274. *****************************************************************************}
  275. procedure CInitCriticalSection(var CS);
  276. var
  277. MAttr : pthread_mutexattr_t;
  278. res: longint;
  279. begin
  280. res:=pthread_mutexattr_init(@MAttr);
  281. if res=0 then
  282. begin
  283. res:=pthread_mutexattr_settype(@MAttr,longint(_PTHREAD_MUTEX_RECURSIVE));
  284. if res=0 then
  285. res := pthread_mutex_init(@CS,@MAttr)
  286. else
  287. { No recursive mutex support :/ }
  288. res := pthread_mutex_init(@CS,NIL);
  289. end
  290. else
  291. res:= pthread_mutex_init(@CS,NIL);
  292. pthread_mutexattr_destroy(@MAttr);
  293. if res <> 0 then
  294. runerror(6);
  295. end;
  296. procedure CEnterCriticalSection(var CS);
  297. begin
  298. if pthread_mutex_lock(@CS) <> 0 then
  299. runerror(6);
  300. end;
  301. procedure CLeaveCriticalSection(var CS);
  302. begin
  303. if pthread_mutex_unlock(@CS) <> 0 then
  304. runerror(6)
  305. end;
  306. procedure CDoneCriticalSection(var CS);
  307. begin
  308. { unlock as long as unlocking works to unlock it if it is recursive
  309. some Delphi code might call this function with a locked mutex }
  310. while pthread_mutex_unlock(@CS)=0 do
  311. ;
  312. if pthread_mutex_destroy(@CS) <> 0 then
  313. runerror(6);
  314. end;
  315. {*****************************************************************************
  316. Semaphore routines
  317. *****************************************************************************}
  318. procedure cSemaphoreWait(const FSem: Pointer);
  319. var
  320. res: cint;
  321. err: cint;
  322. {$if not defined(has_sem_init) and not defined(has_sem_open)}
  323. b: byte;
  324. {$endif}
  325. begin
  326. {$if defined(has_sem_init) or defined(has_sem_open)}
  327. repeat
  328. res:=sem_wait(PSemaphore(FSem));
  329. err:=fpgeterrno;
  330. until (res<>-1) or (err<>ESysEINTR);
  331. {$else}
  332. repeat
  333. res:=fpread(PFilDes(FSem)^[0], b, 1);
  334. err:=fpgeterrno;
  335. until (res<>-1) or ((err<>ESysEINTR) and (err<>ESysEAgain));
  336. {$endif}
  337. end;
  338. procedure cSemaphorePost(const FSem: Pointer);
  339. {$if defined(has_sem_init) or defined(has_sem_open)}
  340. begin
  341. sem_post(PSemaphore(FSem));
  342. end;
  343. {$else}
  344. var
  345. writeres: cint;
  346. err: cint;
  347. b : byte;
  348. begin
  349. b:=0;
  350. repeat
  351. writeres:=fpwrite(PFilDes(FSem)^[1], b, 1);
  352. err:=fpgeterrno;
  353. until (writeres<>-1) or ((err<>ESysEINTR) and (err<>ESysEAgain));
  354. end;
  355. {$endif}
  356. {$if defined(has_sem_open) and not defined(has_sem_init)}
  357. function cIntSemaphoreOpen(const name: pchar; initvalue: boolean): Pointer;
  358. var
  359. err: cint;
  360. begin
  361. repeat
  362. cIntSemaphoreOpen := sem_open(name,O_CREAT,0,ord(initvalue));
  363. err:=fpgeterrno;
  364. until (ptrint(cIntSemaphoreOpen) <> SEM_FAILED) or (err <> ESysEINTR);
  365. if (ptrint(cIntSemaphoreOpen) <> SEM_FAILED) then
  366. { immediately unlink so the semaphore will be destroyed when the }
  367. { the process exits }
  368. sem_unlink(name)
  369. else
  370. cIntSemaphoreOpen:=NIL;
  371. end;
  372. {$endif}
  373. function cIntSemaphoreInit(initvalue: boolean): Pointer;
  374. {$if defined(has_sem_open) and not defined(has_sem_init)}
  375. var
  376. tid: string[31];
  377. semname: string[63];
  378. err: cint;
  379. {$endif}
  380. begin
  381. {$ifdef has_sem_init}
  382. cIntSemaphoreInit := GetMem(SizeOf(TSemaphore));
  383. if sem_init(PSemaphore(cIntSemaphoreInit), 0, ord(initvalue)) <> 0 then
  384. begin
  385. FreeMem(cIntSemaphoreInit);
  386. cIntSemaphoreInit:=NIL;
  387. end;
  388. {$else}
  389. {$ifdef has_sem_open}
  390. { avoid a potential temporary nameclash with another process/thread }
  391. str(fpGetPid,semname);
  392. str(ptruint(pthread_self),tid);
  393. semname:='/FPC'+semname+'T'+tid+#0;
  394. cIntSemaphoreInit:=cIntSemaphoreOpen(@semname[1],initvalue);
  395. {$else}
  396. cIntSemaphoreInit := GetMem(SizeOf(TFilDes));
  397. if (fppipe(PFilDes(cIntSemaphoreInit)^) <> 0) then
  398. begin
  399. FreeMem(cIntSemaphoreInit);
  400. cIntSemaphoreInit:=nil;
  401. end
  402. else if initvalue then
  403. cSemaphorePost(cIntSemaphoreInit);
  404. {$endif}
  405. {$endif}
  406. end;
  407. function cSemaphoreInit: Pointer;
  408. begin
  409. cSemaphoreInit:=cIntSemaphoreInit(false);
  410. end;
  411. procedure cSemaphoreDestroy(const FSem: Pointer);
  412. begin
  413. {$ifdef has_sem_init}
  414. sem_destroy(PSemaphore(FSem));
  415. FreeMem(FSem);
  416. {$else}
  417. {$ifdef has_sem_open}
  418. sem_close(PSemaphore(FSem));
  419. {$else has_sem_init}
  420. fpclose(PFilDes(FSem)^[0]);
  421. fpclose(PFilDes(FSem)^[1]);
  422. FreeMem(FSem);
  423. {$endif}
  424. {$endif}
  425. end;
  426. {*****************************************************************************
  427. Heap Mutex Protection
  428. *****************************************************************************}
  429. var
  430. HeapMutex : pthread_mutex_t;
  431. procedure PThreadHeapMutexInit;
  432. begin
  433. pthread_mutex_init(@heapmutex,nil);
  434. end;
  435. procedure PThreadHeapMutexDone;
  436. begin
  437. pthread_mutex_destroy(@heapmutex);
  438. end;
  439. procedure PThreadHeapMutexLock;
  440. begin
  441. pthread_mutex_lock(@heapmutex);
  442. end;
  443. procedure PThreadHeapMutexUnlock;
  444. begin
  445. pthread_mutex_unlock(@heapmutex);
  446. end;
  447. const
  448. PThreadMemoryMutexManager : TMemoryMutexManager = (
  449. MutexInit : @PThreadHeapMutexInit;
  450. MutexDone : @PThreadHeapMutexDone;
  451. MutexLock : @PThreadHeapMutexLock;
  452. MutexUnlock : @PThreadHeapMutexUnlock;
  453. );
  454. procedure InitHeapMutexes;
  455. begin
  456. SetMemoryMutexManager(PThreadMemoryMutexManager);
  457. end;
  458. type
  459. TPthreadMutex = pthread_mutex_t;
  460. Tbasiceventstate=record
  461. FSem: Pointer;
  462. FEventSection: TPthreadMutex;
  463. FManualReset: Boolean;
  464. end;
  465. plocaleventstate = ^tbasiceventstate;
  466. // peventstate=pointer;
  467. Const
  468. wrSignaled = 0;
  469. wrTimeout = 1;
  470. wrAbandoned= 2;
  471. wrError = 3;
  472. function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  473. var
  474. MAttr : pthread_mutexattr_t;
  475. res : cint;
  476. begin
  477. new(plocaleventstate(result));
  478. plocaleventstate(result)^.FManualReset:=AManualReset;
  479. {$ifdef has_sem_init}
  480. plocaleventstate(result)^.FSem:=cIntSemaphoreInit(true);
  481. if plocaleventstate(result)^.FSem=nil then
  482. begin
  483. FreeMem(result);
  484. runerror(6);
  485. end;
  486. {$else}
  487. {$ifdef has_sem_open}
  488. plocaleventstate(result)^.FSem:=cIntSemaphoreOpen(PChar(Name),InitialState);
  489. if (plocaleventstate(result)^.FSem = NIL) then
  490. begin
  491. FreeMem(result);
  492. runerror(6);
  493. end;
  494. {$else}
  495. plocaleventstate(result)^.FSem:=cSemaphoreInit;
  496. if (plocaleventstate(result)^.FSem = NIL) then
  497. begin
  498. FreeMem(result);
  499. runerror(6);
  500. end;
  501. if InitialState then
  502. cSemaphorePost(plocaleventstate(result)^.FSem);
  503. {$endif}
  504. {$endif}
  505. // plocaleventstate(result)^.feventsection:=nil;
  506. res:=pthread_mutexattr_init(@MAttr);
  507. if res=0 then
  508. begin
  509. res:=pthread_mutexattr_settype(@MAttr,longint(_PTHREAD_MUTEX_RECURSIVE));
  510. if Res=0 then
  511. Res:=pthread_mutex_init(@plocaleventstate(result)^.feventsection,@MAttr)
  512. else
  513. res:=pthread_mutex_init(@plocaleventstate(result)^.feventsection,nil);
  514. end
  515. else
  516. res:=pthread_mutex_init(@plocaleventstate(result)^.feventsection,nil);
  517. pthread_mutexattr_destroy(@MAttr);
  518. if res <> 0 then
  519. begin
  520. cSemaphoreDestroy(plocaleventstate(result)^.FSem);
  521. FreeMem(result);
  522. runerror(6);
  523. end;
  524. end;
  525. procedure Intbasiceventdestroy(state:peventstate);
  526. begin
  527. cSemaphoreDestroy(plocaleventstate(state)^.FSem);
  528. FreeMem(state);
  529. end;
  530. procedure IntbasiceventResetEvent(state:peventstate);
  531. {$if defined(has_sem_init) or defined(has_sem_open)}
  532. var
  533. res: cint;
  534. err: cint;
  535. begin
  536. repeat
  537. res:=sem_trywait(psem_t(plocaleventstate(state)^.FSem));
  538. err:=fpgeterrno;
  539. until (res<>0) and ((res<>-1) or (err<>ESysEINTR));
  540. {$else has_sem_init or has_sem_open}
  541. var
  542. fds: TFDSet;
  543. tv : timeval;
  544. begin
  545. tv.tv_sec:=0;
  546. tv.tv_usec:=0;
  547. fpFD_ZERO(fds);
  548. fpFD_SET(PFilDes(plocaleventstate(state)^.FSem)^[0],fds);
  549. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  550. Try
  551. while fpselect(PFilDes(plocaleventstate(state)^.FSem)^[0],@fds,nil,nil,@tv) > 0 do
  552. cSemaphoreWait(plocaleventstate(state)^.FSem);
  553. finally
  554. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  555. end;
  556. {$endif has_sem_init or has_sem_open}
  557. end;
  558. procedure IntbasiceventSetEvent(state:peventstate);
  559. Var
  560. {$if defined(has_sem_init) or defined(has_sem_open)}
  561. Value : Longint;
  562. res : cint;
  563. err : cint;
  564. {$else}
  565. fds: TFDSet;
  566. tv : timeval;
  567. {$endif}
  568. begin
  569. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  570. Try
  571. {$if defined(has_sem_init) or defined(has_sem_open)}
  572. if (sem_getvalue(plocaleventstate(state)^.FSem,@value) <> -1) then
  573. begin
  574. if Value=0 then
  575. cSemaphorePost(plocaleventstate(state)^.FSem);
  576. end
  577. else if (fpgeterrno = ESysENOSYS) then
  578. { not yet implemented on Mac OS X 10.4.8 }
  579. begin
  580. repeat
  581. res:=sem_trywait(psem_t(plocaleventstate(state)^.FSem));
  582. err:=fpgeterrno;
  583. until ((res<>-1) or (err<>ESysEINTR));
  584. { now we've either decreased the semaphore by 1 (if it was }
  585. { not zero), or we've done nothing (if it was already zero) }
  586. { -> increase by 1 and we have the same result as }
  587. { increasing by 1 only if it was 0 }
  588. cSemaphorePost(plocaleventstate(state)^.FSem);
  589. end
  590. else
  591. runerror(6);
  592. {$else has_sem_init or has_sem_open}
  593. tv.tv_sec:=0;
  594. tv.tv_usec:=0;
  595. fpFD_ZERO(fds);
  596. fpFD_SET(PFilDes(plocaleventstate(state)^.FSem)^[0],fds);
  597. if fpselect(PFilDes(plocaleventstate(state)^.FSem)^[0],@fds,nil,nil,@tv)=0 then
  598. cSemaphorePost(plocaleventstate(state)^.FSem);
  599. {$endif has_sem_init or has_sem_open}
  600. finally
  601. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  602. end;
  603. end;
  604. function IntbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  605. begin
  606. If TimeOut<>Cardinal($FFFFFFFF) then
  607. result:=wrError
  608. else
  609. begin
  610. cSemaphoreWait(plocaleventstate(state)^.FSem);
  611. result:=wrSignaled;
  612. if plocaleventstate(state)^.FManualReset then
  613. begin
  614. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  615. Try
  616. intbasiceventresetevent(State);
  617. cSemaphorePost(plocaleventstate(state)^.FSem);
  618. Finally
  619. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  620. end;
  621. end;
  622. end;
  623. end;
  624. function intRTLEventCreate: PRTLEvent;
  625. var p:pintrtlevent;
  626. begin
  627. new(p);
  628. pthread_cond_init(@p^.condvar, nil);
  629. pthread_mutex_init(@p^.mutex, nil);
  630. p^.isset:=false;
  631. result:=PRTLEVENT(p);
  632. end;
  633. procedure intRTLEventDestroy(AEvent: PRTLEvent);
  634. var p:pintrtlevent;
  635. begin
  636. p:=pintrtlevent(aevent);
  637. pthread_cond_destroy(@p^.condvar);
  638. pthread_mutex_destroy(@p^.mutex);
  639. dispose(p);
  640. end;
  641. procedure intRTLEventSetEvent(AEvent: PRTLEvent);
  642. var p:pintrtlevent;
  643. begin
  644. p:=pintrtlevent(aevent);
  645. pthread_mutex_lock(@p^.mutex);
  646. p^.isset:=true;
  647. pthread_cond_signal(@p^.condvar);
  648. pthread_mutex_unlock(@p^.mutex);
  649. end;
  650. procedure intRTLEventResetEvent(AEvent: PRTLEvent);
  651. var p:pintrtlevent;
  652. begin
  653. p:=pintrtlevent(aevent);
  654. pthread_mutex_lock(@p^.mutex);
  655. p^.isset:=false;
  656. pthread_mutex_unlock(@p^.mutex);
  657. end;
  658. procedure intRTLEventWaitFor(AEvent: PRTLEvent);
  659. var p:pintrtlevent;
  660. begin
  661. p:=pintrtlevent(aevent);
  662. pthread_mutex_lock(@p^.mutex);
  663. while not p^.isset do pthread_cond_wait(@p^.condvar, @p^.mutex);
  664. p^.isset:=false;
  665. pthread_mutex_unlock(@p^.mutex);
  666. end;
  667. procedure intRTLEventWaitForTimeout(AEvent: PRTLEvent;timeout : longint);
  668. var
  669. p : pintrtlevent;
  670. errres : cint;
  671. timespec : ttimespec;
  672. tnow : timeval;
  673. begin
  674. p:=pintrtlevent(aevent);
  675. fpgettimeofday(@tnow,nil);
  676. timespec.tv_sec:=tnow.tv_sec+(timeout div 1000);
  677. timespec.tv_nsec:=(timeout mod 1000)*1000000 + tnow.tv_usec*1000;
  678. if timespec.tv_nsec >= 1000000000 then
  679. begin
  680. inc(timespec.tv_sec);
  681. dec(timespec.tv_nsec, 1000000000);
  682. end;
  683. errres:=0;
  684. pthread_mutex_lock(@p^.mutex);
  685. while (not p^.isset) and
  686. (errres <> ESysETIMEDOUT) do
  687. begin
  688. errres:=pthread_cond_timedwait(@p^.condvar, @p^.mutex, @timespec);
  689. end;
  690. p^.isset:=false;
  691. pthread_mutex_unlock(@p^.mutex);
  692. end;
  693. type
  694. threadmethod = procedure of object;
  695. Function CInitThreads : Boolean;
  696. begin
  697. {$ifdef DEBUG_MT}
  698. Writeln('Entering InitThreads.');
  699. {$endif}
  700. {$ifndef dynpthreads}
  701. Result:=True;
  702. {$else}
  703. Result:=LoadPthreads;
  704. {$endif}
  705. ThreadID := TThreadID (pthread_self);
  706. {$ifdef DEBUG_MT}
  707. Writeln('InitThreads : ',Result);
  708. {$endif DEBUG_MT}
  709. end;
  710. Function CDoneThreads : Boolean;
  711. begin
  712. {$ifndef dynpthreads}
  713. Result:=True;
  714. {$else}
  715. Result:=UnloadPthreads;
  716. {$endif}
  717. end;
  718. Var
  719. CThreadManager : TThreadManager;
  720. Procedure SetCThreadManager;
  721. begin
  722. With CThreadManager do begin
  723. InitManager :=@CInitThreads;
  724. DoneManager :=@CDoneThreads;
  725. BeginThread :=@CBeginThread;
  726. EndThread :=@CEndThread;
  727. SuspendThread :=@CSuspendThread;
  728. ResumeThread :=@CResumeThread;
  729. KillThread :=@CKillThread;
  730. ThreadSwitch :=@CThreadSwitch;
  731. WaitForThreadTerminate :=@CWaitForThreadTerminate;
  732. ThreadSetPriority :=@CThreadSetPriority;
  733. ThreadGetPriority :=@CThreadGetPriority;
  734. GetCurrentThreadId :=@CGetCurrentThreadId;
  735. InitCriticalSection :=@CInitCriticalSection;
  736. DoneCriticalSection :=@CDoneCriticalSection;
  737. EnterCriticalSection :=@CEnterCriticalSection;
  738. LeaveCriticalSection :=@CLeaveCriticalSection;
  739. InitThreadVar :=@CInitThreadVar;
  740. RelocateThreadVar :=@CRelocateThreadVar;
  741. AllocateThreadVars :=@CAllocateThreadVars;
  742. ReleaseThreadVars :=@CReleaseThreadVars;
  743. BasicEventCreate :=@intBasicEventCreate;
  744. BasicEventDestroy :=@intBasicEventDestroy;
  745. BasicEventResetEvent :=@intBasicEventResetEvent;
  746. BasicEventSetEvent :=@intBasicEventSetEvent;
  747. BasiceventWaitFor :=@intBasiceventWaitFor;
  748. rtlEventCreate :=@intrtlEventCreate;
  749. rtlEventDestroy :=@intrtlEventDestroy;
  750. rtlEventSetEvent :=@intrtlEventSetEvent;
  751. rtlEventResetEvent :=@intrtlEventResetEvent;
  752. rtleventWaitForTimeout :=@intrtleventWaitForTimeout;
  753. rtleventWaitFor :=@intrtleventWaitFor;
  754. // semaphores
  755. SemaphoreInit :=@cSemaphoreInit;
  756. SemaphoreDestroy :=@cSemaphoreDestroy;
  757. SemaphoreWait :=@cSemaphoreWait;
  758. SemaphorePost :=@cSemaphorePost;
  759. end;
  760. SetThreadManager(CThreadManager);
  761. InitHeapMutexes;
  762. end;
  763. initialization
  764. if ThreadingAlreadyUsed then
  765. begin
  766. writeln('Threading has been used before cthreads was initialized.');
  767. writeln('Make cthreads one of the first units in your uses clause.');
  768. runerror(211);
  769. end;
  770. SetCThreadManager;
  771. finalization
  772. end.