mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-05-10 08:22:42 +02:00
212 lines
5.4 KiB
ObjectPascal
212 lines
5.4 KiB
ObjectPascal
{
|
|
$Id$
|
|
|
|
libasync: Asynchronous event management
|
|
Copyright (C) 2001-2002 by
|
|
Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org
|
|
|
|
Unix 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.
|
|
}
|
|
|
|
unit libasync;
|
|
|
|
{$MODE objfpc}
|
|
|
|
interface
|
|
|
|
type
|
|
|
|
TAsyncData = record
|
|
IsRunning, DoBreak: Boolean;
|
|
HasCallbacks: Boolean; // True as long as callbacks are set
|
|
FirstTimer: Pointer;
|
|
FirstIOCallback: Pointer;
|
|
CurIOCallback: Pointer; // current callback being processed within 'run'
|
|
NextIOCallback: Pointer; // next callback to get processed within 'run'
|
|
FDData: Pointer;
|
|
HighestHandle: LongInt;
|
|
end;
|
|
|
|
{$INCLUDE libasynch.inc}
|
|
|
|
|
|
|
|
implementation
|
|
|
|
{$ifdef VER1_0}
|
|
uses Linux;
|
|
{$else}
|
|
uses Unix;
|
|
{$endif}
|
|
|
|
const
|
|
MaxHandle = SizeOf(TFDSet) * 8 - 1;
|
|
|
|
type
|
|
PIOCallbackData = ^TIOCallbackData;
|
|
TIOCallbackData = record
|
|
Next: PIOCallbackData;
|
|
IOHandle: LongInt;
|
|
ReadCallback, WriteCallback: TAsyncCallback;
|
|
ReadUserData, WriteUserData: Pointer;
|
|
SavedHandleFlags: LongInt;
|
|
end;
|
|
|
|
{$INCLUDE libasync.inc}
|
|
|
|
|
|
|
|
procedure InternalInit(Handle: TAsyncHandle);
|
|
begin
|
|
Handle^.Data.HighestHandle := -1;
|
|
end;
|
|
|
|
procedure InternalFree(Handle: TAsyncHandle);
|
|
var
|
|
IOCallback: PIOCallbackData;
|
|
begin
|
|
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);
|
|
IOCallback := IOCallback^.Next;
|
|
end;
|
|
|
|
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
|
|
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
|
|
// 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;
|
|
end;
|
|
|
|
procedure InternalInitIOCallback(Handle: TAsyncHandle; Data: PIOCallbackData;
|
|
InitData: Boolean; CallbackTypes: TCallbackTypes);
|
|
var
|
|
i: LongInt;
|
|
begin
|
|
if InitData then
|
|
begin
|
|
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 Data^.IOHandle > Handle^.Data.HighestHandle then
|
|
Handle^.Data.HighestHandle := Data^.IOHandle;
|
|
end;
|
|
|
|
Data^.SavedHandleFlags := fcntl(Data^.IOHandle, F_GetFl);
|
|
fcntl(Data^.IOHandle, F_SetFl, Data^.SavedHandleFlags or Open_NonBlock);
|
|
|
|
case Data^.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 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 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;
|
|
end;
|
|
|
|
procedure InternalClearIOCallback(Handle: TAsyncHandle; IOHandle: LongInt;
|
|
CallbackTypes: TCallbackTypes);
|
|
begin
|
|
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;
|
|
var
|
|
Time: TimeVal;
|
|
begin
|
|
GetTimeOfDay(Time);
|
|
Result := Int64(Time.Sec) * 1000 + Int64(Time.USec div 1000);
|
|
end;
|
|
|
|
|
|
end.
|
|
|
|
|
|
{
|
|
$Log$
|
|
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
|
|
}
|