2
0

systhrd.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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. {*****************************************************************************
  187. Delphi/Win32 compatibility
  188. *****************************************************************************}
  189. procedure SysInitCriticalSection(var CS);
  190. Var
  191. P : PRTLCriticalSection;
  192. begin
  193. P:=PRTLCriticalSection(@CS);
  194. FillChar (p^,sizeof(p^),0);
  195. pthread_mutex_init(P,NIL);
  196. end;
  197. procedure SysEnterCriticalSection(var CS);
  198. begin
  199. pthread_mutex_lock(PRTLCriticalSection(@CS));
  200. end;
  201. procedure SysLeaveCriticalSection(var CS);
  202. begin
  203. pthread_mutex_unlock(PRTLCriticalSection(@CS));
  204. end;
  205. procedure SysDoneCriticalSection(var CS);
  206. begin
  207. pthread_mutex_destroy(PRTLCriticalSection(@CS));
  208. end;
  209. type
  210. Tbasiceventstate=record
  211. FSem: Pointer;
  212. FManualReset: Boolean;
  213. FEventSection: ppthread_mutex_t;
  214. end;
  215. plocaleventstate = ^tbasiceventstate;
  216. // peventstate=pointer;
  217. Const
  218. wrSignaled = 0;
  219. wrTimeout = 1;
  220. wrAbandoned= 2;
  221. wrError = 3;
  222. function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  223. var
  224. MAttr : pthread_mutex_attr_t;
  225. res : cint;
  226. begin
  227. //new(plocaleventstate(result));
  228. getmem (result,sizeof(plocaleventstate));
  229. plocaleventstate(result)^.FManualReset:=AManualReset;
  230. plocaleventstate(result)^.FSem:=New(PSemaphore); //sem_t.
  231. // plocaleventstate(result)^.feventsection:=nil;
  232. res:=pthread_mutexattr_init(@MAttr);
  233. if Res=0 then
  234. try
  235. Res:=pthread_mutexattr_settype(@MAttr,longint(PTHREAD_MUTEX_RECURSIVE));
  236. if Res=0 then
  237. Res:=pthread_mutex_init(@plocaleventstate(result)^.feventsection,@MAttr);
  238. finally
  239. pthread_mutexattr_destroy(@MAttr);
  240. end;
  241. sem_init(psem_t(plocaleventstate(result)^.FSem),ord(False),Ord(InitialState));
  242. end;
  243. procedure Intbasiceventdestroy(state:peventstate);
  244. begin
  245. sem_destroy(psem_t( plocaleventstate(state)^.FSem));
  246. end;
  247. procedure IntbasiceventResetEvent(state:peventstate);
  248. begin
  249. While sem_trywait(psem_t( plocaleventstate(state)^.FSem))=0 do
  250. ;
  251. end;
  252. procedure IntbasiceventSetEvent(state:peventstate);
  253. Var
  254. Value : Longint;
  255. begin
  256. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  257. Try
  258. sem_getvalue(plocaleventstate(state)^.FSem,@value);
  259. if Value=0 then
  260. sem_post(psem_t( plocaleventstate(state)^.FSem));
  261. finally
  262. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  263. end;
  264. end;
  265. function IntbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  266. begin
  267. If TimeOut<>Cardinal($FFFFFFFF) then
  268. result:=wrError
  269. else
  270. begin
  271. sem_wait(psem_t(plocaleventstate(state)^.FSem));
  272. result:=wrSignaled;
  273. if plocaleventstate(state)^.FManualReset then
  274. begin
  275. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  276. Try
  277. intbasiceventresetevent(State);
  278. sem_post(psem_t( plocaleventstate(state)^.FSem));
  279. Finally
  280. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  281. end;
  282. end;
  283. end;
  284. end;
  285. Var
  286. NWThreadManager : TThreadManager;
  287. Procedure InitSystemThreads;
  288. begin
  289. With NWThreadManager do
  290. begin
  291. InitManager :=nil;
  292. DoneManager :=nil;
  293. BeginThread :=@SysBeginThread;
  294. EndThread :=@SysEndThread;
  295. SuspendThread :=@SysSuspendThread;
  296. ResumeThread :=@SysResumeThread;
  297. KillThread :=@SysKillThread;
  298. ThreadSwitch :=@SysThreadSwitch;
  299. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  300. ThreadSetPriority :=@SysThreadSetPriority;
  301. ThreadGetPriority :=@SysThreadGetPriority;
  302. GetCurrentThreadId :=@SysGetCurrentThreadId;
  303. InitCriticalSection :=@SysInitCriticalSection;
  304. DoneCriticalSection :=@SysDoneCriticalSection;
  305. EnterCriticalSection :=@SysEnterCriticalSection;
  306. LeaveCriticalSection :=@SysLeaveCriticalSection;
  307. InitThreadVar :=@SysInitThreadVar;
  308. RelocateThreadVar :=@SysRelocateThreadVar;
  309. AllocateThreadVars :=@SysAllocateThreadVars;
  310. ReleaseThreadVars :=@SysReleaseThreadVars;
  311. BasicEventCreate :=@intBasicEventCreate;
  312. BasicEventDestroy :=@intBasicEventDestroy;
  313. BasicEventResetEvent :=@intBasicEventResetEvent;
  314. BasicEventSetEvent :=@intBasicEventSetEvent;
  315. BasiceventWaitFor :=@intBasiceventWaitFor;
  316. end;
  317. SetThreadManager(NWThreadManager);
  318. ThVarAllocResourceTag := AllocateResourceTag(getnlmhandle,'Threadvar Memory',AllocSignature);
  319. NWSysSetThreadFunctions (@SysAllocateThreadVars,
  320. @SysReleaseThreadVars,
  321. @SysSetThreadDataAreaPtr);
  322. end;