systhrd.inc 13 KB

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