systhrd.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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. { lazy initialize thread support }
  114. LazyInitThreading;
  115. IsMultiThread:=true;
  116. end;
  117. { the only way to pass data to the newly created thread
  118. in a MT safe way, is to use the heap }
  119. getmem(ti,sizeof(pthreadinfo));
  120. ti^.f:=ThreadFunction;
  121. ti^.p:=p;
  122. ti^.stklen:=stacksize;
  123. { call pthread_create }
  124. WRITE_DEBUG('SysBeginThread: Starting new thread'#13#10);
  125. pthread_attr_init(@thread_attr);
  126. pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
  127. // will fail under linux -- apparently unimplemented
  128. pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
  129. // don't create detached, we need to be able to join (waitfor) on
  130. // the newly created thread!
  131. //pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
  132. if pthread_create(@threadid, @thread_attr, @ThreadMain,ti) <> 0 then begin
  133. threadid := 0;
  134. end;
  135. SysBeginThread:=threadid;
  136. WRITE_DEBUG('SysBeginThread returning %d'#13#10,SysBeginThread);
  137. end;
  138. procedure SysEndThread(ExitCode : DWord);
  139. begin
  140. DoneThread;
  141. pthread_detach(pointer(pthread_self));
  142. pthread_exit(pointer(ExitCode));
  143. end;
  144. function SysSuspendThread (threadHandle : dword) : dword;
  145. begin
  146. {$Warning SuspendThread needs to be implemented}
  147. SysSuspendThread := $0FFFFFFFF;
  148. end;
  149. function SysResumeThread (threadHandle : dword) : dword;
  150. begin
  151. {$Warning ResumeThread needs to be implemented}
  152. SysResumeThread := $0FFFFFFFF;
  153. end;
  154. procedure SysThreadSwitch; {give time to other threads}
  155. begin
  156. pthread_yield;
  157. end;
  158. function SysKillThread (threadHandle : dword) : dword;
  159. begin
  160. pthread_detach(pointer(threadHandle));
  161. SysKillThread := pthread_cancel(Pointer(threadHandle));
  162. end;
  163. function SysWaitForThreadTerminate (threadHandle : dword; TimeoutMs : longint) : dword; {0=no timeout}
  164. var
  165. LResultP: Pointer;
  166. LResult: DWord;
  167. begin
  168. LResult := 0;
  169. LResultP := @LResult;
  170. WRITE_DEBUG('SysWaitForThreadTerminate: waiting for %d, timeout %d'#13#10,threadHandle,timeoutMS);
  171. pthread_join(Pointer(threadHandle), @LResultP);
  172. SysWaitForThreadTerminate := LResult;
  173. end;
  174. function SysThreadSetPriority (threadHandle : dword; Prio: longint): boolean; {-15..+15, 0=normal}
  175. begin
  176. {priority is ignored on netware}
  177. SysThreadSetPriority := true;
  178. end;
  179. function SysThreadGetPriority (threadHandle : dword): longint;
  180. begin
  181. {priority is ignored on netware}
  182. SysThreadGetPriority := 0;
  183. end;
  184. function SysGetCurrentThreadId : dword;
  185. begin
  186. SysGetCurrentThreadId:=dword(pthread_self);
  187. end;
  188. procedure SysSetThreadDebugNameA(threadHandle: TThreadID; const ThreadName: AnsiString);
  189. begin
  190. {$Warning SetThreadDebugName needs to be implemented}
  191. end;
  192. procedure SysSetThreadDebugNameU(threadHandle: TThreadID; const ThreadName: UnicodeString);
  193. begin
  194. {$Warning SetThreadDebugName needs to be implemented}
  195. end;
  196. {*****************************************************************************
  197. Delphi/Win32 compatibility
  198. *****************************************************************************}
  199. procedure SysInitCriticalSection(var CS);
  200. Var
  201. P : PRTLCriticalSection;
  202. begin
  203. P:=PRTLCriticalSection(@CS);
  204. FillChar (p^,sizeof(p^),0);
  205. pthread_mutex_init(P,NIL);
  206. end;
  207. procedure SysEnterCriticalSection(var CS);
  208. begin
  209. pthread_mutex_lock(PRTLCriticalSection(@CS));
  210. end;
  211. procedure SysLeaveCriticalSection(var CS);
  212. begin
  213. pthread_mutex_unlock(PRTLCriticalSection(@CS));
  214. end;
  215. procedure SysDoneCriticalSection(var CS);
  216. begin
  217. pthread_mutex_destroy(PRTLCriticalSection(@CS));
  218. end;
  219. type
  220. Tbasiceventstate=record
  221. FSem: Pointer;
  222. FManualReset: Boolean;
  223. FEventSection: ppthread_mutex_t;
  224. end;
  225. plocaleventstate = ^tbasiceventstate;
  226. // peventstate=pointer;
  227. Const
  228. wrSignaled = 0;
  229. wrTimeout = 1;
  230. wrAbandoned= 2;
  231. wrError = 3;
  232. function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  233. var
  234. MAttr : pthread_mutex_attr_t;
  235. res : cint;
  236. begin
  237. //new(plocaleventstate(result));
  238. getmem (result,sizeof(plocaleventstate));
  239. plocaleventstate(result)^.FManualReset:=AManualReset;
  240. plocaleventstate(result)^.FSem:=New(PSemaphore); //sem_t.
  241. // plocaleventstate(result)^.feventsection:=nil;
  242. res:=pthread_mutexattr_init(@MAttr);
  243. if Res=0 then
  244. try
  245. Res:=pthread_mutexattr_settype(@MAttr,longint(PTHREAD_MUTEX_RECURSIVE));
  246. if Res=0 then
  247. Res:=pthread_mutex_init(@plocaleventstate(result)^.feventsection,@MAttr);
  248. finally
  249. pthread_mutexattr_destroy(@MAttr);
  250. end;
  251. sem_init(psem_t(plocaleventstate(result)^.FSem),ord(False),Ord(InitialState));
  252. end;
  253. procedure Intbasiceventdestroy(state:peventstate);
  254. begin
  255. sem_destroy(psem_t( plocaleventstate(state)^.FSem));
  256. end;
  257. procedure IntbasiceventResetEvent(state:peventstate);
  258. begin
  259. While sem_trywait(psem_t( plocaleventstate(state)^.FSem))=0 do
  260. ;
  261. end;
  262. procedure IntbasiceventSetEvent(state:peventstate);
  263. Var
  264. Value : Longint;
  265. begin
  266. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  267. Try
  268. sem_getvalue(plocaleventstate(state)^.FSem,@value);
  269. if Value=0 then
  270. sem_post(psem_t( plocaleventstate(state)^.FSem));
  271. finally
  272. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  273. end;
  274. end;
  275. function IntbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  276. begin
  277. If TimeOut<>Cardinal($FFFFFFFF) then
  278. result:=wrError
  279. else
  280. begin
  281. sem_wait(psem_t(plocaleventstate(state)^.FSem));
  282. result:=wrSignaled;
  283. if plocaleventstate(state)^.FManualReset then
  284. begin
  285. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  286. Try
  287. intbasiceventresetevent(State);
  288. sem_post(psem_t( plocaleventstate(state)^.FSem));
  289. Finally
  290. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  291. end;
  292. end;
  293. end;
  294. end;
  295. Var
  296. NWThreadManager : TThreadManager;
  297. Procedure InitSystemThreads;
  298. begin
  299. With NWThreadManager do
  300. begin
  301. InitManager :=nil;
  302. DoneManager :=nil;
  303. BeginThread :=@SysBeginThread;
  304. EndThread :=@SysEndThread;
  305. SuspendThread :=@SysSuspendThread;
  306. ResumeThread :=@SysResumeThread;
  307. KillThread :=@SysKillThread;
  308. ThreadSwitch :=@SysThreadSwitch;
  309. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  310. ThreadSetPriority :=@SysThreadSetPriority;
  311. ThreadGetPriority :=@SysThreadGetPriority;
  312. GetCurrentThreadId :=@SysGetCurrentThreadId;
  313. SetThreadDebugNameA :=@SysSetThreadDebugNameA;
  314. SetThreadDebugNameU :=@SysSetThreadDebugNameU;
  315. InitCriticalSection :=@SysInitCriticalSection;
  316. DoneCriticalSection :=@SysDoneCriticalSection;
  317. EnterCriticalSection :=@SysEnterCriticalSection;
  318. LeaveCriticalSection :=@SysLeaveCriticalSection;
  319. InitThreadVar :=@SysInitThreadVar;
  320. RelocateThreadVar :=@SysRelocateThreadVar;
  321. AllocateThreadVars :=@SysAllocateThreadVars;
  322. ReleaseThreadVars :=@SysReleaseThreadVars;
  323. BasicEventCreate :=@intBasicEventCreate;
  324. BasicEventDestroy :=@intBasicEventDestroy;
  325. BasicEventResetEvent :=@intBasicEventResetEvent;
  326. BasicEventSetEvent :=@intBasicEventSetEvent;
  327. BasiceventWaitFor :=@intBasiceventWaitFor;
  328. end;
  329. SetThreadManager(NWThreadManager);
  330. ThVarAllocResourceTag := AllocateResourceTag(getnlmhandle,'Threadvar Memory',AllocSignature);
  331. NWSysSetThreadFunctions (@SysAllocateThreadVars,
  332. @SysReleaseThreadVars,
  333. @SysSetThreadDataAreaPtr);
  334. end;