systhrd.inc 13 KB

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