fpc/rtl/inc/thread.inc

681 lines
19 KiB
PHP

{
This file is part of the Free Pascal Run time library.
Copyright (c) 2000 by the Free Pascal development team
OS independent thread functions/overloads
See the File COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
Var
CurrentTM : TThreadManager;
{$ifndef THREADVAR_RELOCATED_ALREADY_DEFINED}
fpc_threadvar_relocate_proc : TRelocateThreadVarHandler; public name 'FPC_THREADVAR_RELOCATE';
{$endif THREADVAR_RELOCATED_ALREADY_DEFINED}
{$ifndef HAS_GETCPUCOUNT}
function GetCPUCount: LongWord;
begin
Result := 1;
end;
{$endif}
{*****************************************************************************
Threadvar initialization
*****************************************************************************}
procedure InitThread(stklen:SizeUInt);
begin
{$ifndef FPUNONE}
SysResetFPU;
{$endif}
{$ifndef HAS_MEMORYMANAGER}
{$ifndef FPC_NO_DEFAULT_HEAP}
{ initialize this thread's heap }
InitHeapThread;
{$endif ndef FPC_NO_DEFAULT_HEAP}
{$else HAS_MEMORYMANAGER}
if MemoryManager.InitThread <> nil then
MemoryManager.InitThread();
{$endif HAS_MEMORYMANAGER}
{$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
if assigned(widestringmanager.ThreadInitProc) then
widestringmanager.ThreadInitProc;
{$endif FPC_HAS_FEATURE_WIDESTRINGS}
{$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
{ ExceptAddrStack and ExceptObjectStack are threadvars }
{ so every thread has its on exception handling capabilities }
SysInitExceptions;
{$endif FPC_HAS_FEATURE_EXCEPTIONS}
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
{$ifndef EMBEDDED}
{ Open all stdio fds again }
SysInitStdio;
InOutRes:=0;
// ErrNo:=0;
{$endif EMBEDDED}
{$endif FPC_HAS_FEATURE_CONSOLEIO}
{$ifdef FPC_HAS_FEATURE_STACKCHECK}
{ Stack checking }
StackLength:= CheckInitialStkLen(stkLen);
StackBottom:=Sptr - StackLength;
{$endif FPC_HAS_FEATURE_STACKCHECK}
ThreadID := CurrentTM.GetCurrentThreadID();
end;
procedure DoneThread;
begin
{$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
if assigned(widestringmanager.ThreadFiniProc) then
widestringmanager.ThreadFiniProc;
{$endif FPC_HAS_FEATURE_WIDESTRINGS}
{$ifndef HAS_MEMORYMANAGER}
{$ifndef FPC_NO_DEFAULT_HEAP}
FinalizeHeap;
{$endif ndef FPC_NO_DEFAULT_HEAP}
{$endif HAS_MEMORYMANAGER}
if MemoryManager.DoneThread <> nil then
MemoryManager.DoneThread();
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
{ Open all stdio fds again }
SysFlushStdio;
{$endif FPC_HAS_FEATURE_CONSOLEIO}
{ Support platforms where threadvar memory is managed outside of the RTL:
reset ThreadID and allow ReleaseThreadVars to be unassigned }
ThreadID := TThreadID(0);
if assigned(CurrentTM.ReleaseThreadVars) then
CurrentTM.ReleaseThreadVars;
end;
procedure InitThread;
begin
{ we should find a reasonable value here }
InitThread($1000000);
end;
{*****************************************************************************
Overloaded functions
*****************************************************************************}
function BeginThread(ThreadFunction : tthreadfunc) : TThreadID;
var
dummy : TThreadID;
begin
BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,nil,0,dummy);
end;
function BeginThread(ThreadFunction : tthreadfunc;p : pointer) : TThreadID;
var
dummy : TThreadID;
begin
BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,dummy);
end;
function BeginThread(ThreadFunction : tthreadfunc;p : pointer;var ThreadId : TThreadID) : TThreadID;
begin
BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,ThreadId);
end;
function BeginThread(ThreadFunction : tthreadfunc;p : pointer;
var ThreadId : TThreadID; const stacksize: SizeUInt) : TThreadID;
begin
BeginThread:=BeginThread(nil,stacksize,ThreadFunction,p,0,ThreadId);
end;
procedure EndThread;
begin
EndThread(0);
end;
function BeginThread(sa : Pointer;stacksize : SizeUInt; ThreadFunction : tthreadfunc;p : pointer;creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
begin
Result:=CurrentTM.BeginThread(sa,stacksize,threadfunction,P,creationflags,ThreadID);
end;
procedure FlushThread;
begin
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
SysFlushStdio;
{$endif FPC_HAS_FEATURE_CONSOLEIO}
end;
procedure EndThread(ExitCode : DWord);
begin
CurrentTM.EndThread(ExitCode);
end;
function SuspendThread (threadHandle : TThreadID) : dword;
begin
Result:=CurrentTM.SuspendThread(ThreadHandle);
end;
function ResumeThread (threadHandle : TThreadID) : dword;
begin
Result:=CurrentTM.ResumeThread(ThreadHandle);
end;
function CloseThread (threadHandle : TThreadID):dword;
begin
result:=CurrentTM.CloseThread(ThreadHandle);
end;
procedure ThreadSwitch;
begin
CurrentTM.ThreadSwitch;
end;
function KillThread (threadHandle : TThreadID) : dword;
begin
Result:=CurrentTM.KillThread(ThreadHandle);
end;
function WaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;
begin
Result:=CurrentTM.WaitForThreadTerminate(ThreadHandle,TimeOutMS);
end;
function ThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean;
begin
Result:=CurrentTM.ThreadSetPriority(ThreadHandle,Prio);
end;
function ThreadGetPriority (threadHandle : TThreadID): longint;
begin
Result:=CurrentTM.ThreadGetPriority(ThreadHandle);
end;
function GetCurrentThreadId : TThreadID;
begin
Result:=CurrentTM.GetCurrentThreadID();
end;
procedure SetThreadDebugName(threadHandle: TThreadID; const ThreadName: AnsiString);
begin
CurrentTM.SetThreadDebugNameA(threadHandle, ThreadName);
end;
{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
procedure SetThreadDebugName(threadHandle: TThreadID; const ThreadName: UnicodeString);
begin
CurrentTM.SetThreadDebugNameU(threadHandle, ThreadName);
end;
{$endif FPC_HAS_FEATURE_UNICODESTRINGS}
procedure InitCriticalSection(out cs : TRTLCriticalSection);
begin
CurrentTM.InitCriticalSection(cs);
end;
procedure DoneCriticalSection(var cs : TRTLCriticalSection);
begin
CurrentTM.DoneCriticalSection(cs);
end;
procedure EnterCriticalSection(var cs : TRTLCriticalSection);
begin
CurrentTM.EnterCriticalSection(cs);
end;
function TryEnterCriticalSection(var cs : TRTLCriticalSection):longint;
begin
result:=CurrentTM.TryEnterCriticalSection(cs);
end;
procedure LeaveCriticalSection(var cs : TRTLCriticalSection);
begin
CurrentTM.LeaveCriticalSection(cs);
end;
Function GetThreadManager(Out TM : TThreadManager) : Boolean;
begin
TM:=CurrentTM;
Result:=True;
end;
Function SetThreadManager(Const NewTM : TThreadManager; Out OldTM : TThreadManager) : Boolean;
begin
GetThreadManager(OldTM);
Result:=SetThreadManager(NewTM);
end;
Function SetThreadManager(Const NewTM : TThreadManager) : Boolean;
begin
Result:=True;
If Assigned(CurrentTM.DoneManager) then
Result:=CurrentTM.DoneManager();
If Result then
begin
CurrentTM:=NewTM;
If Assigned(CurrentTM.InitManager) then
Result:=CurrentTM.InitManager();
end;
end;
function BasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
begin
result:=currenttm.BasicEventCreate(EventAttributes,AManualReset,InitialState, Name);
end;
procedure BasicEventDestroy(state:peventstate);
begin
currenttm.BasicEventDestroy(state);
end;
procedure BasicEventResetEvent(state:peventstate);
begin
currenttm.BasicEventResetEvent(state);
end;
procedure BasicEventSetEvent(state:peventstate);
begin
currenttm.BasicEventSetEvent(state);
end;
function BasicEventWaitFor(Timeout : Cardinal;state:peventstate;FUseComWait : Boolean=False) : longint;
begin
result:=currenttm.BasicEventWaitFor(Timeout,state,FUseComWait);
end;
function RTLEventCreate :PRTLEvent;
begin
result:=currenttm.RTLEventCreate();
end;
procedure RTLeventDestroy(state:pRTLEvent);
begin
currenttm.RTLEventDestroy(state);
end;
procedure RTLeventSetEvent(state:pRTLEvent);
begin
currenttm.RTLEventSetEvent(state);
end;
procedure RTLeventResetEvent(state:pRTLEvent);
begin
currenttm.RTLEventResetEvent(state);
end;
procedure RTLeventWaitFor(state:pRTLEvent);
begin
currenttm.RTLEventWaitFor(state);
end;
procedure RTLeventWaitFor(state:pRTLEvent;timeout : longint);
begin
currenttm.RTLEventWaitForTimeout(state,timeout);
end;
{ ---------------------------------------------------------------------
lazy thread initialization support
---------------------------------------------------------------------}
type
PLazyInitThreadingProcInfo = ^TLazyInitThreadingProcInfo;
TLazyInitThreadingProcInfo = Record
Next : PLazyInitThreadingProcInfo;
Proc : TProcedure;
End;
const
LazyInitThreadingProcList: PLazyInitThreadingProcInfo = nil;
procedure FinalizeLazyInitThreading;
var
p: PLazyInitThreadingProcInfo;
begin
while assigned(LazyInitThreadingProcList) do
begin
p:=LazyInitThreadingProcList^.Next;
Dispose(LazyInitThreadingProcList);
LazyInitThreadingProcList:=p;
end;
end;
procedure RegisterLazyInitThreadingProc(const proc: TProcedure);
var
p: PLazyInitThreadingProcInfo;
begin
if IsMultiThread then
begin
{ multithreading is already enabled - execute directly }
proc();
end
else
begin
if not assigned(LazyInitThreadingProcList) then
AddExitProc(@FinalizeLazyInitThreading);
new(p);
p^.Next:=LazyInitThreadingProcList;
p^.Proc:=proc;
LazyInitThreadingProcList:=p;
end;
end;
procedure LazyInitThreading;
var
p: PLazyInitThreadingProcInfo;
begin
p:=LazyInitThreadingProcList;
while assigned(p) do
begin
p^.Proc();
p:=p^.Next;
end;
end;
{ ---------------------------------------------------------------------
ThreadManager which gives run-time error. Use if no thread support.
---------------------------------------------------------------------}
{$ifndef DISABLE_NO_THREAD_MANAGER}
{ resourcestrings are not supported by the system unit,
they are in the objpas unit and not available for fpc/tp modes }
const
SNoThreads = 'This binary has no thread support compiled in.';
SRecompileWithThreads = 'Recompile the application with a thread-driver in the program uses clause before other units using thread.';
Procedure NoThreadError;
begin
{$ifndef EMBEDDED}
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
{$ifndef FPC_SYSTEM_NO_VERBOSE_THREADERROR}
If IsConsole then
begin
Writeln(StdErr,SNoThreads);
Writeln(StdErr,SRecompileWithThreads);
end;
{$endif FPC_SYSTEM_NO_VERBOSE_THREADERROR}
{$endif FPC_HAS_FEATURE_CONSOLEIO}
{$endif EMBEDDED}
RunError(232)
end;
function NoBeginThread(sa : Pointer;stacksize : PtrUInt;
ThreadFunction : tthreadfunc;p : pointer;
creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
begin
NoThreadError;
result:=tthreadid(-1);
end;
procedure NoEndThread(ExitCode : DWord);
begin
NoThreadError;
end;
function NoThreadHandler (threadHandle : TThreadID) : dword;
begin
NoThreadError;
result:=dword(-1);
end;
function NoWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword; {0=no timeout}
begin
NoThreadError;
result:=dword(-1);
end;
function NoThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
begin
NoThreadError;
result:=false;
end;
function NoThreadGetPriority (threadHandle : TThreadID): longint;
begin
NoThreadError;
result:=-1;
end;
function NoGetCurrentThreadId : TThreadID;
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true;
result:=TThreadID(1);
end;
procedure NoSetThreadDebugNameA(threadHandle: TThreadID; const ThreadName: AnsiString);
begin
NoThreadError;
end;
{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
procedure NoSetThreadDebugNameU(threadHandle: TThreadID; const ThreadName: UnicodeString);
begin
NoThreadError;
end;
{$endif FPC_HAS_FEATURE_UNICODESTRINGS}
procedure NoCriticalSection(var CS);
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true;
end;
function NoTryEnterCriticalSection(var CS):longint;
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true;
Result:=-1;
end;
procedure NoInitThreadvar(var offset : {$ifdef cpu16}word{$else}dword{$endif};size : dword);
begin
NoThreadError;
end;
function NoRelocateThreadvar(offset : {$ifdef cpu16}word{$else}dword{$endif}) : pointer;
begin
NoThreadError;
result:=nil;
end;
function NoBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true;
result:=nil;
end;
procedure NoBasicEvent(state:peventstate);
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true;
end;
function NoBasicEventWaitFor(Timeout : Cardinal;state:peventstate;FUseComWait : Boolean=False) : longint;
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true;
result:=-1;
end;
function NoRTLEventCreate :PRTLEvent;
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true;
result:=nil;
end;
procedure NoRTLEvent(state:pRTLEvent);
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true
end;
procedure NoRTLEventWaitForTimeout(state:pRTLEvent;timeout : longint);
begin
if IsMultiThread then
NoThreadError
else
ThreadingAlreadyUsed:=true;
end;
const
NoThreadManager : TThreadManager = (
InitManager : Nil;
DoneManager : Nil;
{$ifdef EMBEDDED}
{ while this is pretty hacky, it reduces the size of typical embedded programs
and works fine on arm and avr }
BeginThread : @NoBeginThread;
EndThread : TEndThreadHandler(@NoThreadError);
SuspendThread : TThreadHandler(@NoThreadError);
ResumeThread : TThreadHandler(@NoThreadError);
KillThread : TThreadHandler(@NoThreadError);
CloseThread : TThreadHandler(@NoThreadError);
ThreadSwitch : TThreadSwitchHandler(@NoThreadError);
WaitForThreadTerminate : TWaitForThreadTerminateHandler(@NoThreadError);
ThreadSetPriority : TThreadSetPriorityHandler(@NoThreadError);
ThreadGetPriority : TThreadGetPriorityHandler(@NoThreadError);
GetCurrentThreadId : @NoGetCurrentThreadId;
SetThreadDebugNameA : TThreadSetThreadDebugNameHandlerA(@NoThreadError);
{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
SetThreadDebugNameU : TThreadSetThreadDebugNameHandlerU(@NoThreadError);
{$endif FPC_HAS_FEATURE_UNICODESTRINGS}
InitCriticalSection : TCriticalSectionHandler(@NoThreadError);
DoneCriticalSection : TCriticalSectionHandler(@NoThreadError);
EnterCriticalSection : TCriticalSectionHandler(@NoThreadError);
TryEnterCriticalSection: TCriticalSectionHandlerTryEnter(@NoThreadError);
LeaveCriticalSection : TCriticalSectionHandler(@NoThreadError);
InitThreadVar : TInitThreadVarHandler(@NoThreadError);
RelocateThreadVar : TRelocateThreadVarHandler(@NoThreadError);
AllocateThreadVars : @NoThreadError;
ReleaseThreadVars : @NoThreadError;
BasicEventCreate : TBasicEventCreateHandler(@NoThreadError);
BasicEventdestroy : TBasicEventHandler(@NoThreadError);
BasicEventResetEvent : TBasicEventHandler(@NoThreadError);
BasicEventSetEvent : TBasicEventHandler(@NoThreadError);
BasicEventWaitFor : TBasicEventWaitForHandler(@NoThreadError);
RTLEventCreate : TRTLCreateEventHandler(@NoThreadError);
RTLEventdestroy : TRTLEventHandler(@NoThreadError);
RTLEventSetEvent : TRTLEventHandler(@NoThreadError);
RTLEventResetEvent : TRTLEventHandler(@NoThreadError);
RTLEventWaitFor : TRTLEventHandler(@NoThreadError);
RTLEventwaitfortimeout : TRTLEventHandlerTimeout(@NoThreadError);
{$else EMBEDDED}
BeginThread : @NoBeginThread;
EndThread : @NoEndThread;
SuspendThread : @NoThreadHandler;
ResumeThread : @NoThreadHandler;
KillThread : @NoThreadHandler;
CloseThread : @NoThreadHandler;
ThreadSwitch : @NoThreadError;
WaitForThreadTerminate : @NoWaitForThreadTerminate;
ThreadSetPriority : @NoThreadSetPriority;
ThreadGetPriority : @NoThreadGetPriority;
GetCurrentThreadId : @NoGetCurrentThreadId;
SetThreadDebugNameA : @NoSetThreadDebugNameA;
{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
SetThreadDebugNameU : @NoSetThreadDebugNameU;
{$endif FPC_HAS_FEATURE_UNICODESTRINGS}
InitCriticalSection : @NoCriticalSection;
DoneCriticalSection : @NoCriticalSection;
EnterCriticalSection : @NoCriticalSection;
TryEnterCriticalSection: @NoTryEnterCriticalSection;
LeaveCriticalSection : @NoCriticalSection;
InitThreadVar : @NoInitThreadVar;
RelocateThreadVar : @NoRelocateThreadVar;
AllocateThreadVars : @NoThreadError;
ReleaseThreadVars : @NoThreadError;
BasicEventCreate : @NoBasicEventCreate;
BasicEventDestroy : @NoBasicEvent;
BasicEventResetEvent : @NoBasicEvent;
BasicEventSetEvent : @NoBasicEvent;
BasicEventWaitFor : @NoBasiceventWaitFor;
RTLEventCreate : @NoRTLEventCreate;
RTLEventDestroy : @NoRTLevent;
RTLEventSetEvent : @NoRTLevent;
RTLEventResetEvent : @NoRTLEvent;
RTLEventWaitFor : @NoRTLEvent;
RTLEventWaitforTimeout : @NoRTLEventWaitForTimeout;
{$endif EMBEDDED}
);
Procedure SetNoThreadManager;
begin
SetThreadManager(NoThreadManager);
end;
Procedure InitSystemThreads; public name '_FPC_InitSystemThreads';
begin
{ This should be changed to a real value during
thread driver initialization if appropriate. }
ThreadID := TThreadID(1);
SetNoThreadManager;
end;
{$endif DISABLE_NO_THREAD_MANAGER}