systhrds.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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. netware (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. {$mode objfpc}
  14. unit systhrds;
  15. interface
  16. {$S-}
  17. //Procedure SetCThreadManager;
  18. { Posix compliant definition }
  19. uses Libc;
  20. type
  21. PRTLCriticalSection = Ppthread_mutex_t;
  22. TRTLCriticalSection = pthread_mutex_t;
  23. {$i threadh.inc}
  24. implementation
  25. {*****************************************************************************
  26. Generic overloaded
  27. *****************************************************************************}
  28. {$i thread.inc}
  29. {*****************************************************************************
  30. Threadvar support
  31. *****************************************************************************}
  32. {$ifdef HASTHREADVAR}
  33. const
  34. threadvarblocksize : dword = 0;
  35. var
  36. TLSKey : pthread_key_t;
  37. ThVarAllocResourceTag : rtag_t;
  38. procedure SysInitThreadvar(var offset : dword;size : dword);
  39. begin
  40. offset:=threadvarblocksize;
  41. inc(threadvarblocksize,size);
  42. end;
  43. function SysRelocateThreadvar(offset : dword) : pointer;
  44. begin
  45. SysRelocateThreadvar:=pthread_getspecific(tlskey)+Offset;
  46. end;
  47. procedure SysAllocateThreadVars;
  48. var
  49. dataindex : pointer;
  50. begin
  51. { we've to allocate the memory from system }
  52. { because the FPC heap management uses }
  53. { exceptions which use threadvars but }
  54. { these aren't allocated yet ... }
  55. { allocate room on the heap for the thread vars }
  56. DataIndex:=_Alloc(threadvarblocksize,ThVarAllocResourceTag);
  57. //DataIndex:=Pointer(Fpmmap(nil,threadvarblocksize,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0));
  58. FillChar(DataIndex^,threadvarblocksize,0);
  59. pthread_setspecific(tlskey,dataindex);
  60. end;
  61. procedure SysReleaseThreadVars;
  62. begin
  63. _Free (pthread_getspecific(tlskey));
  64. end;
  65. { Include OS independent Threadvar initialization }
  66. {$i threadvr.inc}
  67. {$endif HASTHREADVAR}
  68. {*****************************************************************************
  69. Thread starting
  70. *****************************************************************************}
  71. type
  72. pthreadinfo = ^tthreadinfo;
  73. tthreadinfo = record
  74. f : tthreadfunc;
  75. p : pointer;
  76. stklen : cardinal;
  77. end;
  78. procedure DoneThread;
  79. begin
  80. { Release Threadvars }
  81. {$ifdef HASTHREADVAR}
  82. SysReleaseThreadVars;
  83. {$endif HASTHREADVAR}
  84. end;
  85. function ThreadMain(param : pointer) : pointer;cdecl;
  86. var
  87. ti : tthreadinfo;
  88. {$ifdef DEBUG_MT}
  89. // in here, don't use write/writeln before having called
  90. // InitThread! I wonder if anyone ever debugged these routines,
  91. // because they will have crashed if DEBUG_MT was enabled!
  92. // this took me the good part of an hour to figure out
  93. // why it was crashing all the time!
  94. // this is kind of a workaround, we simply write(2) to fd 0
  95. s: string[100]; // not an ansistring
  96. {$endif DEBUG_MT}
  97. begin
  98. {$ifdef DEBUG_MT}
  99. s := 'New thread started, initing threadvars'#10;
  100. fpwrite(0,s[1],length(s));
  101. {$endif DEBUG_MT}
  102. {$ifdef HASTHREADVAR}
  103. { Allocate local thread vars, this must be the first thing,
  104. because the exception management and io depends on threadvars }
  105. SysAllocateThreadVars;
  106. {$endif HASTHREADVAR}
  107. { Copy parameter to local data }
  108. {$ifdef DEBUG_MT}
  109. s := 'New thread started, initialising ...'#10;
  110. fpwrite(0,s[1],length(s));
  111. {$endif DEBUG_MT}
  112. ti:=pthreadinfo(param)^;
  113. dispose(pthreadinfo(param));
  114. { Initialize thread }
  115. InitThread(ti.stklen);
  116. { Start thread function }
  117. {$ifdef DEBUG_MT}
  118. writeln('Jumping to thread function');
  119. {$endif DEBUG_MT}
  120. ThreadMain:=pointer(ti.f(ti.p));
  121. DoneThread;
  122. pthread_detach(pointer(pthread_self));
  123. end;
  124. function SysBeginThread(sa : Pointer;stacksize : dword;
  125. ThreadFunction : tthreadfunc;p : pointer;
  126. creationFlags : dword; var ThreadId : THandle) : DWord;
  127. var
  128. ti : pthreadinfo;
  129. thread_attr : pthread_attr_t;
  130. begin
  131. {$ifdef DEBUG_MT}
  132. writeln('Creating new thread');
  133. {$endif DEBUG_MT}
  134. { Initialize multithreading if not done }
  135. if not IsMultiThread then
  136. begin
  137. {$ifdef HASTHREADVAR}
  138. { We're still running in single thread mode, setup the TLS }
  139. pthread_key_create(@TLSKey,nil);
  140. InitThreadVars(@SysRelocateThreadvar);
  141. {$endif HASTHREADVAR}
  142. IsMultiThread:=true;
  143. end;
  144. { the only way to pass data to the newly created thread
  145. in a MT safe way, is to use the heap }
  146. getmem(ti,sizeof(pthreadinfo));
  147. ti^.f:=ThreadFunction;
  148. ti^.p:=p;
  149. ti^.stklen:=stacksize;
  150. { call pthread_create }
  151. {$ifdef DEBUG_MT}
  152. writeln('Starting new thread');
  153. {$endif DEBUG_MT}
  154. pthread_attr_init(@thread_attr);
  155. pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
  156. // will fail under linux -- apparently unimplemented
  157. pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
  158. // don't create detached, we need to be able to join (waitfor) on
  159. // the newly created thread!
  160. //pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
  161. if pthread_create(@threadid, @thread_attr, @ThreadMain,ti) <> 0 then begin
  162. threadid := 0;
  163. end;
  164. SysBeginThread:=threadid;
  165. {$ifdef DEBUG_MT}
  166. writeln('BeginThread returning ',SysBeginThread);
  167. {$endif DEBUG_MT}
  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. end;
  179. function SysResumeThread (threadHandle : dword) : dword;
  180. begin
  181. {$Warning ResumeThread needs to be implemented}
  182. end;
  183. procedure SysThreadSwitch; {give time to other threads}
  184. begin
  185. {extern int pthread_yield (void) __THROW;}
  186. {$Warning ThreadSwitch needs to be implemented}
  187. end;
  188. function SysKillThread (threadHandle : dword) : dword;
  189. begin
  190. pthread_detach(pointer(threadHandle));
  191. SysKillThread := pthread_cancel(Pointer(threadHandle));
  192. end;
  193. function SysWaitForThreadTerminate (threadHandle : dword; TimeoutMs : longint) : dword; {0=no timeout}
  194. var
  195. LResultP: Pointer;
  196. LResult: DWord;
  197. begin
  198. LResult := 0;
  199. LResultP := @LResult;
  200. pthread_join(Pointer(threadHandle), @LResultP);
  201. SysWaitForThreadTerminate := LResult;
  202. end;
  203. function SysThreadSetPriority (threadHandle : dword; Prio: longint): boolean; {-15..+15, 0=normal}
  204. begin
  205. {$Warning ThreadSetPriority needs to be implemented}
  206. end;
  207. function SysThreadGetPriority (threadHandle : dword): Integer;
  208. begin
  209. {$Warning ThreadGetPriority needs to be implemented}
  210. end;
  211. function SysGetCurrentThreadId : dword;
  212. begin
  213. SysGetCurrentThreadId:=dword(pthread_self);
  214. end;
  215. {*****************************************************************************
  216. Delphi/Win32 compatibility
  217. *****************************************************************************}
  218. procedure SysInitCriticalSection(var CS);
  219. Var
  220. P : PRTLCriticalSection;
  221. begin
  222. P:=PRTLCriticalSection(@CS);
  223. FillChar (p^,sizeof(p^),0);
  224. pthread_mutex_init(P,NIL);
  225. end;
  226. procedure SysEnterCriticalSection(var CS);
  227. begin
  228. pthread_mutex_lock(PRTLCriticalSection(@CS));
  229. end;
  230. procedure SysLeaveCriticalSection(var CS);
  231. begin
  232. pthread_mutex_unlock(PRTLCriticalSection(@CS));
  233. end;
  234. procedure SysDoneCriticalSection(var CS);
  235. begin
  236. pthread_mutex_destroy(PRTLCriticalSection(@CS));
  237. end;
  238. {*****************************************************************************
  239. Heap Mutex Protection
  240. *****************************************************************************}
  241. var
  242. HeapMutex : pthread_mutex_t;
  243. procedure PThreadHeapMutexInit;
  244. begin
  245. pthread_mutex_init(@heapmutex,nil);
  246. end;
  247. procedure PThreadHeapMutexDone;
  248. begin
  249. pthread_mutex_destroy(@heapmutex);
  250. end;
  251. procedure PThreadHeapMutexLock;
  252. begin
  253. pthread_mutex_lock(@heapmutex);
  254. end;
  255. procedure PThreadHeapMutexUnlock;
  256. begin
  257. pthread_mutex_unlock(@heapmutex);
  258. end;
  259. const
  260. PThreadMemoryMutexManager : TMemoryMutexManager = (
  261. MutexInit : @PThreadHeapMutexInit;
  262. MutexDone : @PThreadHeapMutexDone;
  263. MutexLock : @PThreadHeapMutexLock;
  264. MutexUnlock : @PThreadHeapMutexUnlock;
  265. );
  266. procedure InitHeapMutexes;
  267. begin
  268. SetMemoryMutexManager(PThreadMemoryMutexManager);
  269. end;
  270. type
  271. TPthreadMutex = ppthread_mutex_t;
  272. Tbasiceventstate=record
  273. FSem: Pointer;
  274. FManualReset: Boolean;
  275. FEventSection: TPthreadMutex;
  276. end;
  277. plocaleventstate = ^tbasiceventstate;
  278. // peventstate=pointer;
  279. Const
  280. wrSignaled = 0;
  281. wrTimeout = 1;
  282. wrAbandoned= 2;
  283. wrError = 3;
  284. function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
  285. var
  286. MAttr : pthread_mutex_attr_t;
  287. res : cint;
  288. begin
  289. //new(plocaleventstate(result));
  290. getmem (result,sizeof(plocaleventstate));
  291. plocaleventstate(result)^.FManualReset:=AManualReset;
  292. plocaleventstate(result)^.FSem:=New(PSemaphore); //sem_t.
  293. // plocaleventstate(result)^.feventsection:=nil;
  294. res:=pthread_mutexattr_init(@MAttr);
  295. if Res=0 then
  296. try
  297. Res:=pthread_mutexattr_settype(@MAttr,longint(PTHREAD_MUTEX_RECURSIVE));
  298. if Res=0 then
  299. Res:=pthread_mutex_init(@plocaleventstate(result)^.feventsection,@MAttr);
  300. finally
  301. pthread_mutexattr_destroy(@MAttr);
  302. end;
  303. sem_init(psem_t(plocaleventstate(result)^.FSem),ord(False),Ord(InitialState));
  304. end;
  305. procedure Intbasiceventdestroy(state:peventstate);
  306. begin
  307. sem_destroy(psem_t( plocaleventstate(state)^.FSem));
  308. end;
  309. procedure IntbasiceventResetEvent(state:peventstate);
  310. begin
  311. While sem_trywait(psem_t( plocaleventstate(state)^.FSem))=0 do
  312. ;
  313. end;
  314. procedure IntbasiceventSetEvent(state:peventstate);
  315. Var
  316. Value : Longint;
  317. begin
  318. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  319. Try
  320. sem_getvalue(plocaleventstate(state)^.FSem,@value);
  321. if Value=0 then
  322. sem_post(psem_t( plocaleventstate(state)^.FSem));
  323. finally
  324. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  325. end;
  326. end;
  327. function IntbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
  328. begin
  329. If TimeOut<>Cardinal($FFFFFFFF) then
  330. result:=wrError
  331. else
  332. begin
  333. sem_wait(psem_t(plocaleventstate(state)^.FSem));
  334. result:=wrSignaled;
  335. if plocaleventstate(state)^.FManualReset then
  336. begin
  337. pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
  338. Try
  339. intbasiceventresetevent(State);
  340. sem_post(psem_t( plocaleventstate(state)^.FSem));
  341. Finally
  342. pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
  343. end;
  344. end;
  345. end;
  346. end;
  347. Var
  348. NWThreadManager : TThreadManager;
  349. Procedure SetNWThreadManager;
  350. begin
  351. With NWThreadManager do
  352. begin
  353. InitManager :=nil;
  354. DoneManager :=nil;
  355. BeginThread :=@SysBeginThread;
  356. EndThread :=@SysEndThread;
  357. SuspendThread :=@SysSuspendThread;
  358. ResumeThread :=@SysResumeThread;
  359. KillThread :=@SysKillThread;
  360. ThreadSwitch :=@SysThreadSwitch;
  361. WaitForThreadTerminate :=@SysWaitForThreadTerminate;
  362. ThreadSetPriority :=@SysThreadSetPriority;
  363. ThreadGetPriority :=@SysThreadGetPriority;
  364. GetCurrentThreadId :=@SysGetCurrentThreadId;
  365. InitCriticalSection :=@SysInitCriticalSection;
  366. DoneCriticalSection :=@SysDoneCriticalSection;
  367. EnterCriticalSection :=@SysEnterCriticalSection;
  368. LeaveCriticalSection :=@SysLeaveCriticalSection;
  369. {$ifdef hasthreadvar}
  370. InitThreadVar :=@SysInitThreadVar;
  371. RelocateThreadVar :=@SysRelocateThreadVar;
  372. AllocateThreadVars :=@SysAllocateThreadVars;
  373. ReleaseThreadVars :=@SysReleaseThreadVars;
  374. {$endif}
  375. BasicEventCreate :=@intBasicEventCreate;
  376. BasicEventDestroy :=@intBasicEventDestroy;
  377. BasicEventResetEvent :=@intBasicEventResetEvent;
  378. BasicEventSetEvent :=@intBasicEventSetEvent;
  379. BasiceventWaitFor :=@intBasiceventWaitFor;
  380. end;
  381. SetThreadManager(NWThreadManager);
  382. InitHeapMutexes;
  383. end;
  384. initialization
  385. {$ifdef HASTHREADVAR}
  386. ThVarAllocResourceTag := AllocateResourceTag(getnlmhandle,'Threadvar Memory',AllocSignature);
  387. {$endif}
  388. SetNWThreadManager;
  389. end.
  390. {
  391. $Log$
  392. Revision 1.1 2004-09-05 20:58:47 armin
  393. * first rtl version for netwlibc
  394. }