Bladeren bron

--- Merging r30842 into '.':
U packages/fcl-process/src/amicommon/process.inc
--- Recording mergeinfo for merge of r30842 into '.':
U .
--- Merging r30860 into '.':
U packages/fcl-process/src/amicommon/simpleipc.inc
--- Recording mergeinfo for merge of r30860 into '.':
G .
--- Merging r30886 into '.':
U rtl/aros/system.pp
--- Recording mergeinfo for merge of r30886 into '.':
G .
--- Merging r30899 into '.':
U rtl/amiga/system.pp
U rtl/morphos/system.pp
U rtl/amicommon/sysfile.inc
G rtl/aros/system.pp
--- Recording mergeinfo for merge of r30899 into '.':
G .
--- Merging r30901 into '.':
A rtl/amiga/m68k/m68kamiga.inc
--- Recording mergeinfo for merge of r30901 into '.':
G .
--- Merging r30902 into '.':
U rtl/amiga/m68k/m68kamiga.inc
--- Recording mergeinfo for merge of r30902 into '.':
G .
--- Merging r30903 into '.':
G rtl/amiga/system.pp
U rtl/m68k/m68k.inc
--- Recording mergeinfo for merge of r30903 into '.':
G .
--- Merging r30904 into '.':
D rtl/morphos/sysosh.inc
--- Recording mergeinfo for merge of r30904 into '.':
G .
--- Merging r30905 into '.':
A rtl/amicommon/athreads.pp
--- Recording mergeinfo for merge of r30905 into '.':
G .
--- Merging r30912 into '.':
U rtl/amicommon/sysosh.inc
U rtl/amicommon/athreads.pp
--- Recording mergeinfo for merge of r30912 into '.':
G .
--- Merging r30913 into '.':
G rtl/amicommon/athreads.pp
--- Recording mergeinfo for merge of r30913 into '.':
G .
--- Merging r30914 into '.':
D rtl/amiga/tthread.inc
U rtl/objpas/classes/classesh.inc
A rtl/amicommon/tthread.inc
D rtl/morphos/tthread.inc
--- Recording mergeinfo for merge of r30914 into '.':
G .
--- Merging r30915 into '.':
U packages/morphunits/src/exec.pas
--- Recording mergeinfo for merge of r30915 into '.':
G .
--- Merging r30916 into '.':
G packages/morphunits/src/exec.pas
--- Recording mergeinfo for merge of r30916 into '.':
G .
--- Merging r30917 into '.':
U rtl/morphos/execd.inc
--- Recording mergeinfo for merge of r30917 into '.':
G .
--- Merging r30921 into '.':
U rtl/amicommon/osdebugh.inc
U rtl/amicommon/osdebug.inc
--- Recording mergeinfo for merge of r30921 into '.':
G .
--- Merging r30922 into '.':
G rtl/amicommon/athreads.pp
--- Recording mergeinfo for merge of r30922 into '.':
G .
--- Merging r30923 into '.':
U rtl/amicommon/sysutils.pp
G rtl/amicommon/sysosh.inc
U rtl/aros/arosthreads.inc
U rtl/aros/systhrd.inc
U rtl/aros/i386/doslibf.inc
U rtl/aros/i386/execf.inc
U rtl/amiga/m68k/doslibf.inc
U rtl/morphos/doslibf.inc
--- Recording mergeinfo for merge of r30923 into '.':
G .
--- Merging r30924 into '.':
G rtl/amicommon/athreads.pp
--- Recording mergeinfo for merge of r30924 into '.':
G .
--- Merging r30933 into '.':
G rtl/amicommon/athreads.pp
--- Recording mergeinfo for merge of r30933 into '.':
G .
--- Merging r30940 into '.':
G rtl/amicommon/athreads.pp
--- Recording mergeinfo for merge of r30940 into '.':
G .

# revisions: 30842,30860,30886,30899,30901,30902,30903,30904,30905,30912,30913,30914,30915,30916,30917,30921,30922,30923,30924,30933,30940

git-svn-id: branches/fixes_3_0@31084 -

marco 10 jaren geleden
bovenliggende
commit
c07dbaddf1

+ 3 - 3
.gitattributes

@@ -7899,6 +7899,7 @@ rtl/aix/termiosproc.inc svneol=native#text/plain
 rtl/aix/unxconst.inc svneol=native#text/plain
 rtl/aix/unxconst.inc svneol=native#text/plain
 rtl/aix/unxfunc.inc svneol=native#text/plain
 rtl/aix/unxfunc.inc svneol=native#text/plain
 rtl/amicommon/README.TXT svneol=native#text/plain
 rtl/amicommon/README.TXT svneol=native#text/plain
+rtl/amicommon/athreads.pp svneol=native#text/plain
 rtl/amicommon/classes.pp svneol=native#text/plain
 rtl/amicommon/classes.pp svneol=native#text/plain
 rtl/amicommon/dos.pp svneol=native#text/plain
 rtl/amicommon/dos.pp svneol=native#text/plain
 rtl/amicommon/osdebug.inc svneol=native#text/plain
 rtl/amicommon/osdebug.inc svneol=native#text/plain
@@ -7910,12 +7911,14 @@ rtl/amicommon/sysheap.inc svneol=native#text/plain
 rtl/amicommon/sysos.inc svneol=native#text/plain
 rtl/amicommon/sysos.inc svneol=native#text/plain
 rtl/amicommon/sysosh.inc svneol=native#text/plain
 rtl/amicommon/sysosh.inc svneol=native#text/plain
 rtl/amicommon/sysutils.pp svneol=native#text/plain
 rtl/amicommon/sysutils.pp svneol=native#text/plain
+rtl/amicommon/tthread.inc svneol=native#text/plain
 rtl/amiga/Makefile svneol=native#text/plain
 rtl/amiga/Makefile svneol=native#text/plain
 rtl/amiga/Makefile.fpc svneol=native#text/plain
 rtl/amiga/Makefile.fpc svneol=native#text/plain
 rtl/amiga/doslibd.inc svneol=native#text/plain
 rtl/amiga/doslibd.inc svneol=native#text/plain
 rtl/amiga/m68k/doslibf.inc svneol=native#text/plain
 rtl/amiga/m68k/doslibf.inc svneol=native#text/plain
 rtl/amiga/m68k/execd.inc svneol=native#text/plain
 rtl/amiga/m68k/execd.inc svneol=native#text/plain
 rtl/amiga/m68k/execf.inc svneol=native#text/plain
 rtl/amiga/m68k/execf.inc svneol=native#text/plain
+rtl/amiga/m68k/m68kamiga.inc svneol=native#text/plain
 rtl/amiga/m68k/prt0.as svneol=native#text/plain
 rtl/amiga/m68k/prt0.as svneol=native#text/plain
 rtl/amiga/m68k/utild1.inc svneol=native#text/plain
 rtl/amiga/m68k/utild1.inc svneol=native#text/plain
 rtl/amiga/m68k/utild2.inc svneol=native#text/plain
 rtl/amiga/m68k/utild2.inc svneol=native#text/plain
@@ -7929,7 +7932,6 @@ rtl/amiga/powerpc/utild2.inc svneol=native#text/plain
 rtl/amiga/powerpc/utilf.inc svneol=native#text/plain
 rtl/amiga/powerpc/utilf.inc svneol=native#text/plain
 rtl/amiga/system.pp svneol=native#text/plain
 rtl/amiga/system.pp svneol=native#text/plain
 rtl/amiga/timerd.inc svneol=native#text/plain
 rtl/amiga/timerd.inc svneol=native#text/plain
-rtl/amiga/tthread.inc svneol=native#text/plain
 rtl/android/Makefile svneol=native#text/plain
 rtl/android/Makefile svneol=native#text/plain
 rtl/android/Makefile.fpc svneol=native#text/plain
 rtl/android/Makefile.fpc svneol=native#text/plain
 rtl/android/arm/dllprt0.as svneol=native#text/plain
 rtl/android/arm/dllprt0.as svneol=native#text/plain
@@ -8695,11 +8697,9 @@ rtl/morphos/emuld.inc svneol=native#text/plain
 rtl/morphos/execd.inc svneol=native#text/plain
 rtl/morphos/execd.inc svneol=native#text/plain
 rtl/morphos/execf.inc svneol=native#text/plain
 rtl/morphos/execf.inc svneol=native#text/plain
 rtl/morphos/prt0.as svneol=native#text/plain
 rtl/morphos/prt0.as svneol=native#text/plain
-rtl/morphos/sysosh.inc svneol=native#text/plain
 rtl/morphos/system.pp svneol=native#text/plain
 rtl/morphos/system.pp svneol=native#text/plain
 rtl/morphos/timerd.inc svneol=native#text/plain
 rtl/morphos/timerd.inc svneol=native#text/plain
 rtl/morphos/timerf.inc svneol=native#text/plain
 rtl/morphos/timerf.inc svneol=native#text/plain
-rtl/morphos/tthread.inc svneol=native#text/plain
 rtl/morphos/utild1.inc svneol=native#text/plain
 rtl/morphos/utild1.inc svneol=native#text/plain
 rtl/morphos/utild2.inc svneol=native#text/plain
 rtl/morphos/utild2.inc svneol=native#text/plain
 rtl/morphos/utilf.inc svneol=native#text/plain
 rtl/morphos/utilf.inc svneol=native#text/plain

+ 1 - 1
packages/fcl-process/src/amicommon/process.inc

@@ -117,7 +117,7 @@ begin
    cos := BPTR(0);
    cos := BPTR(0);
    repeat
    repeat
      Inc(UID);
      Inc(UID);
-     TempName := 'T:'+HexStr(FindTask(nil)) + '_'  + HexStr(Self) + '_'+ IntToStr(UID) + '_Starter.tmp';
+     TempName := 'T:PrO_'+ HexStr(FindTask(nil)) + '_' + IntToHex(UID,8);
    until not FileExists(TempName);   
    until not FileExists(TempName);   
    //sysdebugln('TProcess start: "' + ExecName + ' ' + Params+'"  >' + TempName);
    //sysdebugln('TProcess start: "' + ExecName + ' ' + Params+'"  >' + TempName);
    cos := AmigaDos.DosOpen(PChar(TempName), MODE_READWRITE);
    cos := AmigaDos.DosOpen(PChar(TempName), MODE_READWRITE);

+ 22 - 10
packages/fcl-process/src/amicommon/simpleipc.inc

@@ -70,7 +70,7 @@ Type
     Procedure Connect; override;
     Procedure Connect; override;
     Procedure Disconnect; override;
     Procedure Disconnect; override;
     Procedure SendMessage(MsgType : TMessageType; AStream : TStream); override;
     Procedure SendMessage(MsgType : TMessageType; AStream : TStream); override;
-    //Function  ServerRunning : Boolean; override;
+    Function  ServerRunning : Boolean; override;
   end;
   end;
 
 
   TAmigaServerComm = Class(TIPCServerComm)
   TAmigaServerComm = Class(TIPCServerComm)
@@ -90,19 +90,20 @@ Type
   
   
 // ####### CLIENT  
 // ####### CLIENT  
   
   
-function SafePutToPort(Msg: PMessage; Portname: string): Integer;
+function SafePutToPort(Msg: PMessage; Portname: string): Boolean;
  var
  var
    Port: PMsgPort;
    Port: PMsgPort;
    PName: PChar;
    PName: PChar;
  begin
  begin
-   Result := -1;
+   Result := False;
    PName := PChar(Portname + #0);
    PName := PChar(Portname + #0);
    Forbid();
    Forbid();
    Port := FindPort(PName);
    Port := FindPort(PName);
    if Assigned(Port) then
    if Assigned(Port) then
    begin
    begin
-     PutMsg(Port, Msg);
-     Result := 0;
+     if Assigned(Msg) then
+       PutMsg(Port, Msg);
+     Result := True;
    end;
    end;
    Permit();
    Permit();
  end;
  end;
@@ -133,7 +134,7 @@ var
   PortName: string;
   PortName: string;
 begin
 begin
   Size := AStream.Size - AStream.Position;
   Size := AStream.Size - AStream.Position;
-  FullSize := Size + Sizeof(Exec.TMessage);
+  FullSize := Size + SizeOf(TMessageType) + Sizeof(Exec.TMessage);
   PortName := PORTNAMESTART + Owner.ServerID;
   PortName := PORTNAMESTART + Owner.ServerID;
   Memory := System.AllocMem(FullSize);
   Memory := System.AllocMem(FullSize);
   MP := CreateMsgPort;
   MP := CreateMsgPort;
@@ -143,8 +144,10 @@ begin
     MsgHead^.mn_Length := Size;
     MsgHead^.mn_Length := Size;
     Temp := Memory;
     Temp := Memory;
     Inc(Temp, SizeOf(Exec.TMessage));
     Inc(Temp, SizeOf(Exec.TMessage));
+    Move(MsgType, Temp^, SizeOf(TMessageType));
+    Inc(Temp, SizeOf(TMessageType));
     AStream.Read(Temp^, Size);
     AStream.Read(Temp^, Size);
-    if SafePutToPort(MsgHead, PortName) = 0 then
+    if SafePutToPort(MsgHead, PortName) then
       WaitPort(MP);
       WaitPort(MP);
   finally
   finally
     System.FreeMem(Memory);
     System.FreeMem(Memory);
@@ -152,6 +155,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+Function TAmigaClientComm.ServerRunning : Boolean;
+begin
+  Result := SafePutToPort(nil, PORTNAMESTART + Owner.ServerID); 
+end;
+
 // ###### SERVER
 // ###### SERVER
 
 
 Constructor TAmigaServerComm.Create(AOwner: TSimpleIPCServer);
 Constructor TAmigaServerComm.Create(AOwner: TSimpleIPCServer);
@@ -213,8 +221,8 @@ begin
       Inc(Temp, SizeOf(Exec.TMessage));
       Inc(Temp, SizeOf(Exec.TMessage));
       if Assigned(MsgBody) then
       if Assigned(MsgBody) then
         System.FreeMem(MsgBody);
         System.FreeMem(MsgBody);
-      MsgBody := System.AllocMem(SizeOf(Exec.TMessage) + Msg^.mn_Length);
-      Move(Msg^, MsgBody^, SizeOf(Exec.TMessage) + Msg^.mn_Length);
+      MsgBody := System.AllocMem(SizeOf(Exec.TMessage) + SizeOf(TMessageType) + Msg^.mn_Length);
+      Move(Msg^, MsgBody^, SizeOf(Exec.TMessage) + SizeOf(TMessageType) + Msg^.mn_Length);
       ReplyMsg(Msg);
       ReplyMsg(Msg);
       break;
       break;
     end;
     end;
@@ -225,12 +233,16 @@ end;
 Procedure TAmigaServerComm.ReadMessage;
 Procedure TAmigaServerComm.ReadMessage;
 var
 var
   Temp: PByte;
   Temp: PByte;
+  MsgType: TMessageType;
 begin
 begin
   if Assigned(MsgBody) then
   if Assigned(MsgBody) then
   begin
   begin
     Temp := Pointer(MsgBody);
     Temp := Pointer(MsgBody);
     Inc(Temp, SizeOf(Exec.TMessage));
     Inc(Temp, SizeOf(Exec.TMessage));
-    Owner.FMsgType := mtString;
+    MsgType := 0;
+    Move(Temp^, MsgType, SizeOf(TMessageType));
+    Inc(Temp, SizeOf(TMessageType));    
+    Owner.FMsgType := MsgType;
     Owner.FMsgData.Size := 0;
     Owner.FMsgData.Size := 0;
     Owner.FMsgData.Seek(0, soFrombeginning);
     Owner.FMsgData.Seek(0, soFrombeginning);
     Owner.FMsgData.WriteBuffer(temp^, MsgBody^.mn_Length);
     Owner.FMsgData.WriteBuffer(temp^, MsgBody^.mn_Length);

+ 2 - 2
packages/morphunits/src/exec.pas

@@ -544,7 +544,7 @@ type
   TMemEntry = packed record
   TMemEntry = packed record
     me_Un: packed record
     me_Un: packed record
     case Byte of
     case Byte of
-      0 : (meu_Regs: DWord);
+      0 : (meu_Reqs: DWord);
       1 : (meu_Addr: Pointer)
       1 : (meu_Addr: Pointer)
     end;
     end;
     me_Length: DWord;
     me_Length: DWord;
@@ -555,7 +555,7 @@ type
   TMemList = packed record
   TMemList = packed record
     ml_Node      : TNode;
     ml_Node      : TNode;
     ml_NumEntries: Word;
     ml_NumEntries: Word;
-    ml_ME        : PMemEntry;
+    ml_ME        : array [0..0] of TMemEntry;
   end;
   end;
 
 
 
 

+ 990 - 0
rtl/amicommon/athreads.pp

@@ -0,0 +1,990 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2015 by Karoly Balogh,
+    member of the Free Pascal development team.
+
+    native threadmanager implementation for Amiga-like systems
+
+    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.
+
+ **********************************************************************}
+
+{$mode objfpc}
+unit athreads;
+
+interface
+
+procedure SetAThreadBaseName(s: String);
+
+
+implementation
+
+{ enable this to compile athreads easily outside the RTL }
+{.$DEFINE ATHREADS_STANDALONE}
+
+{$IFDEF ATHREADS_STANDALONE}
+uses
+  exec, amigados, utility;
+{$ELSE}
+{ * Include required system specific includes * }
+{$include execd.inc}
+{$include execf.inc}
+{$include timerd.inc}
+{$include doslibd.inc}
+{$include doslibf.inc}
+{$ENDIF}
+
+const
+  threadvarblocksize : dword = 0;
+
+var
+  SubThreadBaseName: String = 'FPC Subthread';
+
+{.$define DEBUG_MT}
+type
+  TThreadOperation = ( toNone, toStart, toResume, toExit );
+
+type
+  PThreadMsg = ^TThreadMsg;
+
+  PThreadInfo = ^TThreadInfo;
+  TThreadInfo = record
+    threadVars: Pointer;     { have threadvars ptr as first field, so no offset is needed to access it (faster) }
+    threadVarsSize: DWord;   { size of the allocated threadvars block }
+    nextThread: PThreadInfo; { threadinfos are a linked list, using this field }
+    threadPtr: PProcess;     { our thread pointer, as returned by CreateNewProc(). invalid after exited field is true! }
+    threadID: TThreadID;     { thread Unique ID }
+    stackLen: PtrUInt;       { stack size the thread was construced with }
+    exitCode: Pointer;       { exitcode after the process has exited     }
+    f: TThreadFunc;          { ThreadFunc function pointer }
+    p: Pointer;              { ThreadFunc argument }
+    flags: dword;            { Flags this thread were created with }
+    num: longint;            { This was the "num"th thread to created }
+    mainthread: boolean;     { true if this is our main thread }
+    exited: boolean;         { true if the thread has exited, and can be cleaned up }
+    suspended: boolean;      { true if the thread was started suspended, and not resumed yet }
+    mutex: TSignalSemaphore; { thread's mutex. locked during the thread's life. }
+    name: String;            { Thread's name }
+  end;
+
+  TThreadMsg = record
+    tm_MsgNode   : TMessage;
+    tm_ThreadInfo: PThreadInfo;
+    tm_Operation : TThreadOperation;
+  end;
+
+var
+  AThreadManager: TThreadManager;
+  AThreadList: PThreadInfo;
+  AThreadListLen: LongInt;
+  AThreadNum: LongInt;
+  AThreadListSemaphore: TSignalSemaphore;
+
+
+{ Simple IntToStr() replacement which works with ShortStrings }
+function IToStr(const i: LongInt): String;
+begin
+  Str(I,result);
+end;
+
+{$IFDEF DEBUG_MT}
+function IToHStr(const i: LongInt): String;
+begin
+  result:=HexStr(Pointer(i));
+end;
+{$ENDIF}
+
+{ Function to add a thread to the running threads list }
+procedure AddToThreadList(var l: PThreadInfo; ti: PThreadInfo);
+var
+  p     : PThreadInfo;
+  inList: Boolean;
+begin
+  inList:=False;
+  ObtainSemaphore(@AThreadListSemaphore);
+
+  if l = nil then
+    { if the list is not yet allocated, the newly added
+      threadinfo will be the first item }
+    l:=ti
+  else
+    begin
+      { otherwise, look for the last item and append }
+      p:=l;
+      while (p^.nextThread<>nil) do p:=p^.nextThread;
+      p^.nextThread:=ti;
+    end;
+
+  inc(AThreadNum);
+  ti^.num:=AThreadNum;
+  inc(AThreadListLen);
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: thread ID:'+IToHStr(ti^.threadID)+' added, now '+IToStr(AThreadListLen)+' thread(s) in list.');
+{$ENDIF}
+  ReleaseSemaphore(@AThreadListSemaphore);
+end;
+
+{ Function to remove a thread from running threads list }
+function RemoveFromThreadList(var l: PThreadInfo; threadID: TThreadID): boolean;
+var
+  p      : PThreadInfo;
+  pprev  : PThreadInfo;
+  inList : Boolean;
+  tmpNext: PThreadInfo;
+  tmpInfo: PThreadInfo;
+begin
+  inList:=False;
+  if l=nil then
+    begin
+      RemoveFromThreadList:=inList;
+      exit;
+    end;
+
+  ObtainSemaphore(@AThreadListSemaphore);
+  p:=l;
+  pprev:=nil;
+  while (p <> nil) and (p^.threadID <> threadID) do
+    begin
+      pprev:=p;
+      p:=p^.nextThread;
+    end;
+
+  if p <> nil then
+    begin
+      tmpNext:=p^.nextThread;
+      if not p^.mainthread and p^.exited then
+        begin
+{$IFDEF DEBUG_MT}
+          SysDebugLn('FPC AThreads: Releasing resources for thread ID:'+IToHStr(threadID));
+          if (p^.threadVars <> nil) or (p^.threadVarsSize <> 0) then
+            SysDebugLn('FPC AThreads: WARNING, threadvars area wasn''t properly freed!'+IToHStr(threadID));
+{$ENDIF}
+          dispose(p);
+          if pprev <> nil then
+            pprev^.nextThread:=tmpNext;
+          Dec(AThreadListLen);
+        end
+      else
+        begin
+{$IFDEF DEBUG_MT}
+          SysDebugLn('FPC AThreads: Error! Attempt to remove threadID, which is the mainthread or not exited:'+IToHStr(threadID));
+{$ENDIF}
+          inList:=false;
+        end;
+    end
+{$IFDEF DEBUG_MT}
+  else
+    SysDebugLn('FPC AThreads: Error! Attempt to remove threadID, which is not in list:'+IToHstr(threadID))
+{$ENDIF}
+  ;
+  ReleaseSemaphore(@AThreadListSemaphore);
+
+  RemoveFromThreadList:=inList;
+end;
+
+{ Function to return a function's ThreadInfo based on the threadID }
+function GetThreadInfo(var l: PThreadInfo; threadID: TThreadID): PThreadInfo;
+var
+  p     : PThreadInfo;
+  inList: Boolean;
+begin
+  inList:=False;
+  GetThreadInfo:=nil;
+  if l = nil then
+    exit;
+
+  ObtainSemaphoreShared(@AThreadListSemaphore);
+  p:=l;
+  while (p <> nil) and (p^.threadID <> threadID) do
+    p:=p^.nextThread;
+  GetThreadInfo:=p;
+  ReleaseSemaphore(@AThreadListSemaphore);
+end;
+
+{ Get current thread's ThreadInfo structure }
+function GetCurrentThreadInfo: PThreadInfo;
+begin
+  result:=PThreadInfo(PProcess(FindTask(nil))^.pr_Task.tc_UserData);
+end;
+
+{ Returns the number of threads still not exited in our threadlist }
+function CountRunningThreads(var l: PThreadInfo): LongInt;
+var
+  p: PThreadInfo;
+begin
+  CountRunningThreads:=0;
+  ObtainSemaphoreShared(@AThreadListSemaphore);
+  p:=l;
+  while p <> nil do
+    begin
+      inc(CountRunningThreads,ord(not p^.exited));
+      p:=p^.nextThread;
+    end;
+  ReleaseSemaphore(@AThreadListSemaphore);
+end;
+
+{ Helper function for IPC }
+procedure SendMessageToThread(var threadMsg: TThreadMsg; p: PThreadInfo; const op: TThreadOperation; waitReply: boolean);
+var
+  replyPort: PMsgPort;
+begin
+  replyPort:=@PProcess(FindTask(nil))^.pr_MsgPort;
+
+  FillChar(threadMsg,sizeof(threadMsg),0);
+  with threadMsg do
+    begin
+      with tm_MsgNode do
+        begin
+          mn_Node.ln_Type:=NT_MESSAGE;
+          mn_Length:=SizeOf(TThreadMsg);
+          if waitReply then
+            mn_ReplyPort:=replyPort
+          else
+            mn_ReplyPort:=nil;
+        end;
+      tm_ThreadInfo:=p;
+      tm_Operation:=op;
+    end;
+  PutMsg(@p^.threadPtr^.pr_MsgPort,@threadMsg);
+
+  if waitReply then
+    begin
+      WaitPort(replyPort);
+      GetMsg(replyPort);
+    end;
+end;
+
+procedure SetAThreadBaseName(s: String);
+begin
+  ObtainSemaphore(@AThreadListSemaphore);
+  SubThreadBaseName:=s;
+  ReleaseSemaphore(@AThreadListSemaphore);
+end;
+
+function GetAThreadBaseName: String;
+begin
+  ObtainSemaphoreShared(@AThreadListSemaphore);
+  GetAThreadBaseName:=SubThreadBaseName;
+  ReleaseSemaphore(@AThreadListSemaphore);
+end;
+
+
+procedure AInitThreadvar(var offset : dword;size : dword);
+begin
+{$IFDEF DEBUG_MT}
+  {SysDebugLn('FPC AThreads: InitThreadvar');}
+{$ENDIF}
+  offset:=threadvarblocksize;
+  inc(threadvarblocksize,size);
+end;
+
+
+function ARelocateThreadvar(offset : dword) : pointer;
+var
+  p: PThreadInfo;
+begin
+{$IFDEF DEBUG_MT}
+  {SysDebugLn('FPC AThreads: RelocateThreadvar');}
+{$ENDIF}
+  p:=GetCurrentThreadInfo;
+  if (p <> nil) and (p^.threadVars <> nil) then
+    result:=p^.threadVars + Offset
+  else
+    result:=nil;
+end;
+
+
+procedure AAllocateThreadVars;
+var
+  p: PThreadInfo;
+begin
+  { we've to allocate the memory from system  }
+  { because the FPC heap management uses      }
+  { exceptions which use threadvars but       }
+  { these aren't allocated yet ...            }
+  { allocate room on the heap for the thread vars }
+  p:=GetCurrentThreadInfo;
+  if p <> nil then
+    begin
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Allocating threadvars, ID:'+IToHStr(p^.threadID));
+{$endif}
+{$ifdef AMIGA}
+      ObtainSemaphore(ASYS_heapSemaphore);
+{$endif}
+      p^.threadVars:=AllocPooled(ASYS_heapPool,threadvarblocksize);
+      if p^.threadVars = nil then
+        SysDebugLn('FPC AThreads: Failed to allocate threadvar memory!')
+      else
+        begin
+          p^.threadVarsSize:=threadvarblocksize;
+          FillChar(p^.threadVars^,threadvarblocksize,0);
+        end;
+{$ifdef AMIGA}
+      ReleaseSemaphore(ASYS_heapSemaphore);
+{$endif}
+    end
+  else
+    begin
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: AllocateThreadVars: tc_UserData of this process was nil!')
+{$endif}
+    end;
+end;
+
+
+procedure AReleaseThreadVars;
+var
+  p: PThreadInfo;
+begin
+  p:=GetCurrentThreadInfo;
+  if (p <> nil) and (p^.threadVars <> nil) then
+    begin
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Releasing threadvars, ID:'+IToHStr(p^.threadID));
+{$endif}
+{$ifdef AMIGA}
+      ObtainSemaphore(ASYS_heapSemaphore);
+{$endif}
+      FreePooled(ASYS_heapPool,p^.threadVars,p^.threadVarsSize);
+      p^.threadVars:=nil;
+      p^.threadVarsSize:=0;
+{$ifdef AMIGA}
+      ReleaseSemaphore(ASYS_heapSemaphore);
+{$endif}
+    end
+  else
+    begin
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: ReleaseThreadVars: tc_UserData or threadVars area of this process was nil!')
+{$endif}
+    end;
+end;
+
+
+procedure InitAThreading;
+var
+  threadInfo: PThreadInfo;
+  p: PProcess;
+begin
+  if (InterLockedExchange(longint(IsMultiThread),ord(true)) = 0) then
+    begin
+      { We're still running in single thread mode, setup the TLS }
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Entering multithreaded mode...');
+{$endif}
+      p:=PProcess(FindTask(nil));
+      new(threadInfo);
+      FillChar(threadInfo^,sizeof(TThreadInfo),0);
+      p^.pr_Task.tc_UserData:=threadInfo;
+      threadInfo^.mainThread:=true;
+      InitSemaphore(@threadInfo^.mutex);
+      ObtainSemaphore(@threadInfo^.mutex);
+      threadInfo^.threadPtr:=p;
+      threadInfo^.threadID:=TThreadID(threadInfo);
+      InitThreadVars(@ARelocateThreadvar);
+      AddToThreadList(AThreadList,threadInfo);
+    end;
+end;
+
+
+procedure ThreadFunc; cdecl;
+var
+  thisThread: PProcess;
+  threadMsg: PThreadMsg;
+  resumeMsg: PThreadMsg;
+  exitSuspend: boolean; // true if we have to exit instead of resuming
+  threadInfo: PThreadInfo;
+begin
+  thisThread:=PProcess(FindTask(nil));
+
+  { wait for our start message to arrive, then fetch it }
+  WaitPort(@thisThread^.pr_MsgPort);
+  threadMsg:=PThreadMsg(GetMsg(@thisThread^.pr_MsgPort));
+
+  { fetch existing threadinfo from the start message, and set 
+    it to tc_userData, so we can proceed with threadvars }
+  threadInfo:=threadMsg^.tm_ThreadInfo;
+  thisThread^.pr_Task.tc_userData:=threadInfo;
+
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: Entering subthread function, ID:'+hexStr(threadInfo));
+{$endif}
+  { Obtain the threads' mutex, used for exit sync }
+  ObtainSemaphore(@threadInfo^.mutex);
+
+  { Allocate local thread vars, this must be the first thing,
+    because the exception management and io depends on threadvars }
+  AAllocateThreadVars;
+
+  { Rename the thread into something sensible }
+  if threadInfo^.name <> '' then
+    begin
+{$ifdef DEBUG_MT}
+      { this line can't be before threadvar allocation }
+      SysDebugLn('FPC AThreads: Renaming thread ID:'+hexStr(threadInfo)+' to '+threadInfo^.name);
+{$endif}
+      thisThread^.pr_Task.tc_Node.ln_Name:=PChar(@threadInfo^.name[1]);
+    end;
+
+  { Reply the message, so the calling thread could continue }
+  { note that threadMsg was allocated on the caller's task, so }
+  { it will be invalid below this point }
+  ReplyMsg(PMessage(threadMsg));
+
+  { if creating a suspended thread, wait for the wakeup message to arrive }
+  { then check if we actually have to resume, or exit }
+  exitSuspend:=false;
+  if threadInfo^.suspended then
+    begin
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Suspending subthread on entry, ID:'+hexStr(threadInfo));
+{$endif}
+      WaitPort(@thisThread^.pr_MsgPort);
+      resumeMsg:=PThreadMsg(GetMsg(@thisThread^.pr_MsgPort));
+      exitSuspend:=resumeMsg^.tm_Operation <> toResume;
+      threadInfo^.suspended:=false;
+      ReplyMsg(PMessage(resumeMsg));
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Resuming subthread on entry, ID:'+hexStr(threadInfo)+', resumed only to exit: '+IToStr(ord(exitSuspend)));
+{$endif}
+    end;
+
+  { Finally, call the user code }
+  if not exitSuspend then
+    begin
+      InitThread(threadInfo^.stackLen);
+      threadInfo^.exitCode:=Pointer(threadInfo^.f(threadInfo^.p));
+      DoneThread;
+    end;
+
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: Exiting Subthread function, ID:'+hexStr(threadInfo));
+{$endif}
+  Forbid();
+  threadInfo^.exited:=true;
+
+  { Finally, Release our exit mutex. }
+  ReleaseSemaphore(@threadInfo^.mutex);
+end;
+
+
+function CreateNewProcess(const Tags : Array Of PtrUInt) : PProcess;
+begin
+  result:=CreateNewProc(@Tags[0]);
+end;
+
+function ABeginThread(sa : Pointer;stacksize : PtrUInt;
+                      ThreadFunction : tthreadfunc;p : pointer;
+                      creationFlags : dword; var ThreadId : TThreadId) : TThreadID;
+var
+  threadInfo: PThreadInfo;
+  threadMsg: TThreadMsg;
+  threadName: String;
+  subThread: PProcess;
+begin
+  ABeginThread:=TThreadID(0);
+
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: Creating new thread...');
+{$endif DEBUG_MT}
+  { Initialize multithreading if not done }
+  if not IsMultiThread then
+    InitAThreading;
+  { the only way to pass data to the newly created thread
+    in a MT safe way, is to use the heap }
+  new(threadInfo);
+  FillChar(threadInfo^,sizeof(TThreadInfo),0);
+  InitSemaphore(@threadInfo^.mutex);
+  threadInfo^.f:=ThreadFunction;
+  threadInfo^.p:=p;
+
+  if (creationFlags and STACK_SIZE_PARAM_IS_A_RESERVATION) > 0 then
+    threadInfo^.stackLen:=stacksize
+  else
+    threadInfo^.stackLen:=System.StackLength; { inherit parent's stack size }
+  threadInfo^.suspended:=(creationFlags and CREATE_SUSPENDED) > 0;
+
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: Starting new thread... Stack size: '+IToStr(threadInfo^.stackLen));
+{$endif}
+  subThread:=CreateNewProcess([NP_Entry,PtrUInt(@ThreadFunc),
+                               {$IFDEF MORPHOS}
+                               NP_CodeType,CODETYPE_PPC,
+                               NP_PPCStackSize,threadInfo^.stacklen,
+                               {$ELSE}
+                               NP_StackSize,threadInfo^.stacklen,
+                               {$ENDIF}
+                               TAG_DONE]);
+  if subThread = nil then
+    begin
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Failed to start the subthread!');
+{$endif}
+      exit;
+    end;
+  ThreadID:=TThreadID(threadInfo);
+  threadInfo^.threadPtr:=subThread;
+  threadInfo^.threadID:=ThreadID;
+  AddToThreadList(AThreadList,threadInfo);
+
+  { the thread should be started, and waiting for our start message, so send it }
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: Sending start message to subthread and waiting for reply, ID:'+IToHStr(threadID));
+{$endif}
+  { AddToThreadList assigned us a number, so use it to name the thread }
+  threadInfo^.name:=GetAThreadBaseName+' #'+IToStr(threadInfo^.num);
+  SendMessageToThread(threadMsg,threadInfo,toStart,true);
+
+  ABeginThread:=ThreadId;
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: Thread created successfully, ID:'+IToHStr(threadID));
+{$endif}
+end;
+
+
+procedure AEndThread(ExitCode : DWord);
+begin
+  { Do not call DoneThread here. It will be called by the threadfunction, when it exits. }
+end;
+
+
+function ASuspendThread (threadHandle : TThreadID) : dword;
+begin
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: unsupported operation: SuspendThread called for ID:'+IToHStr(threadHandle));
+{$endif}
+  // cannot be properly supported on Amiga
+  result:=dword(-1);
+end;
+
+
+function AResumeThread (threadHandle : TThreadID) : dword;
+var
+  m: TThreadMsg;
+  p: PThreadInfo;
+begin
+  AResumeThread:=0;
+  Forbid();
+  p:=GetThreadInfo(AThreadList,threadHandle);
+  if (p <> nil) and p^.suspended then
+    begin
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Waiting for thread to resume, ID:'+IToHStr(threadHandle));
+{$endif}
+      { WaitPort in SendMessageToThread will break the Forbid() state... }
+      SendMessageToThread(m,p,toResume,true);
+      AResumeThread:=0;
+    end
+  else
+    begin
+      SysDebugLn('FPC AThreads: szijjal gazt:'+hexstr(p)+' mi?'+IToStr(ord(p^.suspended))+' mimi?'+IToStr(ord(p^.exited)));
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Error, attempt to resume a non-suspended thread, or invalid thread ID:'+IToHStr(threadHandle));
+{$endif}
+      AResumeThread:=dword(-1);
+    end;
+  Permit();
+end;
+
+
+procedure AThreadSwitch;  {give time to other threads}
+begin
+  { On Unix, this calls sched_yield();
+    Harry 'Piru' Sintonen recommended to emulate this on Amiga systems with
+    exec/Forbid-exec/Permit pair which is pretty fast to execute and will
+    trigger a rescheduling.
+    Another idea by Frank Mariak was to use exec/SetTaskPri() with the same
+    priority }
+  Forbid();
+  Permit();
+end;
+
+
+function AKillThread (threadHandle : TThreadID) : dword;
+begin
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: unsupported operation: KillThread called for ID:'+IToHStr(threadHandle));
+{$endif}
+  // cannot be properly supported on Amiga
+  AKillThread:=dword(-1);
+end;
+
+
+function ACloseThread (threadHandle : TThreadID) : dword;
+begin
+{$WARNING The return value here seems to be undocumented}
+  RemoveFromThreadList(AThreadList, threadHandle);
+  result:=0;
+end;
+
+
+function AWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;  {0=no timeout}
+var
+  p: PThreadInfo;
+  m: TThreadMsg;
+begin
+{.$WARNING Support for timeout argument is not implemented}
+{ But since CThreads uses pthread_join, which has also no timeout,
+  I don't think this is a big issue. (KB) }
+  AWaitForThreadTerminate:=0;
+  Forbid();
+  p:=GetThreadInfo(AThreadList,threadHandle);
+  if (p <> nil) then
+    begin
+      if not p^.exited then
+        begin
+{$ifdef DEBUG_MT}
+          SysDebugLn('FPC AThreads: Waiting for thread to exit, ID:'+IToHStr(threadHandle));
+{$endif}
+          { WaitPort in SendMessageToThread will break the Forbid() state... }
+          if p^.suspended then
+            begin
+              SendMessageToThread(m,p,toExit,true);
+{$ifdef DEBUG_MT}
+              SysDebugLn('FPC AThreads: Signaled suspended thread to exit, ID:'+IToHStr(threadHandle));
+{$endif}
+            end;
+
+          { Wait for the thread to exit... }
+          Permit();
+          ObtainSemaphore(@p^.mutex);
+          ReleaseSemaphore(@p^.mutex);
+          Forbid();
+        end
+      else
+{$ifdef DEBUG_MT}
+        SysDebugLn('FPC AThreads: Thread already exited, ID:'+IToHStr(threadHandle));
+{$endif}
+      AWaitForThreadTerminate:=DWord(p^.exitCode);
+    end
+  else
+    begin
+{$ifdef DEBUG_MT}
+      SysDebugLn('FPC AThreads: Error, attempt to wait for invalid thread ID to exit, ID:'+IToHStr(threadHandle));
+{$endif}
+      AWaitForThreadTerminate:=dword(-1); { Return non-zero code on error. }
+    end;
+  Permit();
+end;
+
+
+function AThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
+begin
+  {$Warning ThreadSetPriority needs to be implemented}
+  result:=false;
+end;
+
+
+function AThreadGetPriority (threadHandle : TThreadID): Integer;
+begin
+  {$Warning ThreadGetPriority needs to be implemented}
+  result:=0;
+end;
+
+
+function AGetCurrentThreadId : TThreadID;
+begin
+  AGetCurrentThreadId := TThreadID(GetCurrentThreadInfo);
+end;
+
+
+Type  PINTRTLEvent = ^TINTRTLEvent;
+      TINTRTLEvent = record
+        isset: boolean;
+      end;
+
+Function intRTLEventCreate: PRTLEvent;
+
+var p:pintrtlevent;
+
+begin
+  new(p);
+  result:=PRTLEVENT(p);
+end;
+
+procedure intRTLEventDestroy(AEvent: PRTLEvent);
+
+var p:pintrtlevent;
+
+begin
+  p:=pintrtlevent(aevent);
+  dispose(p);
+end;
+
+procedure intRTLEventSetEvent(AEvent: PRTLEvent);
+var p:pintrtlevent;
+
+begin
+  p:=pintrtlevent(aevent);
+  p^.isset:=true;
+end;
+
+
+procedure intRTLEventResetEvent(AEvent: PRTLEvent);
+var p:pintrtlevent;
+
+begin
+  p:=pintrtlevent(aevent);
+  p^.isset:=false;
+end;
+
+
+procedure intRTLEventWaitFor(AEvent: PRTLEvent);
+var p:pintrtlevent;
+
+begin
+  p:=pintrtlevent(aevent);
+  p^.isset:=false;
+end;
+
+procedure intRTLEventWaitForTimeout(AEvent: PRTLEvent;timeout : longint);
+var
+  p : pintrtlevent;
+begin
+  p:=pintrtlevent(aevent);
+end;
+
+
+procedure AInitCriticalSection(var CS);
+begin
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: InitCriticalSection '+hexStr(@CS));
+{$ENDIF}
+  InitSemaphore(PSignalSemaphore(@CS));
+end;
+
+
+procedure AEnterCriticalSection(var CS);
+begin
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: EnterCriticalSection '+hexStr(@CS));
+{$ENDIF}
+  ObtainSemaphore(PSignalSemaphore(@CS));
+end;
+
+
+function ATryEnterCriticalSection(var CS):longint;
+begin
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: TryEnterCriticalSection '+hexStr(@CS));
+{$ENDIF}
+  result:=DWord(AttemptSemaphore(PSignalSemaphore(@CS)));
+  if result<>0 then
+    result:=1;
+end;
+
+
+procedure ALeaveCriticalSection(var CS);
+begin
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: LeaveCriticalSection '+hexStr(@CS));
+{$ENDIF}
+  ReleaseSemaphore(PSignalSemaphore(@CS));
+end;
+
+
+procedure ADoneCriticalSection(var CS);
+begin
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: DoneCriticalSection '+hexStr(@CS));
+{$ENDIF}
+  { unlock as long as unlocking works to unlock it if it is recursive
+    some Delphi code might call this function with a locked mutex }
+  with TSignalSemaphore(CS) do
+    while ss_NestCount > 0 do
+      ReleaseSemaphore(PSignalSemaphore(@CS));
+end;
+
+
+function intBasicEventCreate(EventAttributes : Pointer;
+AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
+begin
+end;
+
+procedure intbasiceventdestroy(state:peventstate);
+begin
+end;
+
+procedure intbasiceventResetEvent(state:peventstate);
+begin
+end;
+
+procedure intbasiceventSetEvent(state:peventstate);
+begin
+end;
+
+function intbasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
+begin
+end;
+
+
+function ASemaphoreInit: Pointer;
+begin
+  result:=nil;
+end;
+
+procedure ASemaphoreDestroy(const FSem: Pointer);
+begin
+end;
+
+procedure ASemaphoreWait(const FSem: Pointer);
+begin
+end;
+
+procedure ASemaphorePost(const FSem: Pointer);
+begin
+end;
+
+
+function AInitThreads : Boolean;
+begin
+{$ifdef DEBUG_MT}
+  SysDebugLn('FPC AThreads: Entering InitThreads...');
+{$endif}
+  result:=true;
+
+  // We assume that if you set the thread manager, the application is multithreading.
+  InitAThreading;
+
+  ThreadID := TThreadID(GetCurrentThreadInfo);
+end;
+
+function ADoneThreads : Boolean;
+begin
+  result:=true;
+end;
+
+
+procedure SetAThreadManager;
+begin
+  with AThreadManager do begin
+    InitManager            :=@AInitThreads;
+    DoneManager            :=@ADoneThreads;
+    BeginThread            :=@ABeginThread;
+    EndThread              :=@AEndThread;
+    SuspendThread          :=@ASuspendThread;
+    ResumeThread           :=@AResumeThread;
+    KillThread             :=@AKillThread;
+    ThreadSwitch           :=@AThreadSwitch;
+    CloseThread            :=@ACloseThread;
+    WaitForThreadTerminate :=@AWaitForThreadTerminate;
+    ThreadSetPriority      :=@AThreadSetPriority;
+    ThreadGetPriority      :=@AThreadGetPriority;
+    GetCurrentThreadId     :=@AGetCurrentThreadId;
+    InitCriticalSection    :=@AInitCriticalSection;
+    DoneCriticalSection    :=@ADoneCriticalSection;
+    EnterCriticalSection   :=@AEnterCriticalSection;
+    TryEnterCriticalSection:=@ATryEnterCriticalSection;
+    LeaveCriticalSection   :=@ALeaveCriticalSection;
+    InitThreadVar          :=@AInitThreadVar;
+    RelocateThreadVar      :=@ARelocateThreadVar;
+    AllocateThreadVars     :=@AAllocateThreadVars;
+    ReleaseThreadVars      :=@AReleaseThreadVars;
+    BasicEventCreate       :=@intBasicEventCreate;
+    BasicEventDestroy      :=@intBasicEventDestroy;
+    BasicEventResetEvent   :=@intBasicEventResetEvent;
+    BasicEventSetEvent     :=@intBasicEventSetEvent;
+    BasiceventWaitFor      :=@intBasicEventWaitFor;
+    rtlEventCreate         :=@intrtlEventCreate;
+    rtlEventDestroy        :=@intrtlEventDestroy;
+    rtlEventSetEvent       :=@intrtlEventSetEvent;
+    rtlEventResetEvent     :=@intrtlEventResetEvent;
+    rtleventWaitForTimeout :=@intrtleventWaitForTimeout;
+    rtleventWaitFor        :=@intrtleventWaitFor;
+    // semaphores
+    SemaphoreInit          :=@ASemaphoreInit;
+    SemaphoreDestroy       :=@ASemaphoreDestroy;
+    SemaphoreWait          :=@ASemaphoreWait;
+    SemaphorePost          :=@ASemaphorePost;
+  end;
+  SetThreadManager(AThreadManager);
+end;
+
+Procedure InitSystemThreads; external name '_FPC_InitSystemThreads';
+
+
+{ This should only be called from the finalization }
+procedure WaitForAllThreads;
+var
+  p: PThreadInfo;
+  pn: PThreadInfo;
+begin
+  { If we are the main thread exiting, we have to wait for our subprocesses to
+    exit. Because AmigaOS won't clean up for us. Also, after exiting the main
+    thread the OS unloads all the code segments with code potentially still
+    running in the background... So even waiting here forever is better than
+    exiting with active threads, which will most likely just kill the OS
+    immediately. (KB) }
+  ObtainSemaphore(@AThreadListSemaphore);
+
+{$IFDEF DEBUG_MT}
+  if AThreadListLen > 1 then
+    begin
+      SysDebugLn('FPC AThreads: We have registered subthreads, checking their status...');
+      if CountRunningThreads(AThreadList) > 1 then
+        SysDebugLn('FPC AThreads: We have running subthreads, waiting for them to exit...');
+    end;
+{$ENDIF}
+
+  while CountRunningThreads(AThreadList) > 1 do
+    begin
+      ReleaseSemaphore(@AThreadListSemaphore);
+      DOSDelay(1);
+      { Reobtain the semaphore... }
+      ObtainSemaphore(@AThreadListSemaphore);
+    end;
+
+  if AThreadListLen > 1 then
+    begin
+{$IFDEF DEBUG_MT}
+      SysDebugLn('FPC AThreads: All threads exited but some lacking cleanup - trying to free up resources...');
+{$ENDIF}
+      p:=AThreadList;
+      while p <> nil do
+        begin
+          pn:=p^.nextThread;
+          if not p^.mainThread then
+            RemoveFromThreadList(AThreadList,p^.threadID);
+          p:=pn;
+        end;
+    end
+  else
+    begin
+{$IFDEF DEBUG_MT}
+      SysDebugLn('FPC AThreads: All threads exited normally.');
+{$ENDIF}
+    end;
+  ReleaseSemaphore(@AThreadListSemaphore);
+end;
+
+initialization
+  initsystemthreads;
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: Unit Initialization');
+{$ENDIF}
+  if ThreadingAlreadyUsed then
+    begin
+      writeln('Threading has been used before athreads was initialized.');
+      writeln('Make athreads one of the first units in your uses clause!');
+      runerror(211);
+    end;
+  AThreadList:=nil;
+  AThreadListLen:=0;
+  AThreadNum:=-1; { Mainthread will be 0. }
+  InitSemaphore(@AThreadListSemaphore);
+  SetAThreadManager;
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: Unit Initialization Done');
+{$ENDIF}
+finalization
+{$IFDEF DEBUG_MT}
+  SysDebugLn('FPC AThreads: Unit Finalization');
+{$ENDIF}
+  WaitForAllThreads;
+end.

+ 17 - 0
rtl/amicommon/osdebug.inc

@@ -38,6 +38,23 @@ begin
   RawPutChar(#10);
   RawPutChar(#10);
 end;
 end;
 
 
+procedure SysDebug(const s: ShortString); platform;
+var
+  i: LongInt;
+begin
+  for i:=1 to Length(s) do
+    RawPutChar(s[i]);
+end;
+
+procedure SysDebugLn(const s: ShortString); platform;
+var
+  i: LongInt;
+begin
+  for i:=1 to Length(s) do
+    RawPutChar(s[i]);
+  RawPutChar(#10);
+end;
+
 procedure SysDebugLn; {$IFDEF SYSTEMINLINE}inline;{$ENDIF} platform;
 procedure SysDebugLn; {$IFDEF SYSTEMINLINE}inline;{$ENDIF} platform;
 begin
 begin
   RawPutChar(#10);
   RawPutChar(#10);

+ 2 - 0
rtl/amicommon/osdebugh.inc

@@ -15,4 +15,6 @@
 
 
 procedure SysDebug(const s: RawByteString);
 procedure SysDebug(const s: RawByteString);
 procedure SysDebugLn(const s: RawByteString);
 procedure SysDebugLn(const s: RawByteString);
+procedure SysDebug(const s: ShortString);
+procedure SysDebugLn(const s: ShortString);
 procedure SysDebugLn;
 procedure SysDebugLn;

+ 9 - 0
rtl/amicommon/sysfile.inc

@@ -40,6 +40,7 @@ var
   tmpHandle : LongInt;
   tmpHandle : LongInt;
 begin
 begin
   if l=nil then exit;
   if l=nil then exit;
+  ObtainSemaphore(ASYS_fileSemaphore);
 
 
   { First, close all tracked files }
   { First, close all tracked files }
   tmpNext:=l^.next;
   tmpNext:=l^.next;
@@ -58,6 +59,7 @@ begin
     l:=l^.next;
     l:=l^.next;
     dispose(tmpNext);
     dispose(tmpNext);
   end;
   end;
+  ReleaseSemaphore(ASYS_fileSemaphore);
 end;
 end;
 
 
 { Function to be called to add a file to the opened file list }
 { Function to be called to add a file to the opened file list }
@@ -67,6 +69,8 @@ var
   inList: Boolean;
   inList: Boolean;
 begin
 begin
   inList:=False;
   inList:=False;
+  ObtainSemaphore(ASYS_fileSemaphore);
+
   if l<>nil then begin
   if l<>nil then begin
     { if there is a valid filelist, search for the value }
     { if there is a valid filelist, search for the value }
     { in the list to avoid double additions }
     { in the list to avoid double additions }
@@ -93,6 +97,7 @@ begin
     RawDoFmt('FPC_FILE_DEBUG: Error! Trying add filehandle a filehandle twice: $%lx !'+#10,@h,pointer(1),nil);
     RawDoFmt('FPC_FILE_DEBUG: Error! Trying add filehandle a filehandle twice: $%lx !'+#10,@h,pointer(1),nil);
 {$ENDIF}
 {$ENDIF}
   ;
   ;
+  ReleaseSemaphore(ASYS_fileSemaphore);
 end;
 end;
 
 
 { Function to be called to remove a file from the list }
 { Function to be called to remove a file from the list }
@@ -108,6 +113,7 @@ begin
     exit;
     exit;
   end;
   end;
 
 
+  ObtainSemaphore(ASYS_fileSemaphore);
   p:=l;
   p:=l;
   while (p^.next<>nil) and (not inList) do
   while (p^.next<>nil) and (not inList) do
     if p^.next^.handle=h then inList:=True
     if p^.next^.handle=h then inList:=True
@@ -123,6 +129,7 @@ begin
     RawDoFmt('FPC_FILE_DEBUG: Error! Trying to remove not existing filehandle: $%lx !'+#10,@h,pointer(1),nil);
     RawDoFmt('FPC_FILE_DEBUG: Error! Trying to remove not existing filehandle: $%lx !'+#10,@h,pointer(1),nil);
 {$ENDIF}
 {$ENDIF}
   ;
   ;
+  ReleaseSemaphore(ASYS_fileSemaphore);
 
 
   RemoveFromList:=inList;
   RemoveFromList:=inList;
 end;
 end;
@@ -140,6 +147,7 @@ begin
     exit;
     exit;
   end;
   end;
 
 
+  ObtainSemaphore(ASYS_fileSemaphore);
   p:=l;
   p:=l;
   while (p^.next<>nil) and (inList=nil) do
   while (p^.next<>nil) and (inList=nil) do
     if p^.next^.handle=h then inList:=p^.next
     if p^.next^.handle=h then inList:=p^.next
@@ -150,6 +158,7 @@ begin
     RawDoFmt('FPC_FILE_DEBUG: Warning! Check for not existing filehandle: $%lx !'+#10,@h,pointer(1),nil);
     RawDoFmt('FPC_FILE_DEBUG: Warning! Check for not existing filehandle: $%lx !'+#10,@h,pointer(1),nil);
 {$ENDIF}
 {$ENDIF}
 
 
+  ReleaseSemaphore(ASYS_fileSemaphore);
   CheckInList:=inList;
   CheckInList:=inList;
 end;
 end;
 
 

+ 14 - 4
rtl/amicommon/sysosh.inc

@@ -23,9 +23,19 @@ type
   THandle = LongInt;
   THandle = LongInt;
 {$endif CPU64}
 {$endif CPU64}
   TThreadID = THandle;
   TThreadID = THandle;
-  
+
   PRTLCriticalSection = ^TRTLCriticalSection;
   PRTLCriticalSection = ^TRTLCriticalSection;
+{$IFDEF AROS}
   TRTLCriticalSection = Pointer;
   TRTLCriticalSection = Pointer;
-
-
-
+{$ELSE}
+  TRTLCriticalSection = record
+    { This must actually be bigger or equal to sizeof(TSignalSemaphore)
+      which seems to be 46 bytes on MorphOS and Amiga/m68k. }
+    semaphore: array[0..63] of byte;
+  end;
+{$ENDIF}
+
+{ BeginThread flags we support in AThreads }
+const
+  CREATE_SUSPENDED = 1;
+  STACK_SIZE_PARAM_IS_A_RESERVATION = 2;

+ 2 - 2
rtl/amicommon/sysutils.pp

@@ -63,7 +63,7 @@ uses
 {$i sysutils.inc}
 {$i sysutils.inc}
 
 
 
 
-{ * Include sytem specific includes * }
+{ * Include system specific includes * }
 {$include execd.inc}
 {$include execd.inc}
 {$include execf.inc}
 {$include execf.inc}
 {$include timerd.inc}
 {$include timerd.inc}
@@ -900,7 +900,7 @@ end;
 procedure Sleep(Milliseconds: cardinal);
 procedure Sleep(Milliseconds: cardinal);
 begin
 begin
   // Amiga dos.library Delay() has precision of 1/50 seconds
   // Amiga dos.library Delay() has precision of 1/50 seconds
-  Delay(Milliseconds div 20);
+  DOSDelay(Milliseconds div 20);
 end;
 end;
 
 
 
 

+ 125 - 0
rtl/amicommon/tthread.inc

@@ -0,0 +1,125 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2015 by Karoly Balogh,
+    member of the Free Pascal development team.
+
+    native TThread implementation for Amiga-like systems
+
+    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.
+
+ **********************************************************************}
+
+{ Thread management routines }
+
+{ Based on the Win32 version, but since that mostly just wraps to a stock
+  ThreadManager, it was relatively straightforward to get this working,
+  after we had a ThreadManager (AThreads) (KB) }
+
+procedure TThread.SysCreate(CreateSuspended: Boolean;
+                            const StackSize: SizeUInt);
+begin
+  FSuspended := CreateSuspended;
+  FInitialSuspended := CreateSuspended;
+  { Always start in suspended state, will be resumed in AfterConstruction if necessary
+    See Mantis #16884 }
+  FHandle := BeginThread(nil, StackSize, @ThreadProc, pointer(self), 1{CREATE_SUSPENDED},
+                         FThreadID);
+  if FHandle = TThreadID(0) then
+    raise EThread.CreateFmt(SThreadCreateError, ['Cannot create thread.']);
+
+  FFatalException := nil;
+end;
+
+
+procedure TThread.SysDestroy;
+begin
+  if FHandle<>0 then
+    begin
+      { Don't check Suspended. If the thread has been externally suspended (which is
+        deprecated and strongly discouraged), it's better to deadlock here than
+        to silently free the object and leave OS resources leaked. }
+      if not FFinished {and not Suspended} then
+        begin
+          Terminate;
+          { Allow the thread function to perform the necessary cleanup. Since
+            we've just set Terminated flag, it won't call Execute. }
+          if FInitialSuspended then
+            Start;
+          WaitFor;
+        end;
+    end;
+
+  FFatalException.Free;
+  FFatalException := nil;
+end;
+
+procedure TThread.CallOnTerminate;
+begin
+  FOnTerminate(Self);
+end;
+
+procedure TThread.DoTerminate;
+begin
+  if Assigned(FOnTerminate) then
+    Synchronize(@CallOnTerminate);
+end;
+
+{const
+  Priorities: array [TThreadPriority] of Integer =
+   (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,
+    THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL,
+    THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL);}
+
+function TThread.GetPriority: TThreadPriority;
+var
+  P: Integer;
+  I: TThreadPriority;
+begin
+{  P := GetThreadPriority(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
+//  SetThreadPriority(FHandle, Priorities[Value]);
+end;
+
+
+procedure TThread.SetSuspended(Value: Boolean);
+begin
+  if Value <> FSuspended then
+    if Value then
+      Suspend
+    else
+      Resume;
+end;
+
+procedure TThread.Suspend;
+begin
+  { Unsupported, but lets have it... }
+  FSuspended := True;
+  SuspendThread(FHandle);
+end;
+
+procedure TThread.Resume;
+begin
+  if ResumeThread(FHandle) = 1 then FSuspended := False;
+end;
+
+procedure TThread.Terminate;
+begin
+  FTerminated := True;
+end;
+
+function TThread.WaitFor: Integer;
+begin
+  result:=WaitForThreadTerminate(FThreadID,0);
+  FFinished:=(result = 0);
+end;

+ 1 - 1
rtl/amiga/m68k/doslibf.inc

@@ -111,7 +111,7 @@ SysCall AOS_DOSBase 186;
 function DateStamp(date: PDateStamp location 'd1'): PDateStamp;
 function DateStamp(date: PDateStamp location 'd1'): PDateStamp;
 SysCall AOS_DOSBase 192;
 SysCall AOS_DOSBase 192;
 
 
-procedure Delay(timeout: LongInt location 'd1');
+procedure DOSDelay(timeout: LongInt location 'd1');
 SysCall AOS_DOSBase 198;
 SysCall AOS_DOSBase 198;
 
 
 function WaitForChar(file1  : LongInt location 'd1';
 function WaitForChar(file1  : LongInt location 'd1';

+ 66 - 0
rtl/amiga/m68k/m68kamiga.inc

@@ -0,0 +1,66 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2015 by Karoly Balogh,
+    member of the Free Pascal development team.
+
+    m68k/Amiga atomic operations implementation
+
+    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.
+
+ **********************************************************************}
+
+{ The Amiga hardware doesn't support the m68k CPU's atomic operations
+  like TAS, CAS, CAS2 and so on. Therefore we must "emulate" them from
+  software. The easiest way is the Forbid()/Permit() OS call pair around
+  the ops themselves. It of course won't be hardware-atomic, but should
+  be safe for multithreading. (KB) }
+
+function InterLockedDecrement (var Target: longint) : longint;
+  begin
+    Forbid;
+    Dec(Target);
+    Result := Target;
+    Permit;
+  end;
+
+
+function InterLockedIncrement (var Target: longint) : longint;
+  begin
+    Forbid;
+    Inc(Target);
+    Result := Target;
+    Permit;
+  end;
+
+
+function InterLockedExchange (var Target: longint;Source : longint) : longint;
+  begin
+    Forbid;
+    Result := Target;
+    Target := Source;
+    Permit;
+  end;
+
+
+function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint;
+  begin
+    Forbid;
+    Result := Target;
+    Target := Target + Source;
+    Permit;
+  end;
+
+
+function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint;
+  begin
+    Forbid;
+    Result := Target;
+    if Target = Comperand then
+      Target := NewValue;
+    Permit;
+  end;

+ 8 - 0
rtl/amiga/system.pp

@@ -80,6 +80,7 @@ var
 
 
   ASYS_heapPool : Pointer; { pointer for the OS pool for growing the heap }
   ASYS_heapPool : Pointer; { pointer for the OS pool for growing the heap }
   ASYS_heapSemaphore: Pointer; { 68k OS from 3.x has no MEMF_SEM_PROTECTED for pools, have to do it ourselves }
   ASYS_heapSemaphore: Pointer; { 68k OS from 3.x has no MEMF_SEM_PROTECTED for pools, have to do it ourselves }
+  ASYS_fileSemaphore: Pointer; { mutex semaphore for filelist access arbitration }
   ASYS_origDir  : LongInt; { original directory on startup }
   ASYS_origDir  : LongInt; { original directory on startup }
   AOS_wbMsg    : Pointer; public name '_WBenchMsg'; { the "public" part is amunits compatibility kludge }
   AOS_wbMsg    : Pointer; public name '_WBenchMsg'; { the "public" part is amunits compatibility kludge }
   _WBenchMsg   : Pointer; external name '_WBenchMsg'; { amunits compatibility kludge }
   _WBenchMsg   : Pointer; external name '_WBenchMsg'; { amunits compatibility kludge }
@@ -113,6 +114,7 @@ implementation
 
 
 {$I system.inc}
 {$I system.inc}
 {$I osdebug.inc}
 {$I osdebug.inc}
+{$I m68kamiga.inc}
 
 
 {$IFDEF AMIGAOS4}
 {$IFDEF AMIGAOS4}
   // Required to allow opening of utility library interface...
   // Required to allow opening of utility library interface...
@@ -355,8 +357,14 @@ begin
   ASYS_heapPool:=CreatePool(MEMF_FAST,growheapsize2,growheapsize1);
   ASYS_heapPool:=CreatePool(MEMF_FAST,growheapsize2,growheapsize1);
   if ASYS_heapPool=nil then Halt(1);
   if ASYS_heapPool=nil then Halt(1);
   ASYS_heapSemaphore:=AllocPooled(ASYS_heapPool,sizeof(TSignalSemaphore));
   ASYS_heapSemaphore:=AllocPooled(ASYS_heapPool,sizeof(TSignalSemaphore));
+  if ASYS_heapSemaphore = nil then Halt(1);
   InitSemaphore(ASYS_heapSemaphore);
   InitSemaphore(ASYS_heapSemaphore);
 
 
+  { Initialize semaphore for filelist access arbitration }
+  ASYS_fileSemaphore:=AllocPooled(ASYS_heapPool,sizeof(TSignalSemaphore));
+  if ASYS_fileSemaphore = nil then Halt(1);
+  InitSemaphore(ASYS_fileSemaphore);
+
   if AOS_wbMsg=nil then begin
   if AOS_wbMsg=nil then begin
     StdInputHandle:=dosInput;
     StdInputHandle:=dosInput;
     StdOutputHandle:=dosOutput;
     StdOutputHandle:=dosOutput;

+ 0 - 157
rtl/amiga/tthread.inc

@@ -1,157 +0,0 @@
-{
-    This file is part of the Free Component Library (FCL)
-    Copyright (c) 1999-2002 by the Free Pascal development team
-
-    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.
-
- **********************************************************************}
-
-{****************************************************************************}
-{*                             TThread                                      *}
-{****************************************************************************}
-
-{$WARNING This file is only a stub, and will not work!}
-
-const
- ThreadCount: longint = 0;
-
-(* Implementation of exported functions *)
-
-procedure AddThread (T: TThread);
-begin
- Inc (ThreadCount);
-end;
-
-
-procedure RemoveThread (T: TThread);
-begin
- Dec (ThreadCount);
-end;
-
-
-procedure TThread.CallOnTerminate;
-begin
- FOnTerminate (Self);
-end;
-
-
-function TThread.GetPriority: TThreadPriority;
-var
-{ PTIB: PThreadInfoBlock;
- PPIB: PProcessInfoBlock;}
- I: TThreadPriority;
-begin
-{
- DosGetInfoBlocks (@PTIB, @PPIB);
- with PTIB^.TIB2^ do
-  if Priority >= $300 then GetPriority := tpTimeCritical else
-      if Priority < $200 then GetPriority := tpIdle else
-  begin
-   I := Succ (Low (TThreadPriority));
-   while (I < High (TThreadPriority)) and
-    (Priority - Priorities [I] <= Priorities [Succ (I)] - Priority) do Inc (I);
-   GetPriority := I;
-  end;
-}
-end;
-
-
-procedure TThread.SetPriority(Value: TThreadPriority);
-{var
- PTIB: PThreadInfoBlock;
- PPIB: PProcessInfoBlock;}
-begin
-{ DosGetInfoBlocks (@PTIB, @PPIB);}
-(*
- PTIB^.TIB2^.Priority := Priorities [Value];
-*)
-{
- DosSetPriority (2, High (Priorities [Value]),
-                     Low (Priorities [Value]) - PTIB^.TIB2^.Priority, FHandle);}
-end;
-
-
-procedure TThread.SetSuspended(Value: Boolean);
-begin
- if Value <> FSuspended then
- begin
-  if Value then Suspend else Resume;
- end;
-end;
-
-
-procedure TThread.DoTerminate;
-begin
- if Assigned (FOnTerminate) then Synchronize (@CallOnTerminate);
-end;
-
-
-procedure TThread.SysCreate(CreateSuspended: Boolean;
-                            const StackSize: SizeUInt);
-var
-  Flags: cardinal;
-begin
-  AddThread (Self);
-{
-  FSuspended := CreateSuspended;
-  Flags := dtStack_Commited;
-  if FSuspended then Flags := Flags or dtSuspended;
-  if DosCreateThread (cardinal (FThreadID), @ThreadProc, pointer (Self),
-                                                        Flags, 16384) <> 0 then
-  begin
-   FFinished := true;
-   Destroy;
-  end else FHandle := FThreadID;
-  IsMultiThread := true;
-  FFatalException := nil;
-}
-end;
-
-
-procedure TThread.SysDestroy;
-begin
- if not FFinished and not Suspended then
- begin
-  Terminate;
-  WaitFor;
- end;
-{
- if FHandle <> -1 then DosKillThread (cardinal (FHandle));
- FFatalException.Free;
- FFatalException := nil;
- inherited Destroy;
- RemoveThread (Self);
-}
-end;
-
-procedure TThread.Resume;
-begin
-{ FSuspended := not (DosResumeThread (cardinal (FHandle)) = 0);}
-end;
-
-
-procedure TThread.Suspend;
-begin
-{ FSuspended := DosSuspendThread (cardinal (FHandle)) = 0;}
-end;
-
-
-procedure TThread.Terminate;
-begin
- FTerminated := true;
-end;
-
-
-function TThread.WaitFor: Integer;
-var
- FH: cardinal;
-begin
-{ WaitFor := DosWaitThread (FH, dtWait);}
-end;
-
-

+ 2 - 2
rtl/aros/arosthreads.inc

@@ -322,7 +322,7 @@ end;
 
 
 procedure EmptyFunc;
 procedure EmptyFunc;
 begin
 begin
-  Delay(1);
+  DOSDelay(1);
   ReleaseSemaphore(@AROSThreadStruct^.EmptySemaphore);
   ReleaseSemaphore(@AROSThreadStruct^.EmptySemaphore);
 end;
 end;
 
 
@@ -379,7 +379,7 @@ begin
       NP_Entry, PtrUInt(@EmptyFunc),
       NP_Entry, PtrUInt(@EmptyFunc),
       TAG_DONE, TAG_END]);
       TAG_DONE, TAG_END]);
     ObtainSemaphore(@AROSThreadStruct^.EmptySemaphore);
     ObtainSemaphore(@AROSThreadStruct^.EmptySemaphore);
-    Delay(1);
+    DOSDelay(1);
   end;
   end;
   //
   //
   NewThread^.Task := CreateNewProcTags([
   NewThread^.Task := CreateNewProcTags([

+ 1 - 1
rtl/aros/i386/doslibf.inc

@@ -34,7 +34,7 @@ function IoErr: longint; syscall AOS_DOSBase 22;
 procedure dosExit(ErrCode: longint); syscall AOS_DOSBase 24;
 procedure dosExit(ErrCode: longint); syscall AOS_DOSBase 24;
 function SetProtection(const name: PChar; protect: longword): LongInt; syscall AOS_DOSBase 31;
 function SetProtection(const name: PChar; protect: longword): LongInt; syscall AOS_DOSBase 31;
 function DateStamp(date: PDateStamp): PDateStamp; syscall AOS_DOSBase 32;
 function DateStamp(date: PDateStamp): PDateStamp; syscall AOS_DOSBase 32;
-procedure Delay(ticks: LongWord); syscall AOS_DOSBase 33;
+procedure dosDelay(ticks: LongWord); syscall AOS_DOSBase 33;
 function AllocDosObject(Type_: LongWord; const Tags: PTagItem): Pointer; syscall AOS_DOSBase 38;
 function AllocDosObject(Type_: LongWord; const Tags: PTagItem): Pointer; syscall AOS_DOSBase 38;
 procedure FreeDosObject(Type_: LongWord; Ptr: Pointer); syscall AOS_DOSBase 39;
 procedure FreeDosObject(Type_: LongWord; Ptr: Pointer); syscall AOS_DOSBase 39;
 function SetFileDate(name: PChar; date: PDateStamp): LongBool; syscall AOS_DOSBase 66;
 function SetFileDate(name: PChar; date: PDateStamp): LongBool; syscall AOS_DOSBase 66;

+ 5 - 1
rtl/aros/i386/execf.inc

@@ -2,7 +2,7 @@
     This file is part of the Free Pascal run time library.
     This file is part of the Free Pascal run time library.
     Copyright (c) 2006 Karoly Balogh
     Copyright (c) 2006 Karoly Balogh
 
 
-    exec functions (V40) for Amiga/PowerPC
+    exec functions for AROS/i386
 
 
     See the file COPYING.FPC, included in this distribution,
     See the file COPYING.FPC, included in this distribution,
     for details about the copyright.
     for details about the copyright.
@@ -28,6 +28,7 @@ function AllocSignal(signalNum: LongInt): ShortInt; syscall LocalExecBase 55;
 procedure FreeSignal(signalNum: LongInt); syscall LocalExecBase 56;
 procedure FreeSignal(signalNum: LongInt); syscall LocalExecBase 56;
 procedure AddPort(port: PMsgPort); syscall LocalExecBase 59;
 procedure AddPort(port: PMsgPort); syscall LocalExecBase 59;
 procedure RemPort(port: PMsgPort); syscall LocalExecBase 60;
 procedure RemPort(port: PMsgPort); syscall LocalExecBase 60;
+procedure PutMsg(Port: PMsgPort; Message: PMessage); syscall AOS_ExecBase 61;
 function GetMsg(port: PMsgPort): PMessage; syscall LocalExecBase 62;
 function GetMsg(port: PMsgPort): PMessage; syscall LocalExecBase 62;
 procedure ReplyMsg(message : pMessage); syscall LocalExecBase 63;
 procedure ReplyMsg(message : pMessage); syscall LocalExecBase 63;
 function WaitPort(port: PMsgPort): PMessage; syscall LocalExecBase 64;
 function WaitPort(port: PMsgPort): PMessage; syscall LocalExecBase 64;
@@ -40,6 +41,9 @@ procedure InitSemaphore(SigSem: PSignalSemaphore); syscall AOS_ExecBase 93;
 procedure ObtainSemaphore(SigSem: PSignalSemaphore); syscall AOS_ExecBase 94;
 procedure ObtainSemaphore(SigSem: PSignalSemaphore); syscall AOS_ExecBase 94;
 procedure ReleaseSemaphore(SigSem: PSignalSemaphore); syscall AOS_ExecBase 95;
 procedure ReleaseSemaphore(SigSem: PSignalSemaphore); syscall AOS_ExecBase 95;
 function AttemptSemaphore(SigSem: PSignalSemaphore): LongWord; syscall AOS_ExecBase 96;
 function AttemptSemaphore(SigSem: PSignalSemaphore): LongWord; syscall AOS_ExecBase 96;
+function CreateMsgPort: PMsgPort; syscall AOS_ExecBase 111;
+procedure DeleteMsgPort(Port: PMsgPort); syscall AOS_ExecBase 112;
+procedure ObtainSemaphoreShared(SigSem: PSignalSemaphore); syscall AOS_ExecBase 113;
 function CreatePool(requirements: Cardinal; puddleSize: Cardinal; threshSize: Cardinal): Pointer; syscall LocalExecBase 116;
 function CreatePool(requirements: Cardinal; puddleSize: Cardinal; threshSize: Cardinal): Pointer; syscall LocalExecBase 116;
 procedure DeletePool(poolHeader: Pointer); syscall LocalExecBase 117;
 procedure DeletePool(poolHeader: Pointer); syscall LocalExecBase 117;
 function AllocPooled(poolHeader: Pointer; memSize: Cardinal): Pointer; syscall LocalExecBase 118;
 function AllocPooled(poolHeader: Pointer; memSize: Cardinal): Pointer; syscall LocalExecBase 118;

+ 65 - 50
rtl/aros/system.pp

@@ -67,6 +67,7 @@ var
   AROS_ThreadLib : Pointer; public name 'AROS_THREADLIB';
   AROS_ThreadLib : Pointer; public name 'AROS_THREADLIB';
 
 
   ASYS_heapPool : Pointer; { pointer for the OS pool for growing the heap }
   ASYS_heapPool : Pointer; { pointer for the OS pool for growing the heap }
+  ASYS_fileSemaphore: Pointer; { mutex semaphore for filelist access arbitration }
   ASYS_origDir  : LongInt; { original directory on startup }
   ASYS_origDir  : LongInt; { original directory on startup }
   AOS_wbMsg    : Pointer;
   AOS_wbMsg    : Pointer;
   AOS_ConName  : PChar ='CON:10/30/620/100/FPC Console Output/AUTO/CLOSE/WAIT';
   AOS_ConName  : PChar ='CON:10/30/620/100/FPC Console Output/AUTO/CLOSE/WAIT';
@@ -141,7 +142,7 @@ begin
   //
   //
   if AOS_wbMsg <> nil then
   if AOS_wbMsg <> nil then
   begin
   begin
-    // forbid -> Amiga RKM Libraries Manual 
+    // forbid -> Amiga RKM Libraries Manual
     Forbid();
     Forbid();
     // Reply WBStartupMessage
     // Reply WBStartupMessage
     ReplyMsg(AOS_wbMsg);
     ReplyMsg(AOS_wbMsg);
@@ -150,6 +151,50 @@ begin
   HaltProc(ExitCode);
   HaltProc(ExitCode);
 end;
 end;
 
 
+function GetWBArgsNum: Integer;
+var
+  startup: PWBStartup;
+begin
+  GetWBArgsNum := 0;
+  Startup := nil;
+  Startup := PWBStartup(AOS_wbMsg);
+  if Startup <> nil then
+  begin
+    Result := Startup^.sm_NumArgs - 1;
+  end;
+end;
+
+function GetWBArg(Idx: Integer): string;
+var
+  startup: PWBStartup;
+  wbarg: PWBArgList;
+  Path: array[0..254] of Char;
+  strPath: string;
+  Len: Integer;
+begin
+  GetWBArg := '';
+  FillChar(Path[0],255,#0);
+  Startup := PWBStartup(AOS_wbMsg);
+  if Startup <> nil then
+  begin
+    //if (Idx >= 0) and (Idx < Startup^.sm_NumArgs) then
+    begin
+      wbarg := Startup^.sm_ArgList;
+      if NameFromLock(wbarg^[Idx + 1].wa_Lock,@Path[0],255) then
+      begin
+        Len := 0;
+        while (Path[Len] <> #0) and (Len < 254) do
+          Inc(Len);
+        if Len > 0 then
+          if (Path[Len - 1] <> ':') and (Path[Len - 1] <> '/') then
+            Path[Len] := '/';
+        strPath := Path;
+      end;
+      Result := strPath + wbarg^[Idx + 1].wa_Name;
+    end;
+  end;
+end;
+
 { Generates correct argument array on startup }
 { Generates correct argument array on startup }
 procedure GenerateArgs;
 procedure GenerateArgs;
 var
 var
@@ -175,6 +220,7 @@ var
   Start: Word;
   Start: Word;
   Ende: Word;
   Ende: Word;
   LocalIndex: Word;
   LocalIndex: Word;
+  i: Integer;
   P : PChar;
   P : PChar;
   {$H+}
   {$H+}
   Temp : string;
   Temp : string;
@@ -192,7 +238,14 @@ begin
   { check if we're started from Workbench }
   { check if we're started from Workbench }
   if AOS_wbMsg <> nil then
   if AOS_wbMsg <> nil then
   begin
   begin
-    ArgC := 0;
+    ArgC := GetWBArgsNum + 1;
+    for i := 1 to ArgC - 1 do
+    begin
+      Temp := GetWBArg(i);
+      AllocArg(i, Length(Temp));
+      Move(Temp[1], Argv[i]^, Length(Temp));
+      Argv[i][Length(Temp)] := #0;
+    end;
     Exit;
     Exit;
   end;
   end;
 
 
@@ -215,7 +268,7 @@ begin
     begin
     begin
       while (p[count]<>#0) and (p[count]<>'"') and (p[count]<>LineEnding) do
       while (p[count]<>#0) and (p[count]<>'"') and (p[count]<>LineEnding) do
       begin
       begin
-        Inc(Count) 
+        Inc(Count)
       end;
       end;
     end else
     end else
     begin
     begin
@@ -239,7 +292,7 @@ begin
     end;
     end;
     if inQuotes and (p[count] = '"') then
     if inQuotes and (p[count] = '"') then
       Inc(Count);
       Inc(Count);
-    inQuotes := False; 
+    inQuotes := False;
   end;
   end;
   argc:=localindex;
   argc:=localindex;
 end;
 end;
@@ -297,50 +350,6 @@ end;
                              ParamStr/Randomize
                              ParamStr/Randomize
 *****************************************************************************}
 *****************************************************************************}
 
 
-function GetWBArgsNum: Integer;
-var
-  startup: PWBStartup;
-begin
-  GetWBArgsNum := 0;
-  Startup := nil;
-  Startup := PWBStartup(AOS_wbMsg);
-  if Startup <> nil then
-  begin
-    Result := Startup^.sm_NumArgs - 1;
-  end;
-end;
-
-function GetWBArg(Idx: Integer): string;
-var
-  startup: PWBStartup;
-  wbarg: PWBArgList;
-  Path: array[0..254] of Char;
-  strPath: string;
-  Len: Integer;
-begin
-  GetWBArg := '';
-  FillChar(Path[0],255,#0);
-  Startup := PWBStartup(AOS_wbMsg);
-  if Startup <> nil then
-  begin
-    //if (Idx >= 0) and (Idx < Startup^.sm_NumArgs) then
-    begin
-      wbarg := Startup^.sm_ArgList;
-      if NameFromLock(wbarg^[Idx + 1].wa_Lock,@Path[0],255) then
-      begin
-        Len := 0;
-        while (Path[Len] <> #0) and (Len < 254) do
-          Inc(Len);
-        if Len > 0 then
-          if (Path[Len - 1] <> ':') and (Path[Len - 1] <> '/') then
-            Path[Len] := '/';
-        strPath := Path;
-      end;
-      Result := strPath + wbarg^[Idx + 1].wa_Name;
-    end;
-  end;
-end;
-
 { number of args }
 { number of args }
 function paramcount : longint;
 function paramcount : longint;
 begin
 begin
@@ -401,12 +410,18 @@ begin
   AOS_UtilityBase := OpenLibrary('utility.library', 0);
   AOS_UtilityBase := OpenLibrary('utility.library', 0);
   if AOS_UtilityBase = nil then
   if AOS_UtilityBase = nil then
     Halt(1);
     Halt(1);
-    
+
   { Creating the memory pool for growing heap }
   { Creating the memory pool for growing heap }
   ASYS_heapPool := CreatePool(MEMF_ANY or MEMF_SEM_PROTECTED, growheapsize2, growheapsize1);
   ASYS_heapPool := CreatePool(MEMF_ANY or MEMF_SEM_PROTECTED, growheapsize2, growheapsize1);
   if ASYS_heapPool = nil then
   if ASYS_heapPool = nil then
     Halt(1);
     Halt(1);
-  
+
+  { Initialize semaphore for filelist access arbitration }
+  ASYS_fileSemaphore:=AllocPooled(ASYS_heapPool,sizeof(TSignalSemaphore));
+  if ASYS_fileSemaphore = nil then
+    Halt(1);
+  InitSemaphore(ASYS_fileSemaphore);
+
   if AOS_wbMsg = nil then begin
   if AOS_wbMsg = nil then begin
     StdInputHandle := THandle(dosInput);
     StdInputHandle := THandle(dosInput);
     StdOutputHandle := THandle(dosOutput);
     StdOutputHandle := THandle(dosOutput);

+ 1 - 1
rtl/aros/systhrd.inc

@@ -153,7 +153,7 @@ end;
 
 
 procedure SysThreadSwitch;
 procedure SysThreadSwitch;
 begin
 begin
-  Delay(0);
+  DOSDelay(0);
 end;
 end;
 
 
 function SysSuspendThread(ThreadHandle: THandle): dword;
 function SysSuspendThread(ThreadHandle: THandle): dword;

+ 2 - 1
rtl/m68k/m68k.inc

@@ -384,7 +384,7 @@ asm
 @LMEMSET3:
 @LMEMSET3:
 end;
 end;
 
 
-
+{$IFNDEF HASAMIGA}
 function InterLockedDecrement (var Target: longint) : longint;
 function InterLockedDecrement (var Target: longint) : longint;
   begin
   begin
   {$warning FIX ME}
   {$warning FIX ME}
@@ -424,6 +424,7 @@ function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comp
     if Target = Comperand then
     if Target = Comperand then
       Target := NewValue;
       Target := NewValue;
   end;
   end;
+{$ENDIF HASAMIGA}
 
 
 {$if defined(CPUM68K_HAS_BYTEREV) or defined(CPUM68K_HAS_ROLROR)}
 {$if defined(CPUM68K_HAS_BYTEREV) or defined(CPUM68K_HAS_ROLROR)}
 { Disabled for now, because not all cases below were tested. (KB) }
 { Disabled for now, because not all cases below were tested. (KB) }

+ 1 - 1
rtl/morphos/doslibf.inc

@@ -114,7 +114,7 @@ SysCall MOS_DOSBase 186;
 function DateStamp(date: PDateStamp location 'd1'): PDateStamp;
 function DateStamp(date: PDateStamp location 'd1'): PDateStamp;
 SysCall MOS_DOSBase 192;
 SysCall MOS_DOSBase 192;
 
 
-procedure Delay(timeout: LongInt location 'd1');
+procedure DOSDelay(timeout: LongInt location 'd1');
 SysCall MOS_DOSBase 198;
 SysCall MOS_DOSBase 198;
 
 
 function WaitForChar(file1  : LongInt location 'd1';
 function WaitForChar(file1  : LongInt location 'd1';

+ 2 - 2
rtl/morphos/execd.inc

@@ -490,7 +490,7 @@ type
   TMemEntry = packed record
   TMemEntry = packed record
     me_Un: packed record
     me_Un: packed record
     case Byte of
     case Byte of
-      0 : (meu_Regs: DWord);
+      0 : (meu_Reqs: DWord);
       1 : (meu_Addr: Pointer)
       1 : (meu_Addr: Pointer)
     end;
     end;
     me_Length: DWord;
     me_Length: DWord;
@@ -501,7 +501,7 @@ type
   TMemList = packed record
   TMemList = packed record
     ml_Node      : TNode;
     ml_Node      : TNode;
     ml_NumEntries: Word;
     ml_NumEntries: Word;
-    ml_ME        : PMemEntry;
+    ml_ME        : array [0..0] of TMemEntry;
   end;
   end;
 
 
 
 

+ 0 - 33
rtl/morphos/sysosh.inc

@@ -1,33 +0,0 @@
-{
-    This file is part of the Free Pascal run time library.
-    Copyright (c) 2001 by Free Pascal development team
-
-    This file implements all the base types and limits required
-    for a minimal POSIX compliant subset required to port the compiler
-    to a new OS.
-
-    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.
-
- **********************************************************************}
-
-{Platform specific information}
-type
-{$ifdef CPU64}
-  THandle = Int64;
-{$else CPU64}
-  THandle = Longint;
-{$endif CPU64}
-  TThreadID = THandle;
-  
-  PRTLCriticalSection = ^TRTLCriticalSection;
-  TRTLCriticalSection = record
-   Locked: boolean
-  end;
-
-
-

+ 6 - 0
rtl/morphos/system.pp

@@ -64,6 +64,7 @@ var
   MOS_UtilityBase: Pointer;
   MOS_UtilityBase: Pointer;
 
 
   ASYS_heapPool : Pointer; { pointer for the OS pool for growing the heap }
   ASYS_heapPool : Pointer; { pointer for the OS pool for growing the heap }
+  ASYS_fileSemaphore: Pointer; { mutex semaphore for filelist access arbitration }
   ASYS_origDir  : LongInt; { original directory on startup }
   ASYS_origDir  : LongInt; { original directory on startup }
   MOS_ambMsg   : Pointer;
   MOS_ambMsg   : Pointer;
   MOS_ConName  : PChar ='CON:10/30/620/100/FPC Console Output/AUTO/CLOSE/WAIT';
   MOS_ConName  : PChar ='CON:10/30/620/100/FPC Console Output/AUTO/CLOSE/WAIT';
@@ -367,6 +368,11 @@ begin
  { Creating the memory pool for growing heap }
  { Creating the memory pool for growing heap }
  ASYS_heapPool:=CreatePool(MEMF_FAST or MEMF_SEM_PROTECTED,growheapsize2,growheapsize1);
  ASYS_heapPool:=CreatePool(MEMF_FAST or MEMF_SEM_PROTECTED,growheapsize2,growheapsize1);
  if ASYS_heapPool=nil then Halt(1);
  if ASYS_heapPool=nil then Halt(1);
+ 
+ { Initialize semaphore for filelist access arbitration }
+ ASYS_fileSemaphore:=AllocPooled(ASYS_heapPool,sizeof(TSignalSemaphore));
+ if ASYS_fileSemaphore = nil then Halt(1);
+ InitSemaphore(ASYS_fileSemaphore);
 
 
  if MOS_ambMsg=nil then begin
  if MOS_ambMsg=nil then begin
    MOS_ConHandle:=0;
    MOS_ConHandle:=0;

+ 0 - 157
rtl/morphos/tthread.inc

@@ -1,157 +0,0 @@
-{
-    This file is part of the Free Component Library (FCL)
-    Copyright (c) 1999-2002 by the Free Pascal development team
-
-    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.
-
- **********************************************************************}
-
-{****************************************************************************}
-{*                             TThread                                      *}
-{****************************************************************************}
-
-{$WARNING This file is only a stub, and will not work!}
-
-const
- ThreadCount: longint = 0;
-
-(* Implementation of exported functions *)
-
-procedure AddThread (T: TThread);
-begin
- Inc (ThreadCount);
-end;
-
-
-procedure RemoveThread (T: TThread);
-begin
- Dec (ThreadCount);
-end;
-
-
-procedure TThread.CallOnTerminate;
-begin
- FOnTerminate (Self);
-end;
-
-
-function TThread.GetPriority: TThreadPriority;
-var
-{ PTIB: PThreadInfoBlock;
- PPIB: PProcessInfoBlock;}
- I: TThreadPriority;
-begin
-{
- DosGetInfoBlocks (@PTIB, @PPIB);
- with PTIB^.TIB2^ do
-  if Priority >= $300 then GetPriority := tpTimeCritical else
-      if Priority < $200 then GetPriority := tpIdle else
-  begin
-   I := Succ (Low (TThreadPriority));
-   while (I < High (TThreadPriority)) and
-    (Priority - Priorities [I] <= Priorities [Succ (I)] - Priority) do Inc (I);
-   GetPriority := I;
-  end;
-}
-end;
-
-
-procedure TThread.SetPriority(Value: TThreadPriority);
-{var
- PTIB: PThreadInfoBlock;
- PPIB: PProcessInfoBlock;}
-begin
-{ DosGetInfoBlocks (@PTIB, @PPIB);}
-(*
- PTIB^.TIB2^.Priority := Priorities [Value];
-*)
-{
- DosSetPriority (2, High (Priorities [Value]),
-                     Low (Priorities [Value]) - PTIB^.TIB2^.Priority, FHandle);}
-end;
-
-
-procedure TThread.SetSuspended(Value: Boolean);
-begin
- if Value <> FSuspended then
- begin
-  if Value then Suspend else Resume;
- end;
-end;
-
-
-procedure TThread.DoTerminate;
-begin
- if Assigned (FOnTerminate) then Synchronize (@CallOnTerminate);
-end;
-
-
-procedure TThread.SysCreate(CreateSuspended: Boolean;
-                            const StackSize: SizeUInt);
-var
-  Flags: cardinal;
-begin
-  AddThread (Self);
-{
-  FSuspended := CreateSuspended;
-  Flags := dtStack_Commited;
-  if FSuspended then Flags := Flags or dtSuspended;
-  if DosCreateThread (cardinal (FThreadID), @ThreadProc, pointer (Self),
-                                                        Flags, 16384) <> 0 then
-  begin
-   FFinished := true;
-   Destroy;
-  end else FHandle := FThreadID;
-  IsMultiThread := true;
-  FFatalException := nil;
-}
-end;
-
-
-procedure TThread.SysDestroy;
-begin
- if not FFinished and not Suspended then
- begin
-  Terminate;
-  WaitFor;
- end;
-{
- if FHandle <> -1 then DosKillThread (cardinal (FHandle));
- FFatalException.Free;
- FFatalException := nil;
- inherited Destroy;
- RemoveThread (Self);
-}
-end;
-
-procedure TThread.Resume;
-begin
-{ FSuspended := not (DosResumeThread (cardinal (FHandle)) = 0);}
-end;
-
-
-procedure TThread.Suspend;
-begin
-{ FSuspended := DosSuspendThread (cardinal (FHandle)) = 0;}
-end;
-
-
-procedure TThread.Terminate;
-begin
- FTerminated := true;
-end;
-
-
-function TThread.WaitFor: Integer;
-var
- FH: cardinal;
-begin
-{ WaitFor := DosWaitThread (FH, dtWait);}
-end;
-
-

+ 4 - 0
rtl/objpas/classes/classesh.inc

@@ -1628,6 +1628,10 @@ type
     FSem: Pointer;
     FSem: Pointer;
     FCond: Pointer;
     FCond: Pointer;
     FInitialSuspended: boolean;
     FInitialSuspended: boolean;
+{$endif}
+{$if defined(amiga) or defined(morphos)}
+  private
+    FInitialSuspended: boolean;
 {$endif}
 {$endif}
   public
   public
     constructor Create(CreateSuspended: Boolean;
     constructor Create(CreateSuspended: Boolean;