systhrd.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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. { ok, so this is a hack, but it works nicely. Just never use
  13. a multiline argument with WRITE_DEBUG! }
  14. {$MACRO ON}
  15. {$IFDEF DEBUG_MT}
  16. {$define WRITE_DEBUG := ConsolePrintf} // actually write something
  17. {$ELSE}
  18. {$define WRITE_DEBUG := //} // just comment out those lines
  19. {$ENDIF}
  20. {*****************************************************************************
  21. Threadvar support
  22. *****************************************************************************}
  23. const
  24. threadvarblocksize : dword = 0;
  25. thredvarsmainthread: pointer = nil; // to free the threadvars in the signal handler
  26. var
  27. TLSKey : pthread_key_t;
  28. ThVarAllocResourceTag : rtag_t;
  29. procedure SysInitThreadvar(var offset : dword;size : dword);
  30. begin
  31. offset:=threadvarblocksize;
  32. inc(threadvarblocksize,size);
  33. end;
  34. function SysRelocateThreadvar(offset : dword) : pointer;
  35. begin
  36. SysRelocateThreadvar:=pthread_getspecific(tlskey)+Offset;
  37. end;
  38. procedure SysAllocateThreadVars;
  39. var
  40. dataindex : pointer;
  41. begin
  42. { we've to allocate the memory from system }
  43. { because the FPC heap management uses }
  44. { exceptions which use threadvars but }
  45. { these aren't allocated yet ... }
  46. { allocate room on the heap for the thread vars }
  47. DataIndex:=_Alloc(threadvarblocksize,ThVarAllocResourceTag);
  48. //DataIndex:=Pointer(Fpmmap(nil,threadvarblocksize,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0));
  49. FillChar(DataIndex^,threadvarblocksize,0);
  50. pthread_setspecific(tlskey,dataindex);
  51. if thredvarsmainthread = nil then
  52. thredvarsmainthread := dataindex;
  53. WRITE_DEBUG ('SysAllocateThreadVars'#13#10);
  54. end;
  55. procedure SysReleaseThreadVars;
  56. begin
  57. WRITE_DEBUG ('SysReleaseThreadVars'#13#10);
  58. _Free (pthread_getspecific(tlskey));
  59. end;
  60. function SysSetThreadDataAreaPtr (newPtr:pointer):pointer;
  61. begin
  62. SysSetThreadDataAreaPtr := pthread_getspecific(tlskey); // return current
  63. if newPtr = nil then // if nil
  64. newPtr := thredvarsmainthread; // set main thread vars
  65. pthread_setspecific(tlskey,newPtr);
  66. end;
  67. {*****************************************************************************
  68. Thread starting
  69. *****************************************************************************}
  70. type
  71. pthreadinfo = ^tthreadinfo;
  72. tthreadinfo = record
  73. f : tthreadfunc;
  74. p : pointer;
  75. stklen : cardinal;
  76. end;
  77. procedure DoneThread;
  78. begin
  79. { Release Threadvars }
  80. WRITE_DEBUG('DoneThread, releasing threadvars'#13#10);
  81. SysReleaseThreadVars;
  82. end;
  83. function ThreadMain(param : pointer) : pointer;cdecl;
  84. var
  85. ti : tthreadinfo;
  86. begin
  87. WRITE_DEBUG('New thread started, initing threadvars'#13#10);
  88. { Allocate local thread vars, this must be the first thing,
  89. because the exception management and io depends on threadvars }
  90. SysAllocateThreadVars;
  91. { Copy parameter to local data }
  92. WRITE_DEBUG('New thread started, initialising ...'#13#10);
  93. ti:=pthreadinfo(param)^;
  94. dispose(pthreadinfo(param));
  95. { Initialize thread }
  96. InitThread(ti.stklen);
  97. { Start thread function }
  98. WRITE_DEBUG('Jumping to thread function'#13#10);
  99. ThreadMain:=pointer(ti.f(ti.p));
  100. DoneThread;
  101. //pthread_detach(pointer(pthread_self));
  102. pthread_exit (nil);
  103. end;
  104. function SysBeginThread(sa : Pointer;stacksize : SizeUInt;
  105. ThreadFunction : tthreadfunc;p : pointer;
  106. creationFlags : dword; var ThreadId : THandle) : DWord;
  107. var
  108. ti : pthreadinfo;
  109. thread_attr : pthread_attr_t;
  110. begin
  111. WRITE_DEBUG('SysBeginThread: Creating new thread'#13#10);
  112. { Initialize multithreading if not done }
  113. if not IsMultiThread then
  114. begin
  115. { We're still running in single thread mode, setup the TLS }
  116. pthread_key_create(@TLSKey,nil);
  117. InitThreadVars(@SysRelocateThreadvar);
  118. IsMultiThread:=true;
  119. end;
  120. { the only way to pass data to the newly created thread
  121. in a MT safe way, is to use the heap }
  122. getmem(ti,sizeof(pthreadinfo));
  123. ti^.f:=ThreadFunction;
  124. ti^.p:=p;
  125. ti^.stklen:=stacksize;
  126. { call pthread_create }
  127. WRITE_DEBUG('SysBeginThread: Starting new thread'#13#10);
  128. pthread_attr_init(@thread_attr);
  129. pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
  130. // will fail under linux -- apparently unimplemented
  131. pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
  132. // don't create detached, we need to be able to join (waitfor) on
  133. // the newly created thread!
  134. //pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
  135. if pthread_create(@threadid, @thread_attr, @ThreadMain,ti) <> 0 then begin
  136. threadid := 0;
  137. end;
  138. SysBeginThread:=threadid;
  139. WRITE_DEBUG('SysBeginThread returning %d'#13#10,SysBeginThread);
  140. end;
  141. procedure SysEndThread(ExitCode : DWord);
  142. begin
  143. DoneThread;
  144. pthread_detach(pointer(pthread_self));
  145. pthread_exit(pointer(ExitCode));
  146. end;
  147. function SysSuspendThread (threadHandle : dword) : dword;
  148. begin
  149. {$Warning SuspendThread needs to be implemented}
  150. SysSuspendThread := $0FFFFFFFF;
  151. end;
  152. function SysResumeThread (threadHandle : dword) : dword;
  153. begin
  154. {$Warning ResumeThread needs to be implemented}
  155. SysResumeThread := $0FFFFFFFF;
  156. end;
  157. procedure SysThreadSwitch; {give time to other threads}
  158. begin
  159. pthread_yield;
  160. end;
  161. function SysKillThread (threadHandle : dword) : dword;
  162. begin
  163. pthread_detach(pointer(threadHandle));
  164. SysKillThread := pthread_cancel(Pointer(threadHandle));
  165. end;
  166. function SysWaitForThreadTerminate (threadHandle : dword; TimeoutMs : longint) : dword; {0=no timeout}
  167. var
  168. LResultP: Pointer;
  169. LResult: DWord;
  170. begin
  171. LResult := 0;
  172. LResultP := @LResult;
  173. WRITE_DEBUG('SysWaitForThreadTerminate: waiting for %d, timeout %d'#13#10,threadHandle,timeoutMS);
  174. pthread_join(Pointer(threadHandle), @LResultP);
  175. SysWaitForThreadTerminate := LResult;
  176. end;
  177. function SysThreadSetPriority (threadHandle : dword; Prio: longint): boolean; {-15..+15, 0=normal}
  178. begin
  179. {priority is ignored on netware}
  180. SysThreadSetPriority := true;
  181. end;
  182. function SysThreadGetPriority (threadHandle : dword): longint;
  183. begin
  184. {priority is ignored on netware}
  185. SysThreadGetPriority := 0;
  186. end;
  187. function SysGetCurrentThreadId : dword;
  188. begin
  189. SysGetCurrentThreadId:=dword(pthread_self);
  190. end;
  191. {*****************************************************************************
  192. Delphi/Win32 compatibility
  193. *****************************************************************************}
  194. procedure SysInitCriticalSection(var CS);
  195. Var
  196. P : PRTLCriticalSection;
  197. begin
  198. P:=PRTLCriticalSection(@CS);
  199. FillChar (p^,sizeof(p^),0);
  200. pthread_mutex_init(P,NIL);
  201. end;
  202. procedure SysEnterCriticalSection(var CS);
  203. begin
  204. pthread_mutex_lock(PRTLCriticalSection(@CS));
  205. end;
  206. procedure SysLeaveCriticalSection(var CS);
  207. begin
  208. pthread_mutex_unlock(PRTLCriticalSection(@CS));
  209. end;
  210. procedure SysDoneCriticalSection(var CS);
  211. begin
  212. pthread_mutex_destroy(PRTLCriticalSection(@CS));
  213. end;
  214. {*****************************************************************************
  215. Heap Mutex Protection
  216. *****************************************************************************}
  217. var
  218. HeapMutex : pthread_mutex_t;
  219. procedure PThreadHeapMutexInit;
  220. begin
  221. pthread_mutex_init(@heapmutex,nil);
  222. end;
  223. procedure PThreadHeapMutexDone;
  224. begin
  225. pthread_mutex_destroy(@heapmutex);
  226. end;
  227. procedure PThreadHeapMutexLock;
  228. begin
  229. pthread_mutex_lock(@heapmutex);
  230. end;
  231. procedure PThreadHeapMutexUnlock;
  232. begin
  233. pthread_mutex_unlock(@heapmutex);
  234. end;
  235. const
  236. PThreadMemoryMutexManager : TMemoryMutexManager = (
  237. MutexInit : @PThreadHeapMutexInit;
  238. MutexDone : @PThreadHeapMutexDone;
  239. MutexLock : @PThreadHeapMutexLock;
  240. MutexUnlock : @PThreadHeapMutexUnlock;
  241. );
  242. procedure InitHeapMutexes;
  243. begin
  244. SetMemoryMutexManager(PThreadMemoryMutexManager);
  245. end;
  246. type
  247. Tbasiceventstate=record
  248. FSem: Pointer;
  249. FManualReset: Boolean;
  250. FEventSection: ppthread_mutex_t;
  251. end;
  252. plocaleventstate = ^tbasiceventstate;
  253. // peventstate=pointer;
  254. Const
  255. wrSignaled = 0;
  256. wrTimeout = 1;
  257. wrAbandoned= 2;
  258. wrError = 3;
  259. function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  260. var
  261. MAttr : pthread_mutex_attr_t;
  262. res : cint;
  263. begin
  264. //new(plocaleventstate(result));
  265. getmem (result,sizeof(plocaleventstate));
  266. plocaleventstate(result)^.FManualReset:=AManualReset;
  267. plocaleventstate(result)^.FSem:=New(PSemaphore); //sem_t.
  268. // plocaleventstate(result)^.feventsection:=nil;
  269. res:=pthread_mutexattr_init(@MAttr);
  270. if Res=0 then
  271. try
  272. Res:=pthread_mutexattr_settype(@MAttr,longint(PTHREAD_MUTEX_RECURSIVE));
  273. if Res=0 then
  274. Res:=pthread_mutex_init(@plocaleventstate(result)^.feventsection,@MAttr);
  275. finally
  276. pthread_mutexattr_destroy(@MAttr);
  277. end;
  278. sem_init(psem_t(plocaleventstate(result)^.FSem),ord(False),Ord(InitialState));
  279. end;
  280. procedure Intbasiceventdestroy(state:peventstate);
  281. begin
  282. sem_destroy(psem_t( plocaleventstate(state)^.FSem));
  283. end;
  284. procedure IntbasiceventResetEvent(state:peventstate);
  285. begin
  286. While sem_trywait(psem_t( plocaleventstate(state)^.FSem))=0 do
  287. ;
  288. end;
  289. procedure IntbasiceventSetEvent(state:peventstate);
  290. Var
  291. Value : Longint;
  292. begin
  293. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  294. Try
  295. sem_getvalue(plocaleventstate(state)^.FSem,@value);
  296. if Value=0 then
  297. sem_post(psem_t( plocaleventstate(state)^.FSem));
  298. finally
  299. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  300. end;
  301. end;
  302. function IntbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  303. begin
  304. If TimeOut<>Cardinal($FFFFFFFF) then
  305. result:=wrError
  306. else
  307. begin
  308. sem_wait(psem_t(plocaleventstate(state)^.FSem));
  309. result:=wrSignaled;
  310. if plocaleventstate(state)^.FManualReset then
  311. begin
  312. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  313. Try
  314. intbasiceventresetevent(State);
  315. sem_post(psem_t( plocaleventstate(state)^.FSem));
  316. Finally
  317. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  318. end;
  319. end;
  320. end;
  321. end;
  322. Var
  323. NWThreadManager : TThreadManager;
  324. Procedure InitSystemThreads;
  325. begin
  326. With NWThreadManager do
  327. begin
  328. InitManager :=nil;
  329. DoneManager :=nil;
  330. BeginThread :=@SysBeginThread;
  331. EndThread :=@SysEndThread;
  332. SuspendThread :=@SysSuspendThread;
  333. ResumeThread :=@SysResumeThread;
  334. KillThread :=@SysKillThread;
  335. ThreadSwitch :=@SysThreadSwitch;
  336. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  337. ThreadSetPriority :=@SysThreadSetPriority;
  338. ThreadGetPriority :=@SysThreadGetPriority;
  339. GetCurrentThreadId :=@SysGetCurrentThreadId;
  340. InitCriticalSection :=@SysInitCriticalSection;
  341. DoneCriticalSection :=@SysDoneCriticalSection;
  342. EnterCriticalSection :=@SysEnterCriticalSection;
  343. LeaveCriticalSection :=@SysLeaveCriticalSection;
  344. InitThreadVar :=@SysInitThreadVar;
  345. RelocateThreadVar :=@SysRelocateThreadVar;
  346. AllocateThreadVars :=@SysAllocateThreadVars;
  347. ReleaseThreadVars :=@SysReleaseThreadVars;
  348. BasicEventCreate :=@intBasicEventCreate;
  349. BasicEventDestroy :=@intBasicEventDestroy;
  350. BasicEventResetEvent :=@intBasicEventResetEvent;
  351. BasicEventSetEvent :=@intBasicEventSetEvent;
  352. BasiceventWaitFor :=@intBasiceventWaitFor;
  353. end;
  354. SetThreadManager(NWThreadManager);
  355. InitHeapMutexes;
  356. ThVarAllocResourceTag := AllocateResourceTag(getnlmhandle,'Threadvar Memory',AllocSignature);
  357. NWSysSetThreadFunctions (@SysAllocateThreadVars,
  358. @SysReleaseThreadVars,
  359. @SysSetThreadDataAreaPtr);
  360. end;