2
$Id: systhrd.inc,v 1.2 2005/02/14 17:13:30 peter Exp $
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.
7
Linux (pthreads) threading support implementation
9
See the file COPYING.FPC, included in this distribution,
10
for details about the copyright.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
**********************************************************************}
18
{ ok, so this is a hack, but it works nicely. Just never use
19
a multiline argument with WRITE_DEBUG! }
22
{$define WRITE_DEBUG := ConsolePrintf} // actually write something
24
{$define WRITE_DEBUG := //} // just comment out those lines
27
{*****************************************************************************
29
*****************************************************************************}
33
threadvarblocksize : dword = 0;
34
thredvarsmainthread: pointer = nil; // to free the threadvars in the signal handler
38
TLSKey : pthread_key_t;
39
ThVarAllocResourceTag : rtag_t;
41
procedure SysInitThreadvar(var offset : dword;size : dword);
43
offset:=threadvarblocksize;
44
inc(threadvarblocksize,size);
47
function SysRelocateThreadvar(offset : dword) : pointer;
49
SysRelocateThreadvar:=pthread_getspecific(tlskey)+Offset;
53
procedure SysAllocateThreadVars;
57
{ we've to allocate the memory from system }
58
{ because the FPC heap management uses }
59
{ exceptions which use threadvars but }
60
{ these aren't allocated yet ... }
61
{ allocate room on the heap for the thread vars }
62
DataIndex:=_Alloc(threadvarblocksize,ThVarAllocResourceTag);
63
//DataIndex:=Pointer(Fpmmap(nil,threadvarblocksize,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0));
64
FillChar(DataIndex^,threadvarblocksize,0);
65
pthread_setspecific(tlskey,dataindex);
66
if thredvarsmainthread = nil then
67
thredvarsmainthread := dataindex;
68
WRITE_DEBUG ('SysAllocateThreadVars'#13#10);
72
procedure SysReleaseThreadVars;
74
WRITE_DEBUG ('SysReleaseThreadVars'#13#10);
75
_Free (pthread_getspecific(tlskey));
78
function SysSetThreadDataAreaPtr (newPtr:pointer):pointer;
80
SysSetThreadDataAreaPtr := pthread_getspecific(tlskey); // return current
81
if newPtr = nil then // if nil
82
newPtr := thredvarsmainthread; // set main thread vars
83
pthread_setspecific(tlskey,newPtr);
89
{*****************************************************************************
91
*****************************************************************************}
94
pthreadinfo = ^tthreadinfo;
101
procedure DoneThread;
103
{ Release Threadvars }
104
{$ifdef HASTHREADVAR}
105
WRITE_DEBUG('DoneThread, releasing threadvars'#13#10);
106
SysReleaseThreadVars;
107
{$endif HASTHREADVAR}
111
function ThreadMain(param : pointer) : pointer;cdecl;
115
WRITE_DEBUG('New thread started, initing threadvars'#13#10);
116
{$ifdef HASTHREADVAR}
117
{ Allocate local thread vars, this must be the first thing,
118
because the exception management and io depends on threadvars }
119
SysAllocateThreadVars;
120
{$endif HASTHREADVAR}
121
{ Copy parameter to local data }
122
WRITE_DEBUG('New thread started, initialising ...'#13#10);
123
ti:=pthreadinfo(param)^;
124
dispose(pthreadinfo(param));
125
{ Initialize thread }
126
InitThread(ti.stklen);
127
{ Start thread function }
128
WRITE_DEBUG('Jumping to thread function'#13#10);
129
ThreadMain:=pointer(ti.f(ti.p));
131
//pthread_detach(pointer(pthread_self));
136
function SysBeginThread(sa : Pointer;stacksize : dword;
137
ThreadFunction : tthreadfunc;p : pointer;
138
creationFlags : dword; var ThreadId : THandle) : DWord;
141
thread_attr : pthread_attr_t;
143
WRITE_DEBUG('SysBeginThread: Creating new thread'#13#10);
144
{ Initialize multithreading if not done }
145
if not IsMultiThread then
147
{$ifdef HASTHREADVAR}
148
{ We're still running in single thread mode, setup the TLS }
149
pthread_key_create(@TLSKey,nil);
150
InitThreadVars(@SysRelocateThreadvar);
151
{$endif HASTHREADVAR}
154
{ the only way to pass data to the newly created thread
155
in a MT safe way, is to use the heap }
156
getmem(ti,sizeof(pthreadinfo));
157
ti^.f:=ThreadFunction;
159
ti^.stklen:=stacksize;
160
{ call pthread_create }
161
WRITE_DEBUG('SysBeginThread: Starting new thread'#13#10);
162
pthread_attr_init(@thread_attr);
163
pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
165
// will fail under linux -- apparently unimplemented
166
pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
168
// don't create detached, we need to be able to join (waitfor) on
169
// the newly created thread!
170
//pthread_attr_setdetachstate(@thread_attr, PTHREAD_CREATE_DETACHED);
171
if pthread_create(@threadid, @thread_attr, @ThreadMain,ti) <> 0 then begin
174
SysBeginThread:=threadid;
175
WRITE_DEBUG('SysBeginThread returning %d'#13#10,SysBeginThread);
179
procedure SysEndThread(ExitCode : DWord);
182
pthread_detach(pointer(pthread_self));
183
pthread_exit(pointer(ExitCode));
187
function SysSuspendThread (threadHandle : dword) : dword;
189
{$Warning SuspendThread needs to be implemented}
190
SysSuspendThread := $0FFFFFFFF;
193
function SysResumeThread (threadHandle : dword) : dword;
195
{$Warning ResumeThread needs to be implemented}
196
SysResumeThread := $0FFFFFFFF;
199
procedure SysThreadSwitch; {give time to other threads}
204
function SysKillThread (threadHandle : dword) : dword;
206
pthread_detach(pointer(threadHandle));
207
SysKillThread := pthread_cancel(Pointer(threadHandle));
210
function SysWaitForThreadTerminate (threadHandle : dword; TimeoutMs : longint) : dword; {0=no timeout}
216
LResultP := @LResult;
217
WRITE_DEBUG('SysWaitForThreadTerminate: waiting for %d, timeout %d'#13#10,threadHandle,timeoutMS);
218
pthread_join(Pointer(threadHandle), @LResultP);
219
SysWaitForThreadTerminate := LResult;
222
function SysThreadSetPriority (threadHandle : dword; Prio: longint): boolean; {-15..+15, 0=normal}
224
{priority is ignored on netware}
225
SysThreadSetPriority := true;
229
function SysThreadGetPriority (threadHandle : dword): longint;
231
{priority is ignored on netware}
232
SysThreadGetPriority := 0;
235
function SysGetCurrentThreadId : dword;
237
SysGetCurrentThreadId:=dword(pthread_self);
241
{*****************************************************************************
242
Delphi/Win32 compatibility
243
*****************************************************************************}
245
procedure SysInitCriticalSection(var CS);
248
P : PRTLCriticalSection;
251
P:=PRTLCriticalSection(@CS);
252
FillChar (p^,sizeof(p^),0);
253
pthread_mutex_init(P,NIL);
256
procedure SysEnterCriticalSection(var CS);
258
pthread_mutex_lock(PRTLCriticalSection(@CS));
261
procedure SysLeaveCriticalSection(var CS);
263
pthread_mutex_unlock(PRTLCriticalSection(@CS));
266
procedure SysDoneCriticalSection(var CS);
268
pthread_mutex_destroy(PRTLCriticalSection(@CS));
272
{*****************************************************************************
273
Heap Mutex Protection
274
*****************************************************************************}
277
HeapMutex : pthread_mutex_t;
279
procedure PThreadHeapMutexInit;
281
pthread_mutex_init(@heapmutex,nil);
284
procedure PThreadHeapMutexDone;
286
pthread_mutex_destroy(@heapmutex);
289
procedure PThreadHeapMutexLock;
291
pthread_mutex_lock(@heapmutex);
294
procedure PThreadHeapMutexUnlock;
296
pthread_mutex_unlock(@heapmutex);
300
PThreadMemoryMutexManager : TMemoryMutexManager = (
301
MutexInit : @PThreadHeapMutexInit;
302
MutexDone : @PThreadHeapMutexDone;
303
MutexLock : @PThreadHeapMutexLock;
304
MutexUnlock : @PThreadHeapMutexUnlock;
307
procedure InitHeapMutexes;
309
SetMemoryMutexManager(PThreadMemoryMutexManager);
313
Tbasiceventstate=record
315
FManualReset: Boolean;
316
FEventSection: ppthread_mutex_t;
318
plocaleventstate = ^tbasiceventstate;
319
// peventstate=pointer;
327
function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
330
MAttr : pthread_mutex_attr_t;
335
//new(plocaleventstate(result));
336
getmem (result,sizeof(plocaleventstate));
337
plocaleventstate(result)^.FManualReset:=AManualReset;
338
plocaleventstate(result)^.FSem:=New(PSemaphore); //sem_t.
339
// plocaleventstate(result)^.feventsection:=nil;
340
res:=pthread_mutexattr_init(@MAttr);
343
Res:=pthread_mutexattr_settype(@MAttr,longint(PTHREAD_MUTEX_RECURSIVE));
345
Res:=pthread_mutex_init(@plocaleventstate(result)^.feventsection,@MAttr);
347
pthread_mutexattr_destroy(@MAttr);
349
sem_init(psem_t(plocaleventstate(result)^.FSem),ord(False),Ord(InitialState));
352
procedure Intbasiceventdestroy(state:peventstate);
355
sem_destroy(psem_t( plocaleventstate(state)^.FSem));
358
procedure IntbasiceventResetEvent(state:peventstate);
361
While sem_trywait(psem_t( plocaleventstate(state)^.FSem))=0 do
365
procedure IntbasiceventSetEvent(state:peventstate);
371
pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
373
sem_getvalue(plocaleventstate(state)^.FSem,@value);
375
sem_post(psem_t( plocaleventstate(state)^.FSem));
377
pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
381
function IntbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
384
If TimeOut<>Cardinal($FFFFFFFF) then
388
sem_wait(psem_t(plocaleventstate(state)^.FSem));
390
if plocaleventstate(state)^.FManualReset then
392
pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
394
intbasiceventresetevent(State);
395
sem_post(psem_t( plocaleventstate(state)^.FSem));
397
pthread_mutex_unlock(@plocaleventstate(state)^.feventsection);
404
NWThreadManager : TThreadManager;
406
Procedure InitSystemThreads;
409
With NWThreadManager do
413
BeginThread :=@SysBeginThread;
414
EndThread :=@SysEndThread;
415
SuspendThread :=@SysSuspendThread;
416
ResumeThread :=@SysResumeThread;
417
KillThread :=@SysKillThread;
418
ThreadSwitch :=@SysThreadSwitch;
419
WaitForThreadTerminate :=@SysWaitForThreadTerminate;
420
ThreadSetPriority :=@SysThreadSetPriority;
421
ThreadGetPriority :=@SysThreadGetPriority;
422
GetCurrentThreadId :=@SysGetCurrentThreadId;
423
InitCriticalSection :=@SysInitCriticalSection;
424
DoneCriticalSection :=@SysDoneCriticalSection;
425
EnterCriticalSection :=@SysEnterCriticalSection;
426
LeaveCriticalSection :=@SysLeaveCriticalSection;
427
{$ifdef hasthreadvar}
428
InitThreadVar :=@SysInitThreadVar;
429
RelocateThreadVar :=@SysRelocateThreadVar;
430
AllocateThreadVars :=@SysAllocateThreadVars;
431
ReleaseThreadVars :=@SysReleaseThreadVars;
433
BasicEventCreate :=@intBasicEventCreate;
434
BasicEventDestroy :=@intBasicEventDestroy;
435
BasicEventResetEvent :=@intBasicEventResetEvent;
436
BasicEventSetEvent :=@intBasicEventSetEvent;
437
BasiceventWaitFor :=@intBasiceventWaitFor;
439
SetThreadManager(NWThreadManager);
441
{$ifdef HASTHREADVAR}
442
ThVarAllocResourceTag := AllocateResourceTag(getnlmhandle,'Threadvar Memory',AllocSignature);
444
NWSysSetThreadFunctions (@SysAllocateThreadVars,
445
@SysReleaseThreadVars,
446
@SysSetThreadDataAreaPtr);
451
$Log: systhrd.inc,v $
452
Revision 1.2 2005/02/14 17:13:30 peter
455
Revision 1.1 2005/02/06 16:57:18 peter
456
* threads for go32v2,os,emx,netware
458
Revision 1.1 2005/02/06 13:06:20 peter
459
* moved file and dir functions to sysfile/sysdir
460
* win32 thread in systemunit