systhrd.inc 14 KB

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