* Split in common implementation an platform dependent implementation

This commit is contained in:
sg 2002-09-25 21:53:39 +00:00
parent f346e81a97
commit 32b9486692
3 changed files with 625 additions and 490 deletions

View File

@ -2,10 +2,10 @@
$Id$
libasync: Asynchronous event management
Copyright (C) 2001 by
Copyright (C) 2001-2002 by
Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org
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;
TAsyncCallback = procedure(UserData: Pointer); cdecl;
TAsyncResult = (
asyncOK,
asyncInvalidHandle,
asyncInvalidFileHandle,
asyncHandlerAlreadySet);
TCallbackTypes = set of (cbRead, cbWrite);
// Construction and destruction
{ An implementation unit has to implement the following fordward procedures,
and additionally asyncGetTicks }
procedure asyncInit(
Handle: TAsyncHandle); cdecl;
procedure InternalInit(Handle: TAsyncHandle); forward;
procedure asyncFree(
Handle: TAsyncHandle); cdecl;
procedure InternalFree(Handle: TAsyncHandle); forward;
procedure InternalRun(Handle: TAsyncHandle; TimeOut: Int64); forward;
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;
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;
procedure asyncBreak(
Handle: TAsyncHandle); cdecl;
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;
// Status information
procedure asyncInit(Handle: TAsyncHandle); cdecl;
begin
InternalInit(Handle);
end;
function asyncIsRunning(
Handle: TAsyncHandle
): Boolean; cdecl;
procedure asyncFree(Handle: TAsyncHandle); cdecl;
var
Timer, NextTimer: PTimerData;
IOCallback, NextIOCallback: PIOCallbackData;
begin
InternalFree(Handle);
function asyncGetTicks: Int64; cdecl;
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
NextIOCallback := IOCallback^.Next;
Dispose(IOCallback);
IOCallback := NextIOCallback;
end;
// Timer management
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;
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;
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
}

View File

@ -0,0 +1,116 @@
{
$Id$
libasync: Asynchronous event management
Copyright (C) 2001-2002 by
Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org
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
}

View File

@ -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,88 +59,102 @@ type
SavedHandleFlags: LongInt;
end;
{$INCLUDE libasync.inc}
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;
procedure InternalInit(Handle: TAsyncHandle);
begin
if IOHandle > MaxHandle then
Handle^.Data.HighestHandle := -1;
end;
procedure InternalFree(Handle: TAsyncHandle);
var
IOCallback: PIOCallbackData;
begin
IOCallback := PIOCallbackData(Handle^.Data.FirstIOCallback);
while Assigned(IOCallback) do
begin
Result := asyncInvalidFileHandle;
exit;
if (IOCallback^.SavedHandleFlags and Open_NonBlock) = 0 then
fcntl(IOCallback^.IOHandle, F_SetFl, IOCallback^.SavedHandleFlags);
IOCallback := IOCallback^.Next;
end;
NeedData := True;
Data := Handle^.Data.FirstIOCallback;
while Assigned(Data) do
if Assigned(Handle^.Data.FDData) then
FreeMem(Handle^.Data.FDData);
end;
procedure InternalRun(Handle: TAsyncHandle; TimeOut: Int64);
var
AsyncResult: Integer;
CurReadFDSet, CurWriteFDSet: TFDSet;
CurIOCallback: PIOCallbackData;
begin
if Handle^.Data.HighestHandle < 0 then
// No I/O checks to do, so just wait...
AsyncResult := Select(0, nil, nil, nil, TimeOut)
else
begin
if Data^.IOHandle = IOHandle then
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 then
begin
if ARead then
// Check for I/O events
Handle^.Data.CurIOCallback := Handle^.Data.FirstIOCallback;
while Assigned(Handle^.Data.CurIOCallback) do
begin
if Assigned(Data^.ReadCallback) then
begin
Result := asyncHandlerAlreadySet;
exit;
end;
Data^.ReadCallback := ReadCallback;
Data^.ReadUserData := ReadUserData;
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;
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;
end;
if NeedData then
procedure InternalInitIOCallback(Handle: TAsyncHandle; Data: PIOCallbackData;
InitData: Boolean; CallbackTypes: TCallbackTypes);
var
i: LongInt;
begin
if InitData 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;
if Data^.IOHandle > Handle^.Data.HighestHandle then
Handle^.Data.HighestHandle := Data^.IOHandle;
end;
Data^.SavedHandleFlags := fcntl(IOHandle, F_GetFl);
fcntl(IOHandle, F_SetFl, Data^.SavedHandleFlags or Open_NonBlock);
Data^.SavedHandleFlags := fcntl(Data^.IOHandle, F_GetFl);
fcntl(Data^.IOHandle, F_SetFl, Data^.SavedHandleFlags or Open_NonBlock);
case IOHandle of
case Data^.IOHandle of
StdInputHandle:
i := Open_RdOnly;
StdOutputHandle, StdErrorHandle:
@ -161,194 +165,28 @@ begin
case i of
Open_RdOnly:
if ARead then
FD_Set(IOHandle, PFDSet(Handle^.Data.FDData)[0]);
if cbRead in CallbackTypes then
FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[0]);
Open_WrOnly:
if AWrite then
FD_Set(IOHandle, PFDSet(Handle^.Data.FDData)[1]);
if cbWrite in CallbackTypes then
FD_Set(Data^.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]);
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;
end;
Handle^.Data.HasCallbacks := True;
Result := asyncOK;
end;
procedure CheckForCallbacks(Handle: TAsyncHandle);
var
Data: PIOCallbackData;
procedure InternalClearIOCallback(Handle: TAsyncHandle; IOHandle: LongInt;
CallbackTypes: TCallbackTypes);
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
Handle^.Data.HighestHandle := -1;
end;
procedure asyncFree(Handle: TAsyncHandle); cdecl;
var
Timer, NextTimer: PTimerData;
IOCallback, NextIOCallback: 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;
end;
Handle^.Data.NextIOCallback := nil;
if Assigned(Handle^.Data.FDData) then
FreeMem(Handle^.Data.FDData);
end;
procedure asyncRun(Handle: TAsyncHandle); cdecl;
var
Timer, NextTimer: PTimerData;
TimeOut, AsyncResult: Integer;
CurTime, NextTick: Int64;
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
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;
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;
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;
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;
function asyncGetTicks: Int64; cdecl;
@ -359,204 +197,15 @@ begin
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;
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;
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;
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;
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
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;
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)[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);
end;
end.
{
$Log$
Revision 1.4 2002-09-15 15:51:09 sg
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
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
}