123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- {
- $Id$
- libasync: Asynchronous event management
- Copyright (C) 2001-2002 by
- Areca Systems GmbH / Sebastian Guenther, [email protected]
- 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
- }
|