Переглянути джерело

* Split in common implementation an platform dependent implementation

sg 23 роки тому
батько
коміт
32b9486692

+ 414 - 44
packages/base/libasync/libasync.inc

@@ -2,10 +2,10 @@
     $Id$
 
     libasync: Asynchronous event management
-    Copyright (C) 2001 by
+    Copyright (C) 2001-2002 by
       Areca Systems GmbH / Sebastian Guenther, [email protected]
 
-    Common interface declaration
+    Common implementation
 
     See the file COPYING.FPC, included in this distribution,
     for details about the copyright.
@@ -16,104 +16,474 @@
 }
 
 type
-  TAsyncHandleStruct = packed record
+  PTimerData = ^TTimerData;
+  TTimerData = record
+    Next: PTimerData;
+    MSec: LongInt;
+    NextTick: Int64;
+    Callback: TAsyncCallback;
     UserData: Pointer;
-    Data: TAsyncData;
+    Periodic: Boolean;
   end;
-  TAsyncHandle = ^TAsyncHandleStruct;
 
-  TAsyncTimer = Pointer;
+  TCallbackTypes = set of (cbRead, cbWrite);
 
-  TAsyncCallback = procedure(UserData: Pointer); cdecl;
 
-  TAsyncResult = (
-    asyncOK,
-    asyncInvalidHandle,
-    asyncInvalidFileHandle,
-    asyncHandlerAlreadySet);
+{ An implementation unit has to implement the following fordward procedures,
+  and additionally asyncGetTicks }
 
+procedure InternalInit(Handle: TAsyncHandle); forward;
 
-// Construction and destruction
+procedure InternalFree(Handle: TAsyncHandle); forward;
 
-procedure asyncInit(
-  Handle: TAsyncHandle); cdecl;
+procedure InternalRun(Handle: TAsyncHandle; TimeOut: Int64); forward;
 
-procedure asyncFree(
-  Handle: TAsyncHandle); cdecl;
+procedure InternalInitIOCallback(Handle: TAsyncHandle; Data: PIOCallbackData;
+  InitData: Boolean; CallbackTypes: TCallbackTypes); forward;
 
+procedure InternalClearIOCallback(Handle: TAsyncHandle; IOHandle: LongInt;
+  CallbackTypes: TCallbackTypes); forward;
 
-// Running and stopping the event loop
 
-procedure asyncRun(
-  Handle: TAsyncHandle); cdecl;
 
-procedure asyncBreak(
-  Handle: TAsyncHandle); cdecl;
+function InitIOCallback(Handle: TAsyncHandle; IOHandle: LongInt;
+  ARead: Boolean; ReadCallback: TAsyncCallback; ReadUserData: Pointer;
+  AWrite: Boolean; WriteCallback: TAsyncCallback; WriteUserData: Pointer):
+  TAsyncResult;
+var
+  Data: PIOCallbackData;
+  NeedData: Boolean;
+  CallbackTypes: TCallbackTypes;
+begin
+  if IOHandle > MaxHandle then
+  begin
+    Result := asyncInvalidFileHandle;
+    exit;
+  end;
+
+  NeedData := True;
+  Data := Handle^.Data.FirstIOCallback;
+  while Assigned(Data) do
+  begin
+    if Data^.IOHandle = IOHandle then
+    begin
+      if ARead then
+      begin
+        if Assigned(Data^.ReadCallback) then
+	begin
+	  Result := asyncHandlerAlreadySet;
+	  exit;
+	end;
+        Data^.ReadCallback := ReadCallback;
+	Data^.ReadUserData := ReadUserData;
+      end;
+      if AWrite then
+      begin
+        if Assigned(Data^.WriteCallback) then
+	begin
+	  Result := asyncHandlerAlreadySet;
+	  exit;
+	end;
+        Data^.WriteCallback := WriteCallback;
+	Data^.WriteUserData := WriteUserData;
+      end;
+      NeedData := False;
+      break;
+    end;
+    Data := Data^.Next;
+  end;
+
+  if NeedData then
+  begin
+    New(Data);
+    Data^.Next := Handle^.Data.FirstIOCallback;
+    Handle^.Data.FirstIOCallback := Data;
+    Data^.IOHandle := IOHandle;
+    if ARead then
+    begin
+      Data^.ReadCallback := ReadCallback;
+      Data^.ReadUserData := ReadUserData;
+    end else
+      Data^.ReadCallback := nil;
+    if AWrite then
+    begin
+      Data^.WriteCallback := WriteCallback;
+      Data^.WriteUserData := WriteUserData;
+    end else
+      Data^.WriteCallback := nil;
+  end;
 
+  CallbackTypes := [];
+  if ARead then
+    CallbackTypes := [cbRead];
+  if AWrite then
+    CallbackTypes := CallbackTypes + [cbWrite];
+  InternalInitIOCallback(Handle, Data, NeedData, CallbackTypes);
+
+  Handle^.Data.HasCallbacks := True;
+  Result := asyncOK;
+end;
+
+procedure CheckForCallbacks(Handle: TAsyncHandle);
+begin
+  if (Handle^.Data.HasCallbacks) and
+    (not Assigned(Handle^.Data.FirstIOCallback)) and
+    (not Assigned(Handle^.Data.FirstTimer)) then
+    Handle^.Data.HasCallbacks := False;
+end;
+
+
+procedure asyncInit(Handle: TAsyncHandle); cdecl;
+begin
+  InternalInit(Handle);
+end;
+
+procedure asyncFree(Handle: TAsyncHandle); cdecl;
+var
+  Timer, NextTimer: PTimerData;
+  IOCallback, NextIOCallback: PIOCallbackData;
+begin
+  InternalFree(Handle);
+
+  Timer := PTimerData(Handle^.Data.FirstTimer);
+  while Assigned(Timer) do
+  begin
+    NextTimer := Timer^.Next;
+    Dispose(Timer);
+    Timer := NextTimer;
+  end;
 
-// Status information
+  IOCallback := PIOCallbackData(Handle^.Data.FirstIOCallback);
+  while Assigned(IOCallback) do
+  begin
+    NextIOCallback := IOCallback^.Next;
+    Dispose(IOCallback);
+    IOCallback := NextIOCallback;
+  end;
 
-function asyncIsRunning(
-  Handle: TAsyncHandle
-  ): Boolean; cdecl;
+  Handle^.Data.NextIOCallback := nil;
+end;
+
+procedure asyncRun(Handle: TAsyncHandle); cdecl;
+var
+  Timer, NextTimer: PTimerData;
+  TimeOut, CurTime, NextTick: Int64;
+begin
+  if Handle^.Data.IsRunning then
+    exit;
+
+  Handle^.Data.DoBreak := False;
+  Handle^.Data.IsRunning := True;
+
+  // Prepare timers
+  if Assigned(Handle^.Data.FirstTimer) then
+  begin
+    CurTime := asyncGetTicks;
+    Timer := Handle^.Data.FirstTimer;
+    while Assigned(Timer) do
+    begin
+      Timer^.NextTick := CurTime + Timer^.MSec;
+      Timer := Timer^.Next;
+    end;
+  end;
 
-function asyncGetTicks: Int64; cdecl;
+  while (not Handle^.Data.DoBreak) and Handle^.Data.HasCallbacks do
+  begin
+    Timer := Handle^.Data.FirstTimer;
+    if Assigned(Handle^.Data.FirstTimer) then
+    begin
+      // Determine when the next timer tick will happen
+      CurTime := asyncGetTicks;
+      NextTick := High(Int64);
+      Timer := Handle^.Data.FirstTimer;
+      while Assigned(Timer) do
+      begin
+        if Timer^.NextTick < NextTick then
+	  NextTick := Timer^.NextTick;
+	Timer := Timer^.Next;
+      end;
+      TimeOut := NextTick - CurTime;
+      if TimeOut < 0 then
+        TimeOut := 0;
+    end else
+      TimeOut := -1;
+
+    InternalRun(Handle, TimeOut);
+
+    {if Handle^.Data.HighestHandle >= 0 then
+    begin
+      CurReadFDSet := PFDSet(Handle^.Data.FDData)[0];
+      CurWriteFDSet := PFDSet(Handle^.Data.FDData)[1];
+      AsyncResult := Select(Handle^.Data.HighestHandle + 1,
+        @CurReadFDSet, @CurWriteFDSet, nil, TimeOut);
+    end else
+      AsyncResult := Select(0, nil, nil, nil, TimeOut);
+
+    if (AsyncResult > 0) and not Handle^.Data.DoBreak then
+    begin
+      // Check for I/O events
+      Handle^.Data.CurIOCallback := Handle^.Data.FirstIOCallback;
+      while Assigned(Handle^.Data.CurIOCallback) do
+      begin
+        CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
+        Handle^.Data.NextIOCallback := CurIOCallback^.Next;
+	if FD_IsSet(CurIOCallback^.IOHandle, CurReadFDSet) and
+	  FD_IsSet(CurIOCallback^.IOHandle, PFDSet(Handle^.Data.FDData)[0]) and
+	  Assigned(CurIOCallback^.ReadCallback) then
+	begin
+	  CurIOCallback^.ReadCallback(CurIOCallback^.ReadUserData);
+	  if Handle^.Data.DoBreak then
+	    break;
+	end;
+
+	CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
+	if Assigned(CurIOCallback) and
+	  FD_IsSet(CurIOCallback^.IOHandle, CurWriteFDSet) and
+	  FD_IsSet(CurIOCallback^.IOHandle, PFDSet(Handle^.Data.FDData)[1]) and
+	  Assigned(CurIOCallback^.WriteCallback) then
+	begin
+	  CurIOCallback^.WriteCallback(CurIOCallback^.WriteUserData);
+	  if Handle^.Data.DoBreak then
+	    break;
+	end;
+
+	Handle^.Data.CurIOCallback := Handle^.Data.NextIOCallback;
+      end;
+    end;}
+
+    if Assigned(Handle^.Data.FirstTimer) then
+    begin
+      // Check for triggered timers
+      CurTime := asyncGetTicks;
+      Timer := Handle^.Data.FirstTimer;
+      while Assigned(Timer) do
+      begin
+        if Timer^.NextTick <= CurTime then
+	begin
+	  Timer^.Callback(Timer^.UserData);
+	  NextTimer := Timer^.Next;
+	  if Timer^.Periodic then
+	    Inc(Timer^.NextTick, Timer^.MSec)
+	  else
+	    asyncRemoveTimer(Handle, Timer);
+	  if Handle^.Data.DoBreak then
+	    break;
+	  Timer := NextTimer;
+	end else
+	  Timer := Timer^.Next;
+      end;
+    end;
+
+  end;
+  Handle^.Data.CurIOCallback := nil;
+  Handle^.Data.NextIOCallback := nil;
+  Handle^.Data.IsRunning := False;
+end;
 
+procedure asyncBreak(Handle: TAsyncHandle); cdecl;
+begin
+  Handle^.Data.DoBreak := True;
+end;
 
-// Timer management
+function asyncIsRunning(Handle: TAsyncHandle): Boolean; cdecl;
+begin
+  Result := Handle^.Data.IsRunning;
+end;
 
 function asyncAddTimer(
   Handle: TAsyncHandle;
   MSec: LongInt;
-  Periodic: Boolean;		// False = One-shot timer, True = Periodic timer
+  Periodic: Boolean;
   Callback: TAsyncCallback;
-  UserData: Pointer		// User data for callback
+  UserData: Pointer
   ): TAsyncTimer; cdecl;
+var
+  Data: PTimerData;
+begin
+  if not Assigned(Callback) then
+    exit;
+
+  New(Data);
+  Result := Data;
+  Data^.Next := Handle^.Data.FirstTimer;
+  Handle^.Data.FirstTimer := Data;
+  Data^.MSec := MSec;
+  Data^.Periodic := Periodic;
+  Data^.Callback := Callback;
+  Data^.UserData := UserData;
+  if Handle^.Data.IsRunning then
+    Data^.NextTick := asyncGetTicks + MSec;
+
+  Handle^.Data.HasCallbacks := True;
+end;
 
 procedure asyncRemoveTimer(
   Handle: TAsyncHandle;
   Timer: TASyncTimer); cdecl;
-
-
-// I/O callback management
+var
+  Data, CurData, PrevData, NextData: PTimerData;
+begin
+  Data := PTimerData(Timer);
+  CurData := Handle^.Data.FirstTimer;
+  PrevData := nil;
+  while Assigned(CurData) do
+  begin
+    NextData := CurData^.Next;
+    if CurData = Data then
+    begin
+      if Assigned(PrevData) then
+        PrevData^.Next := NextData
+      else
+        Handle^.Data.FirstTimer := NextData;
+      break;
+    end;
+    PrevData := CurData;
+    CurData := NextData;
+  end;
+  Dispose(Data);
+  CheckForCallbacks(Handle);
+end;
 
 function asyncSetIOCallback(
   Handle: TAsyncHandle;
   IOHandle: LongInt;
   Callback: TAsyncCallback;
   UserData: Pointer): TAsyncResult; cdecl;
+begin
+  Result := InitIOCallback(Handle, IOHandle, True, Callback, UserData,
+    True, Callback, UserData);
+end;
 
-procedure asyncClearIOCallback(
-  Handle: TAsyncHandle;
+procedure asyncClearIOCallback(Handle: TAsyncHandle;
   IOHandle: LongInt); cdecl;
+var
+  CurData, PrevData, NextData: PIOCallbackData;
+begin
+  CurData := Handle^.Data.FirstIOCallback;
+  PrevData := nil;
+  while Assigned(CurData) do
+  begin
+    NextData := CurData^.Next;
+    if CurData^.IOHandle = IOHandle then
+    begin
+      if Handle^.Data.CurIOCallback = CurData then
+        Handle^.Data.CurIOCallback := nil;
+      if Handle^.Data.NextIOCallback = CurData then
+        Handle^.Data.NextIOCallback := NextData;
+
+      InternalClearIOCallback(Handle, IOHandle, [cbRead, cbWrite]);
+
+      if Assigned(PrevData) then
+        PrevData^.Next := NextData
+      else
+        Handle^.Data.FirstIOCallback := NextData;
+      Dispose(CurData);
+      break;
+    end;
+    PrevData := CurData;
+    CurData := NextData;
+  end;
+  CheckForCallbacks(Handle);
+end;
 
 function asyncSetDataAvailableCallback(
   Handle: TAsyncHandle;
   IOHandle: LongInt;
   Callback: TAsyncCallback;
   UserData: Pointer): TAsyncResult; cdecl;
+begin
+  Result := InitIOCallback(Handle, IOHandle, True, Callback, UserData, False,
+    nil, nil);
+end;
 
-procedure asyncClearDataAvailableCallback(
-  Handle: TAsyncHandle;
+procedure asyncClearDataAvailableCallback(Handle: TAsyncHandle;
   IOHandle: LongInt); cdecl;
+var
+  CurData, PrevData, NextData: PIOCallbackData;
+begin
+  CurData := Handle^.Data.FirstIOCallback;
+  PrevData := nil;
+  while Assigned(CurData) do
+  begin
+    NextData := CurData^.Next;
+    if CurData^.IOHandle = IOHandle then
+    begin
+      if Handle^.Data.CurIOCallback = CurData then
+        Handle^.Data.CurIOCallback := nil;
+      if Handle^.Data.NextIOCallback = CurData then
+        Handle^.Data.NextIOCallback := NextData;
+
+      InternalClearIOCallback(Handle, IOHandle, [cbRead]);
+
+      if Assigned(CurData^.WriteCallback) then
+        CurData^.ReadCallback := nil
+      else
+      begin
+        if Assigned(PrevData) then
+          PrevData^.Next := NextData
+        else
+          Handle^.Data.FirstIOCallback := NextData;
+        Dispose(CurData);
+      end;
+      break;
+    end;
+    PrevData := CurData;
+    CurData := NextData;
+  end;
+  CheckForCallbacks(Handle);
+end;
 
 function asyncSetCanWriteCallback(
   Handle: TAsyncHandle;
   IOHandle: LongInt;
   Callback: TAsyncCallback;
   UserData: Pointer): TAsyncResult; cdecl;
+begin
+  Result := InitIOCallback(Handle, IOHandle, False, nil, nil, True,
+    Callback, UserData);
+end;
 
-procedure asyncClearCanWriteCallback(
-  Handle: TAsyncHandle;
+procedure asyncClearCanWriteCallback(Handle: TAsyncHandle;
   IOHandle: LongInt); cdecl;
+var
+  CurData, PrevData, NextData: PIOCallbackData;
+begin
+  CurData := Handle^.Data.FirstIOCallback;
+  PrevData := nil;
+  while Assigned(CurData) do
+  begin
+    NextData := CurData^.Next;
+    if CurData^.IOHandle = IOHandle then
+    begin
+      if Handle^.Data.CurIOCallback = CurData then
+        Handle^.Data.CurIOCallback := nil;
+      if Handle^.Data.NextIOCallback = CurData then
+        Handle^.Data.NextIOCallback := NextData;
+
+      InternalClearIOCallback(Handle, IOHandle, [cbWrite]);
+
+      if Assigned(CurData^.ReadCallback) then
+        CurData^.WriteCallback := nil
+      else
+      begin
+        if Assigned(PrevData) then
+          PrevData^.Next := NextData
+        else
+          Handle^.Data.FirstIOCallback := NextData;
+        Dispose(CurData);
+      end;
+      break;
+    end;
+    PrevData := CurData;
+    CurData := NextData;
+  end;
+  CheckForCallbacks(Handle);
+end;
 
 
 {
   $Log$
-  Revision 1.3  2002-09-15 15:43:30  sg
-  * Improved error reporting
-
-  Revision 1.1  2002/01/29 17:54:53  peter
-    * splitted to base and extra
+  Revision 1.4  2002-09-25 21:53:39  sg
+  * Split in common implementation an platform dependent implementation
 
 }

+ 116 - 0
packages/base/libasync/libasynch.inc

@@ -0,0 +1,116 @@
+{
+    $Id$
+
+    libasync: Asynchronous event management
+    Copyright (C) 2001-2002 by
+      Areca Systems GmbH / Sebastian Guenther, [email protected]
+
+    Common interface declaration
+
+    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.
+}
+
+type
+  TAsyncHandleStruct = packed record
+    UserData: Pointer;
+    Data: TAsyncData;
+  end;
+  TAsyncHandle = ^TAsyncHandleStruct;
+
+  TAsyncTimer = Pointer;
+
+  TAsyncCallback = procedure(UserData: Pointer); cdecl;
+
+  TAsyncResult = (
+    asyncOK,
+    asyncInvalidHandle,
+    asyncInvalidFileHandle,
+    asyncHandlerAlreadySet);
+
+
+// Construction and destruction
+
+procedure asyncInit(
+  Handle: TAsyncHandle); cdecl;
+
+procedure asyncFree(
+  Handle: TAsyncHandle); cdecl;
+
+
+// Running and stopping the event loop
+
+procedure asyncRun(
+  Handle: TAsyncHandle); cdecl;
+
+procedure asyncBreak(
+  Handle: TAsyncHandle); cdecl;
+
+
+// Status information
+
+function asyncIsRunning(
+  Handle: TAsyncHandle
+  ): Boolean; cdecl;
+
+function asyncGetTicks: Int64; cdecl;
+
+
+// Timer management
+
+function asyncAddTimer(
+  Handle: TAsyncHandle;
+  MSec: LongInt;
+  Periodic: Boolean;		// False = One-shot timer, True = Periodic timer
+  Callback: TAsyncCallback;
+  UserData: Pointer		// User data for callback
+  ): TAsyncTimer; cdecl;
+
+procedure asyncRemoveTimer(
+  Handle: TAsyncHandle;
+  Timer: TASyncTimer); cdecl;
+
+
+// I/O callback management
+
+function asyncSetIOCallback(
+  Handle: TAsyncHandle;
+  IOHandle: LongInt;
+  Callback: TAsyncCallback;
+  UserData: Pointer): TAsyncResult; cdecl;
+
+procedure asyncClearIOCallback(
+  Handle: TAsyncHandle;
+  IOHandle: LongInt); cdecl;
+
+function asyncSetDataAvailableCallback(
+  Handle: TAsyncHandle;
+  IOHandle: LongInt;
+  Callback: TAsyncCallback;
+  UserData: Pointer): TAsyncResult; cdecl;
+
+procedure asyncClearDataAvailableCallback(
+  Handle: TAsyncHandle;
+  IOHandle: LongInt); cdecl;
+
+function asyncSetCanWriteCallback(
+  Handle: TAsyncHandle;
+  IOHandle: LongInt;
+  Callback: TAsyncCallback;
+  UserData: Pointer): TAsyncResult; cdecl;
+
+procedure asyncClearCanWriteCallback(
+  Handle: TAsyncHandle;
+  IOHandle: LongInt); cdecl;
+
+
+{
+  $Log$
+  Revision 1.1  2002-09-25 21:53:39  sg
+  * Split in common implementation an platform dependent implementation
+
+}

+ 71 - 422
packages/base/libasync/unix/libasync.pp

@@ -34,7 +34,7 @@ type
     HighestHandle: LongInt;
   end;
 
-{$INCLUDE libasync.inc}
+{$INCLUDE libasynch.inc}
 
 
 
@@ -43,23 +43,13 @@ implementation
 {$ifdef VER1_0}
 uses Linux;
 {$else}
-Uses Unix;
+uses Unix;
 {$endif}
 
 const
   MaxHandle = SizeOf(TFDSet) * 8 - 1;
 
 type
-  PTimerData = ^TTimerData;
-  TTimerData = record
-    Next: PTimerData;
-    MSec: LongInt;
-    NextTick: Int64;
-    Callback: TAsyncCallback;
-    UserData: Pointer;
-    Periodic: Boolean;
-  end;
-
   PIOCallbackData = ^TIOCallbackData;
   TIOCallbackData = record
     Next: PIOCallbackData;
@@ -69,242 +59,48 @@ type
     SavedHandleFlags: LongInt;
   end;
 
-
-
-function InitIOCallback(Handle: TAsyncHandle; IOHandle: LongInt;
-  ARead: Boolean; ReadCallback: TAsyncCallback; ReadUserData: Pointer;
-  AWrite: Boolean; WriteCallback: TAsyncCallback; WriteUserData: Pointer):
-  TAsyncResult;
-var
-  Data: PIOCallbackData;
-  i: LongInt;
-  NeedData: Boolean;
-begin
-  if IOHandle > MaxHandle then
-  begin
-    Result := asyncInvalidFileHandle;
-    exit;
-  end;
-
-  NeedData := True;
-  Data := Handle^.Data.FirstIOCallback;
-  while Assigned(Data) do
-  begin
-    if Data^.IOHandle = IOHandle then
-    begin
-      if ARead then
-      begin
-        if Assigned(Data^.ReadCallback) then
-	begin
-	  Result := asyncHandlerAlreadySet;
-	  exit;
-	end;
-        Data^.ReadCallback := ReadCallback;
-	Data^.ReadUserData := ReadUserData;
-      end;
-      if AWrite then
-      begin
-        if Assigned(Data^.WriteCallback) then
-	begin
-	  Result := asyncHandlerAlreadySet;
-	  exit;
-	end;
-        Data^.WriteCallback := WriteCallback;
-	Data^.WriteUserData := WriteUserData;
-      end;
-      NeedData := False;
-      break;
-    end;
-    Data := Data^.Next;
-  end;
-
-  if NeedData then
-  begin
-    New(Data);
-    Data^.Next := Handle^.Data.FirstIOCallback;
-    Handle^.Data.FirstIOCallback := Data;
-    Data^.IOHandle := IOHandle;
-    if ARead then
-    begin
-      Data^.ReadCallback := ReadCallback;
-      Data^.ReadUserData := ReadUserData;
-    end else
-      Data^.ReadCallback := nil;
-    if AWrite then
-    begin
-      Data^.WriteCallback := WriteCallback;
-      Data^.WriteUserData := WriteUserData;
-    end else
-      Data^.WriteCallback := nil;
-
-    if not Assigned(Handle^.Data.FDData) then
-    begin
-      GetMem(Handle^.Data.FDData, SizeOf(TFDSet) * 2);
-      FD_Zero(PFDSet(Handle^.Data.FDData)[0]);
-      FD_Zero(PFDSet(Handle^.Data.FDData)[1]);
-    end;
-    if IOHandle > Handle^.Data.HighestHandle then
-      Handle^.Data.HighestHandle := IOHandle;
-  end;
-
-  Data^.SavedHandleFlags := fcntl(IOHandle, F_GetFl);
-  fcntl(IOHandle, F_SetFl, Data^.SavedHandleFlags or Open_NonBlock);
-
-  case IOHandle of
-    StdInputHandle:
-      i := Open_RdOnly;
-    StdOutputHandle, StdErrorHandle:
-      i := Open_WrOnly;
-    else
-      i := Data^.SavedHandleFlags and Open_Accmode;
-  end;
-
-  case i of
-    Open_RdOnly:
-      if ARead then
-        FD_Set(IOHandle, PFDSet(Handle^.Data.FDData)[0]);
-    Open_WrOnly:
-      if AWrite then
-        FD_Set(IOHandle, PFDSet(Handle^.Data.FDData)[1]);
-    Open_RdWr:
-      begin
-        if ARead then
-	  FD_Set(IOHandle, PFDSet(Handle^.Data.FDData)[0]);
-	if AWrite then
-	  FD_Set(IOHandle, PFDSet(Handle^.Data.FDData)[1]);
-      end;
-  end;
-
-  Handle^.Data.HasCallbacks := True;
-  Result := asyncOK;
-end;
-
-procedure CheckForCallbacks(Handle: TAsyncHandle);
-var
-  Data: PIOCallbackData;
-begin
-  if (Handle^.Data.HasCallbacks) and
-    (not Assigned(Handle^.Data.FirstIOCallback)) and
-    (not Assigned(Handle^.Data.FirstTimer)) then
-    Handle^.Data.HasCallbacks := False;
-end;
+{$INCLUDE libasync.inc}
 
 
 
-procedure asyncInit(Handle: TAsyncHandle); cdecl;
+procedure InternalInit(Handle: TAsyncHandle);
 begin
   Handle^.Data.HighestHandle := -1;
 end;
 
-procedure asyncFree(Handle: TAsyncHandle); cdecl;
+procedure InternalFree(Handle: TAsyncHandle);
 var
-  Timer, NextTimer: PTimerData;
-  IOCallback, NextIOCallback: PIOCallbackData;
+  IOCallback: PIOCallbackData;
 begin
-  Timer := PTimerData(Handle^.Data.FirstTimer);
-  while Assigned(Timer) do
-  begin
-    NextTimer := Timer^.Next;
-    Dispose(Timer);
-    Timer := NextTimer;
-  end;
-
   IOCallback := PIOCallbackData(Handle^.Data.FirstIOCallback);
   while Assigned(IOCallback) do
   begin
     if (IOCallback^.SavedHandleFlags and Open_NonBlock) = 0 then
       fcntl(IOCallback^.IOHandle, F_SetFl, IOCallback^.SavedHandleFlags);
-    NextIOCallback := IOCallback^.Next;
-    Dispose(IOCallback);
-    IOCallback := NextIOCallback;
+    IOCallback := IOCallback^.Next;
   end;
 
-  Handle^.Data.NextIOCallback := nil;
-
   if Assigned(Handle^.Data.FDData) then
     FreeMem(Handle^.Data.FDData);
 end;
 
-procedure asyncRun(Handle: TAsyncHandle); cdecl;
+procedure InternalRun(Handle: TAsyncHandle; TimeOut: Int64);
 var
-  Timer, NextTimer: PTimerData;
-  TimeOut, AsyncResult: Integer;
-  CurTime, NextTick: Int64;
+  AsyncResult: Integer;
   CurReadFDSet, CurWriteFDSet: TFDSet;
   CurIOCallback: PIOCallbackData;
 begin
-  if Handle^.Data.IsRunning then
-    exit;
-
-  Handle^.Data.DoBreak := False;
-  Handle^.Data.IsRunning := True;
-
-  // Prepare timers
-  if Assigned(Handle^.Data.FirstTimer) then
+  if Handle^.Data.HighestHandle < 0 then
+    // No I/O checks to do, so just wait...
+    AsyncResult := Select(0, nil, nil, nil, TimeOut)
+  else
   begin
-    CurTime := asyncGetTicks;
-    Timer := Handle^.Data.FirstTimer;
-    while Assigned(Timer) do
-    begin
-      Timer^.NextTick := CurTime + Timer^.MSec;
-      Timer := Timer^.Next;
-    end;
-  end;
-
-  while (not Handle^.Data.DoBreak) and Handle^.Data.HasCallbacks do
-  begin
-    Timer := Handle^.Data.FirstTimer;
-    if Assigned(Handle^.Data.FirstTimer) then
-    begin
-      // Determine when the next timer tick will happen
-      CurTime := asyncGetTicks;
-      NextTick := High(Int64);
-      Timer := Handle^.Data.FirstTimer;
-      while Assigned(Timer) do
-      begin
-        if Timer^.NextTick < NextTick then
-	  NextTick := Timer^.NextTick;
-	Timer := Timer^.Next;
-      end;
-      TimeOut := NextTick - CurTime;
-      if TimeOut < 0 then
-        TimeOut := 0;
-    end else
-      TimeOut := -1;
-
-    if Handle^.Data.HighestHandle >= 0 then
-    begin
-      CurReadFDSet := PFDSet(Handle^.Data.FDData)[0];
-      CurWriteFDSet := PFDSet(Handle^.Data.FDData)[1];
-      AsyncResult := Select(Handle^.Data.HighestHandle + 1,
-        @CurReadFDSet, @CurWriteFDSet, nil, TimeOut);
-    end else
-      AsyncResult := Select(0, nil, nil, nil, TimeOut);
-
-    if Assigned(Handle^.Data.FirstTimer) then
-    begin
-      // Check for triggered timers
-      CurTime := asyncGetTicks;
-      Timer := Handle^.Data.FirstTimer;
-      while Assigned(Timer) do
-      begin
-        if Timer^.NextTick <= CurTime then
-	begin
-	  Timer^.Callback(Timer^.UserData);
-	  NextTimer := Timer^.Next;
-	  if Timer^.Periodic then
-	    Inc(Timer^.NextTick, Timer^.MSec)
-	  else
-	    asyncRemoveTimer(Handle, Timer);
-	  if Handle^.Data.DoBreak then
-	    break;
-	  Timer := NextTimer;
-	end else
-	  Timer := Timer^.Next;
-      end;
-    end;
+    CurReadFDSet := PFDSet(Handle^.Data.FDData)[0];
+    CurWriteFDSet := PFDSet(Handle^.Data.FDData)[1];
+    AsyncResult := Select(Handle^.Data.HighestHandle + 1,
+      @CurReadFDSet, @CurWriteFDSet, nil, TimeOut);
 
-    if (AsyncResult > 0) and not Handle^.Data.DoBreak then
+    if AsyncResult > 0 then
     begin
       // Check for I/O events
       Handle^.Data.CurIOCallback := Handle^.Data.FirstIOCallback;
@@ -312,236 +108,93 @@ begin
       begin
         CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
         Handle^.Data.NextIOCallback := CurIOCallback^.Next;
-	if FD_IsSet(CurIOCallback^.IOHandle, CurReadFDSet) and
+        if FD_IsSet(CurIOCallback^.IOHandle, CurReadFDSet) and
 	  FD_IsSet(CurIOCallback^.IOHandle, PFDSet(Handle^.Data.FDData)[0]) and
 	  Assigned(CurIOCallback^.ReadCallback) then
-	begin
+        begin
 	  CurIOCallback^.ReadCallback(CurIOCallback^.ReadUserData);
 	  if Handle^.Data.DoBreak then
 	    break;
-	end;
+        end;
 
-	CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
-	if Assigned(CurIOCallback) and
+        CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
+        if Assigned(CurIOCallback) and
 	  FD_IsSet(CurIOCallback^.IOHandle, CurWriteFDSet) and
 	  FD_IsSet(CurIOCallback^.IOHandle, PFDSet(Handle^.Data.FDData)[1]) and
 	  Assigned(CurIOCallback^.WriteCallback) then
-	begin
+        begin
 	  CurIOCallback^.WriteCallback(CurIOCallback^.WriteUserData);
 	  if Handle^.Data.DoBreak then
 	    break;
-	end;
+        end;
 
-	Handle^.Data.CurIOCallback := Handle^.Data.NextIOCallback;
+        Handle^.Data.CurIOCallback := Handle^.Data.NextIOCallback;
       end;
     end;
   end;
-  Handle^.Data.CurIOCallback := nil;
-  Handle^.Data.NextIOCallback := nil;
-  Handle^.Data.IsRunning := False;
-end;
-
-procedure asyncBreak(Handle: TAsyncHandle); cdecl;
-begin
-  Handle^.Data.DoBreak := True;
-end;
-
-function asyncIsRunning(Handle: TAsyncHandle): Boolean; cdecl;
-begin
-  Result := Handle^.Data.IsRunning;
-end;
-
-function asyncGetTicks: Int64; cdecl;
-var
-  Time: TimeVal;
-begin
-  GetTimeOfDay(Time);
-  Result := Int64(Time.Sec) * 1000 + Int64(Time.USec div 1000);
 end;
 
-function asyncAddTimer(
-  Handle: TAsyncHandle;
-  MSec: LongInt;
-  Periodic: Boolean;
-  Callback: TAsyncCallback;
-  UserData: Pointer
-  ): TAsyncTimer; cdecl;
+procedure InternalInitIOCallback(Handle: TAsyncHandle; Data: PIOCallbackData;
+  InitData: Boolean; CallbackTypes: TCallbackTypes);
 var
-  Data: PTimerData;
-begin
-  if not Assigned(Callback) then
-    exit;
-
-  New(Data);
-  Result := Data;
-  Data^.Next := Handle^.Data.FirstTimer;
-  Handle^.Data.FirstTimer := Data;
-  Data^.MSec := MSec;
-  Data^.Periodic := Periodic;
-  Data^.Callback := Callback;
-  Data^.UserData := UserData;
-  if Handle^.Data.IsRunning then
-    Data^.NextTick := asyncGetTicks + MSec;
-
-  Handle^.Data.HasCallbacks := True;
-end;
-
-procedure asyncRemoveTimer(
-  Handle: TAsyncHandle;
-  Timer: TASyncTimer); cdecl;
-var
-  Data, CurData, PrevData, NextData: PTimerData;
+  i: LongInt;
 begin
-  Data := PTimerData(Timer);
-  CurData := Handle^.Data.FirstTimer;
-  PrevData := nil;
-  while Assigned(CurData) do
+  if InitData then
   begin
-    NextData := CurData^.Next;
-    if CurData = Data then
+    if not Assigned(Handle^.Data.FDData) then
     begin
-      if Assigned(PrevData) then
-        PrevData^.Next := NextData
-      else
-        Handle^.Data.FirstTimer := NextData;
-      break;
+      GetMem(Handle^.Data.FDData, SizeOf(TFDSet) * 2);
+      FD_Zero(PFDSet(Handle^.Data.FDData)[0]);
+      FD_Zero(PFDSet(Handle^.Data.FDData)[1]);
     end;
-    PrevData := CurData;
-    CurData := NextData;
+    if Data^.IOHandle > Handle^.Data.HighestHandle then
+      Handle^.Data.HighestHandle := Data^.IOHandle;
   end;
-  Dispose(Data);
-  CheckForCallbacks(Handle);
-end;
 
-function asyncSetIOCallback(
-  Handle: TAsyncHandle;
-  IOHandle: LongInt;
-  Callback: TAsyncCallback;
-  UserData: Pointer): TAsyncResult; cdecl;
-begin
-  Result := InitIOCallback(Handle, IOHandle, True, Callback, UserData,
-    True, Callback, UserData);
-end;
+  Data^.SavedHandleFlags := fcntl(Data^.IOHandle, F_GetFl);
+  fcntl(Data^.IOHandle, F_SetFl, Data^.SavedHandleFlags or Open_NonBlock);
 
-procedure asyncClearIOCallback(Handle: TAsyncHandle;
-  IOHandle: LongInt); cdecl;
-var
-  CurData, PrevData, NextData: PIOCallbackData;
-begin
-  CurData := Handle^.Data.FirstIOCallback;
-  PrevData := nil;
-  while Assigned(CurData) do
-  begin
-    NextData := CurData^.Next;
-    if CurData^.IOHandle = IOHandle then
-    begin
-      if Handle^.Data.CurIOCallback = CurData then
-        Handle^.Data.CurIOCallback := nil;
-      if Handle^.Data.NextIOCallback = CurData then
-        Handle^.Data.NextIOCallback := NextData;
-      FD_Clr(IOHandle, PFDSet(Handle^.Data.FDData)[0]);
-      FD_Clr(IOHandle, PFDSet(Handle^.Data.FDData)[1]);
-      if Assigned(PrevData) then
-        PrevData^.Next := NextData
-      else
-        Handle^.Data.FirstIOCallback := NextData;
-      Dispose(CurData);
-      break;
-    end;
-    PrevData := CurData;
-    CurData := NextData;
+  case Data^.IOHandle of
+    StdInputHandle:
+      i := Open_RdOnly;
+    StdOutputHandle, StdErrorHandle:
+      i := Open_WrOnly;
+    else
+      i := Data^.SavedHandleFlags and Open_Accmode;
   end;
-  CheckForCallbacks(Handle);
-end;
 
-function asyncSetDataAvailableCallback(
-  Handle: TAsyncHandle;
-  IOHandle: LongInt;
-  Callback: TAsyncCallback;
-  UserData: Pointer): TAsyncResult; cdecl;
-begin
-  Result := InitIOCallback(Handle, IOHandle, True, Callback, UserData, False,
-    nil, nil);
-end;
-
-procedure asyncClearDataAvailableCallback(Handle: TAsyncHandle;
-  IOHandle: LongInt); cdecl;
-var
-  CurData, PrevData, NextData: PIOCallbackData;
-begin
-  CurData := Handle^.Data.FirstIOCallback;
-  PrevData := nil;
-  while Assigned(CurData) do
-  begin
-    NextData := CurData^.Next;
-    if CurData^.IOHandle = IOHandle then
-    begin
-      if Handle^.Data.CurIOCallback = CurData then
-        Handle^.Data.CurIOCallback := nil;
-      if Handle^.Data.NextIOCallback = CurData then
-        Handle^.Data.NextIOCallback := NextData;
-      FD_Clr(IOHandle, PFDSet(Handle^.Data.FDData)[0]);
-      if Assigned(CurData^.WriteCallback) then
-        CurData^.ReadCallback := nil
-      else
+  case i of
+    Open_RdOnly:
+      if cbRead in CallbackTypes then
+        FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[0]);
+    Open_WrOnly:
+      if cbWrite in CallbackTypes then
+        FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[1]);
+    Open_RdWr:
       begin
-        if Assigned(PrevData) then
-          PrevData^.Next := NextData
-        else
-          Handle^.Data.FirstIOCallback := NextData;
-        Dispose(CurData);
+        if cbRead in CallbackTypes then
+	  FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[0]);
+	if cbWrite in CallbackTypes then
+	  FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[1]);
       end;
-      break;
-    end;
-    PrevData := CurData;
-    CurData := NextData;
   end;
-  CheckForCallbacks(Handle);
 end;
 
-function asyncSetCanWriteCallback(
-  Handle: TAsyncHandle;
-  IOHandle: LongInt;
-  Callback: TAsyncCallback;
-  UserData: Pointer): TAsyncResult; cdecl;
+procedure InternalClearIOCallback(Handle: TAsyncHandle; IOHandle: LongInt;
+  CallbackTypes: TCallbackTypes);
 begin
-  Result := InitIOCallback(Handle, IOHandle, False, nil, nil, True,
-    Callback, UserData);
+  if cbRead in CallbackTypes then
+    FD_Clr(IOHandle, PFDSet(Handle^.Data.FDData)[0]);
+  if cbWrite in CallbackTypes then
+    FD_Clr(IOHandle, PFDSet(Handle^.Data.FDData)[1]);
 end;
 
-procedure asyncClearCanWriteCallback(Handle: TAsyncHandle;
-  IOHandle: LongInt); cdecl;
+function asyncGetTicks: Int64; cdecl;
 var
-  CurData, PrevData, NextData: PIOCallbackData;
+  Time: TimeVal;
 begin
-  CurData := Handle^.Data.FirstIOCallback;
-  PrevData := nil;
-  while Assigned(CurData) do
-  begin
-    NextData := CurData^.Next;
-    if CurData^.IOHandle = IOHandle then
-    begin
-      if Handle^.Data.CurIOCallback = CurData then
-        Handle^.Data.CurIOCallback := nil;
-      if Handle^.Data.NextIOCallback = CurData then
-        Handle^.Data.NextIOCallback := NextData;
-      FD_Clr(IOHandle, PFDSet(Handle^.Data.FDData)[1]);
-      if Assigned(CurData^.ReadCallback) then
-        CurData^.WriteCallback := nil
-      else
-      begin
-        if Assigned(PrevData) then
-          PrevData^.Next := NextData
-        else
-          Handle^.Data.FirstIOCallback := NextData;
-        Dispose(CurData);
-      end;
-      break;
-    end;
-    PrevData := CurData;
-    CurData := NextData;
-  end;
-  CheckForCallbacks(Handle);
+  GetTimeOfDay(Time);
+  Result := Int64(Time.Sec) * 1000 + Int64(Time.USec div 1000);
 end;
 
 
@@ -550,13 +203,9 @@ end.
 
 {
   $Log$
-  Revision 1.4  2002-09-15 15:51:09  sg
-  * Removed debugging output code
-
-  Revision 1.3  2002/09/15 15:43:30  sg
-  * Improved error reporting
-
-  Revision 1.1  2002/01/29 17:54:53  peter
-    * splitted to base and extra
+  Revision 1.5  2002-09-25 21:53:39  sg
+  * Split in common implementation an platform dependent implementation
 
+  Revision 1.4  2002/09/15 15:51:09  sg
+  * Removed debugging output code
 }