systhrds.pp 15 KB

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