cthreads.pp 24 KB

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