mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 08:19:36 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			295 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
{
 | 
						|
  $Id$
 | 
						|
 | 
						|
  Linux TThread implementation
 | 
						|
}
 | 
						|
 | 
						|
type
 | 
						|
  PThreadRec=^TThreadRec;
 | 
						|
  TThreadRec=record
 | 
						|
    thread : TThread;
 | 
						|
    next   : PThreadRec;
 | 
						|
  end;
 | 
						|
 | 
						|
var
 | 
						|
  ThreadRoot : PThreadRec;
 | 
						|
  ThreadsInited : boolean;
 | 
						|
//  MainThreadID: longint;
 | 
						|
 | 
						|
Const
 | 
						|
  ThreadCount: longint = 0;
 | 
						|
 | 
						|
function ThreadSelf:TThread;
 | 
						|
var
 | 
						|
  hp : PThreadRec;
 | 
						|
  sp : longint;
 | 
						|
begin
 | 
						|
  sp:=SPtr;
 | 
						|
  hp:=ThreadRoot;
 | 
						|
  while assigned(hp) do
 | 
						|
   begin
 | 
						|
     if (sp<=hp^.Thread.FStackPointer) and
 | 
						|
        (sp>(hp^.Thread.FStackPointer-hp^.Thread.FStackSize)) then
 | 
						|
      begin
 | 
						|
        Result:=hp^.Thread;
 | 
						|
        exit;
 | 
						|
      end;
 | 
						|
     hp:=hp^.next;
 | 
						|
   end;
 | 
						|
  Result:=nil;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
//function SIGCHLDHandler(Sig: longint): longint; cdecl;//this is std linux C declaration as function
 | 
						|
procedure SIGCHLDHandler(Sig: longint); cdecl;
 | 
						|
begin
 | 
						|
  waitpid(-1, nil, WNOHANG);
 | 
						|
end;
 | 
						|
 | 
						|
procedure InitThreads;
 | 
						|
var
 | 
						|
  Act, OldAct: PSigActionRec;
 | 
						|
begin
 | 
						|
  ThreadRoot:=nil;
 | 
						|
  ThreadsInited:=true;
 | 
						|
 | 
						|
 | 
						|
// This will install SIGCHLD signal handler
 | 
						|
// signal() installs "one-shot" handler,
 | 
						|
// so it is better to install and set up handler with sigaction()
 | 
						|
 | 
						|
  GetMem(Act, SizeOf(SigActionRec));
 | 
						|
  GetMem(OldAct, SizeOf(SigActionRec));
 | 
						|
 | 
						|
  Act^.sa_handler := @SIGCHLDHandler;
 | 
						|
  Act^.sa_flags := SA_NOCLDSTOP {or SA_NOMASK or SA_RESTART};
 | 
						|
  Act^.sa_mask := 0; //Do not block all signals ??. Don't need if SA_NOMASK in flags
 | 
						|
 | 
						|
  SigAction(SIGCHLD, Act, OldAct);
 | 
						|
 | 
						|
  FreeMem(Act, SizeOf(SigActionRec));
 | 
						|
  FreeMem(OldAct, SizeOf(SigActionRec));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure DoneThreads;
 | 
						|
var
 | 
						|
  hp : PThreadRec;
 | 
						|
begin
 | 
						|
  while assigned(ThreadRoot) do
 | 
						|
   begin
 | 
						|
     ThreadRoot^.Thread.Destroy;
 | 
						|
     hp:=ThreadRoot;
 | 
						|
     ThreadRoot:=ThreadRoot^.Next;
 | 
						|
     dispose(hp);
 | 
						|
   end;
 | 
						|
  ThreadsInited:=false;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure AddThread(t:TThread);
 | 
						|
var
 | 
						|
  hp : PThreadRec;
 | 
						|
begin
 | 
						|
  { Need to initialize threads ? }
 | 
						|
  if not ThreadsInited then
 | 
						|
   InitThreads;
 | 
						|
 | 
						|
  { Put thread in the linked list }
 | 
						|
  new(hp);
 | 
						|
  hp^.Thread:=t;
 | 
						|
  hp^.next:=ThreadRoot;
 | 
						|
  ThreadRoot:=hp;
 | 
						|
 | 
						|
  inc(ThreadCount, 1);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure RemoveThread(t:TThread);
 | 
						|
var
 | 
						|
  lasthp,hp : PThreadRec;
 | 
						|
begin
 | 
						|
  hp:=ThreadRoot;
 | 
						|
  lasthp:=nil;
 | 
						|
  while assigned(hp) do
 | 
						|
   begin
 | 
						|
     if hp^.Thread=t then
 | 
						|
      begin
 | 
						|
        if assigned(lasthp) then
 | 
						|
         lasthp^.next:=hp^.next
 | 
						|
        else
 | 
						|
         ThreadRoot:=hp^.next;
 | 
						|
        dispose(hp);
 | 
						|
        exit;
 | 
						|
      end;
 | 
						|
     lasthp:=hp;
 | 
						|
     hp:=hp^.next;
 | 
						|
   end;
 | 
						|
 | 
						|
  Dec(ThreadCount, 1);
 | 
						|
  if ThreadCount = 0 then DoneThreads;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{ TThread }
 | 
						|
function ThreadProc(args:pointer): Integer;cdecl;
 | 
						|
var
 | 
						|
  FreeThread: Boolean;
 | 
						|
  Thread : TThread absolute args;
 | 
						|
begin
 | 
						|
  Thread.Execute;
 | 
						|
  FreeThread := Thread.FFreeOnTerminate;
 | 
						|
  Result := Thread.FReturnValue;
 | 
						|
  Thread.FFinished := True;
 | 
						|
  Thread.DoTerminate;
 | 
						|
  if FreeThread then
 | 
						|
    Thread.Free;
 | 
						|
  ExitProcess(Result);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
constructor TThread.Create(CreateSuspended: Boolean);
 | 
						|
var
 | 
						|
  Flags: Integer;
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  AddThread(self);
 | 
						|
  FSuspended := CreateSuspended;
 | 
						|
  Flags := CLONE_VM + CLONE_FS + CLONE_FILES + CLONE_SIGHAND + SIGCHLD;
 | 
						|
  { Setup 16k of stack }
 | 
						|
  FStackSize:=16384;
 | 
						|
  Getmem(pointer(FStackPointer),FStackSize);
 | 
						|
  inc(FStackPointer,FStackSize);
 | 
						|
  FCallExitProcess:=false;
 | 
						|
  { Clone }
 | 
						|
  FHandle:= Clone(@ThreadProc,pointer(FStackPointer),Flags,self);
 | 
						|
  if FSuspended then Suspend;
 | 
						|
  FThreadID := FHandle;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
destructor TThread.Destroy;
 | 
						|
begin
 | 
						|
  if not FFinished and not Suspended then
 | 
						|
   begin
 | 
						|
     Terminate;
 | 
						|
     WaitFor;
 | 
						|
   end;
 | 
						|
  if FHandle <> -1 then
 | 
						|
    Kill(FHandle, SIGKILL);
 | 
						|
  dec(FStackPointer,FStackSize);
 | 
						|
  Freemem(pointer(FStackPointer),FStackSize);
 | 
						|
  inherited Destroy;
 | 
						|
  RemoveThread(self);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TThread.CallOnTerminate;
 | 
						|
begin
 | 
						|
  FOnTerminate(Self);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TThread.DoTerminate;
 | 
						|
begin
 | 
						|
  if Assigned(FOnTerminate) then
 | 
						|
    Synchronize(@CallOnTerminate);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
const
 | 
						|
{ I Don't know idle or timecritical, value is also 20, so the largest other
 | 
						|
  possibility is 19 (PFV) }
 | 
						|
  Priorities: array [TThreadPriority] of Integer =
 | 
						|
   (-20,-19,-10,9,10,19,20);
 | 
						|
 | 
						|
function TThread.GetPriority: TThreadPriority;
 | 
						|
var
 | 
						|
  P: Integer;
 | 
						|
  I: TThreadPriority;
 | 
						|
begin
 | 
						|
  P := Linux.GetPriority(Prio_Process,FHandle);
 | 
						|
  Result := tpNormal;
 | 
						|
  for I := Low(TThreadPriority) to High(TThreadPriority) do
 | 
						|
    if Priorities[I] = P then
 | 
						|
      Result := I;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TThread.SetPriority(Value: TThreadPriority);
 | 
						|
begin
 | 
						|
  Linux.SetPriority(Prio_Process,FHandle, Priorities[Value]);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TThread.Synchronize(Method: TThreadMethod);
 | 
						|
begin
 | 
						|
  FSynchronizeException := nil;
 | 
						|
  FMethod := Method;
 | 
						|
{  SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self)); }
 | 
						|
  if Assigned(FSynchronizeException) then
 | 
						|
    raise FSynchronizeException;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TThread.SetSuspended(Value: Boolean);
 | 
						|
begin
 | 
						|
  if Value <> FSuspended then
 | 
						|
    if Value then
 | 
						|
      Suspend
 | 
						|
    else
 | 
						|
      Resume;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TThread.Suspend;
 | 
						|
begin
 | 
						|
  Kill(FHandle, SIGSTOP);
 | 
						|
  FSuspended := true;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TThread.Resume;
 | 
						|
begin
 | 
						|
  Kill(FHandle, SIGCONT);
 | 
						|
  FSuspended := False;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TThread.Terminate;
 | 
						|
begin
 | 
						|
  FTerminated := True;
 | 
						|
end;
 | 
						|
 | 
						|
function TThread.WaitFor: Integer;
 | 
						|
var
 | 
						|
  status : longint;
 | 
						|
begin
 | 
						|
  if FThreadID = MainThreadID then
 | 
						|
   WaitPid(0,@status,0)
 | 
						|
  else
 | 
						|
   WaitPid(FHandle,@status,0);
 | 
						|
  Result:=status;
 | 
						|
end;
 | 
						|
 | 
						|
{
 | 
						|
  $Log$
 | 
						|
  Revision 1.7  2000-01-06 01:20:33  peter
 | 
						|
    * moved out of packages/ back to topdir
 | 
						|
 | 
						|
  Revision 1.1  2000/01/03 19:33:09  peter
 | 
						|
    * moved to packages dir
 | 
						|
 | 
						|
  Revision 1.5  1999/10/27 10:40:30  peter
 | 
						|
    * fixed threadproc decl
 | 
						|
 | 
						|
  Revision 1.4  1999/08/28 09:32:26  peter
 | 
						|
    * readded header/log
 | 
						|
 | 
						|
  Revision 1.2  1999/05/31 12:47:59  peter
 | 
						|
    * classes unit to unitobjects
 | 
						|
 | 
						|
  Revision 1.1  1999/05/30 10:46:42  peter
 | 
						|
    * start of tthread for linux,win32
 | 
						|
 | 
						|
}
 |