📄 idfiberweaverinline.pas
字号:
{ $HDR$}
{**********************************************************************}
{ Unit archived using Team Coherence }
{ Team Coherence is Copyright 2002 by Quality Software Components }
{ }
{ For further information / comments, visit our WEB site at }
{ http://www.TeamCoherence.com }
{**********************************************************************}
{}
{ $Log: 56070: IdFiberWeaverInline.pas
{
Rev 1.2 6/11/2004 8:39:52 AM DSiders
Added "Do not Localize" comments.
}
{
{ Rev 1.1 2004.02.09 9:16:38 PM czhower
{ Updated to compile and match lib changes.
}
{
{ Rev 1.0 2004.02.03 12:38:52 AM czhower
{ Move
}
{
{ Rev 1.2 2003.11.04 3:51:20 PM czhower
{ Update to sync TC
}
{
{ Rev 1.1 2003.10.21 12:19:22 AM czhower
{ TIdTask support and fiber bug fixes.
}
{
{ Rev 1.0 2003.10.19 2:50:54 PM czhower
{ Fiber cleanup
}
{
{ Rev 1.4 2003.10.19 1:04:26 PM czhower
{ Updates
}
{
{ Rev 1.3 2003.10.11 5:43:20 PM czhower
{ Chained servers now functional.
}
{
{ Rev 1.2 2003.09.19 10:09:40 PM czhower
{ Next stage of fiber support in servers.
}
{
{ Rev 1.1 2003.08.20 1:46:22 PM czhower
{ Update to compile.
}
{
{ Rev 1.0 8/16/2003 11:09:12 AM JPMugaas
{ Moved from Indy Core dir as part of package reorg
}
{
Rev 1.8 7/26/2003 12:20:02 PM BGooijen
Small fix to prevent some exceptions
}
{
{ Rev 1.7 2003.06.30 7:33:50 PM czhower
{ Fix to exception handling.
}
{
{ Rev 1.6 2003.06.25 1:25:58 AM czhower
{ Small changes.
}
{
{ Rev 1.4 2003.06.03 11:05:02 PM czhower
{ Modified ProcessInThisFiber to support error flag return.
}
{
{ Rev 1.3 2003.04.17 7:44:58 PM czhower
}
{
Rev 1.2 4/11/2003 6:37:38 PM BGooijen
ProcessInThisFiber and WaitForFibers are now overridden here
}
{
{ Rev 1.1 2003.04.10 10:51:06 PM czhower
}
{
Rev 1.14 3/27/2003 12:34:02 PM BGooijen
very little clean-up
}
{
{ Rev 1.13 2003.03.27 1:31:18 AM czhower
{ Removal of hack cast.
}
{
{ Rev 1.12 2003.03.27 1:29:16 AM czhower
{ Exception frame swapping.
}
{
{ Rev 1.11 2003.03.27 12:45:58 AM czhower
{ Fixed AV relating to preparation changes for exception frame swapping
}
{
{ Rev 1.10 2003.03.27 12:18:06 AM czhower
}
{
Rev 1.9 3/26/2003 8:37:50 PM BGooijen
Added WaitForFibers
}
{
{ Rev 1.8 2003.03.26 12:48:30 AM czhower
}
{
{ Rev 1.7 3/25/2003 01:58:20 PM JPMugaas
{ Fixed a type-error.
}
{
{ Rev 1.6 3/25/2003 01:27:56 AM JPMugaas
{ Made a custom exception class that descends from EIdSIlentException so that
{ the component does not always raise an exception in the server if there's no
{ client connection.
}
{
{ Rev 1.5 2003.03.16 12:49:32 PM czhower
}
{
Rev 1.4 3/13/2003 10:18:14 AM BGooijen
Server side fibers, bug fixes
}
{
{ Rev 1.3 12-15-2002 17:08:00 BGooijen
{ Removed AssignList, and added a hack-cast to use .Assign
}
{
{ Rev 1.2 2002.12.07 11:10:30 PM czhower
{ Removed unneeded code.
}
{
{ Rev 1.1 12-6-2002 20:34:10 BGooijen
{ Now compiles on Delphi 5
}
{
{ Rev 1.0 11/13/2002 08:44:26 AM JPMugaas
}
unit IdFiberWeaverInline;
interface
uses
Classes, IdException,
IdGlobal, IdFiber, IdFiberWeaver, IdThreadSafe,
SyncObjs;
type
TIdFiberWeaverInline = class;
TIdFiberNotifyEvent = procedure(AFiberWeaver: TIdFiberWeaverInline;
AFiber: TIdFiberBase) of object;
TIdFiberWeaverInline = class(TIdFiberWeaver)
protected
// TIdThreadSafeInteger cannot be used for FActiveFiberList because the
// semantics cause the first fiber to be counted more than once during
// finish, and possibly other fibers as well. The only other solution
// involves using TIdFiber itself, and that would cause changes to TIdFiber
// that would be made only for the accomodation of TIdFiberWeaverInline.
//
// As it is TIdFiber itself has no knowledge ot TIdFiberWeaverInline.
//
// FActiveFiberList is used by ProcessInThisThread to detect when all fibers
// have finished.
FActiveFiberList: TIdThreadSafeList;
FAddEvent: TEvent;
// FActiveFiberList contains a list of fibers to schedule. Fibers are
// removed when they are running or are suspened. When a fiber is ready to
// excecuted again it is added to FActiveFiberList and the fiber weaver will
// schedule it.
FFiberList: TIdThreadSafeList;
FFreeFibersOnCompletion: Boolean;
FOnIdle: TNotifyEvent;
FOnSwitch: TIdFiberNotifyEvent;
FSelfFiber: TIdConvertedFiber;
//
procedure DoIdle;
procedure DoSwitch(AFiber: TIdFiberBase); virtual;
procedure InitComponent; override;
procedure Relinquish(
AFiber: TIdFiber;
AReschedule: Boolean
); override;
procedure ScheduleFiber(
ACurrentFiber: TIdFiberBase;
ANextFiber: TIdFiber
);
public
procedure Add(AFiber: TIdFiber); override;
destructor Destroy; override;
function HasFibers: Boolean;
function ProcessInThisThread: Boolean;
function WaitForFibers(
ATimeout: Cardinal = Infinite
): Boolean;
override;
published
property FreeFibersOnCompletion: Boolean read FFreeFibersOnCompletion
write FFreeFibersOnCompletion;
//
property OnIdle: TNotifyEvent read FOnIdle write FOnIdle;
property OnSwitch: TIdFiberNotifyEvent read FOnSwitch write FOnSwitch;
end;
EIdNoFibersToSchedule = class(EIdSilentException);
implementation
uses
SysUtils,
Windows;
{ TIdFiberWeaverInline }
procedure TIdFiberWeaverInline.Add(AFiber: TIdFiber);
begin
inherited;
AFiber.SetRelinquishHandler(Relinquish);
with FFiberList.LockList do try
Add(AFiber);
FAddEvent.SetEvent;
finally FFiberList.UnlockList; end;
end;
destructor TIdFiberWeaverInline.Destroy;
begin
FreeAndNil(FActiveFiberList);
FreeAndNil(FFiberList);
FreeAndNil(FAddEvent);
inherited;
end;
procedure TIdFiberWeaverInline.DoIdle;
begin
if Assigned(FOnIdle) then begin
FOnIdle(Self);
end;
end;
procedure TIdFiberWeaverInline.DoSwitch(AFiber: TIdFiberBase);
begin
if Assigned(FOnSwitch) then begin
FOnSwitch(Self, AFiber);
end;
end;
function TIdFiberWeaverInline.HasFibers: Boolean;
begin
Result := not FFiberList.IsCountLessThan(1);
end;
procedure TIdFiberWeaverInline.InitComponent;
begin
inherited;
FActiveFiberList := TIdThreadSafeList.Create;
FAddEvent := TEvent.Create(nil, False, False, '');
FFiberList := TIdThreadSafeList.Create;
end;
function TIdFiberWeaverInline.ProcessInThisThread: Boolean;
// Returns true if ANY fiber terminated because of an unhandled exception.
// If false, user does not need to loop through the fibers to look.
var
LFiber: TIdFiber;
LFiberList: TList;
begin
Result := False;
LFiberList := FFiberList.LockList; try
if LFiberList.Count = 0 then begin
raise EIdNoFibersToSchedule.Create('No fibers to schedule.'); {do not localize}
end;
FActiveFiberList.Assign(LFiberList);
finally FFiberList.UnlockList; end;
// This loop catches fibers as they finish. Relinquish accomplishes explicit
// switching faster by performing only one switch instead of two.
FSelfFiber := TIdConvertedFiber.Create; try
while True do begin
LFiber := TIdFiber(FFiberList.Pull);
if LFiber = nil then begin
if FActiveFiberList.IsEmpty then begin
// All fibers finished
Break;
end else begin
FAddEvent.WaitFor(Infinite);
end;
end else begin
// So it will switch back here when finished so other fibers can be
// processed.
LFiber.ParentFiber := FSelfFiber;
//
ScheduleFiber(FSelfFiber, LFiber);
// if any fiber terminated with a fatal exception return true
// Dont set it to it, else false would reset it.
if FSelfFiber.PriorFiber is TIdFiber then begin
LFiber := TIdFiber(FSelfFiber.PriorFiber);
if LFiber.FatalExceptionOccurred then begin
Result := True;
end;
// Finished fibers always switch back to parent and will not short
// circuit schedule
if LFiber.Finished then begin
FActiveFiberList.Remove(LFiber);
if FreeFibersOnCompletion then begin
FreeAndNil(LFiber);
end;
end;
end;
end;
end;
finally FreeAndNil(FSelfFiber); end;
end;
procedure TIdFiberWeaverInline.Relinquish(
AFiber: TIdFiber;
AReschedule: Boolean
);
var
LFiber: TIdFiber;
begin
while True do begin
LFiber := nil;
// Get next fiber to schedule
with FFiberList.LockList do try
if Count > 0 then begin
LFiber := TIdFiber(List[0]);
Delete(0);
if AReschedule then begin
Add(AFiber);
end;
// If no fibers to schedule, we will rerun ourself if set to reschedule
end else if AReschedule then begin
// Soft cast as a check that a converted fiber has not been passed
// with AReschedule = True
LFiber := AFiber as TIdFiber;
end;
finally FFiberList.UnlockList; end;
if LFiber = nil then begin
// If there are no fibers to schedule, that means we are waiting on
// ourself, or another relinquished fiber. Wait for one to get readded
// to list.
//
//TODO: Allow a parameter for timeout and call DoIdle
//TODO: Better yet - integrate with AntiFreeze also
DoIdle;
FAddEvent.WaitFor(Infinite);
end else if LFiber = AFiber then begin
// If the next fiber is ourself, simply exit to return to ourself
Break;
end else if LFiber <> nil then begin
// Must set the parent fiber to self so that when it finishes we get
// control again. The main ProcessInThisThread loop does this, but
// only for ones it first starts. Fibers can get added to the list and
// then scheduled here in this short circuit switch. When they finish
// they will have no parent fiber.
LFiber.ParentFiber := FSelfFiber;
ScheduleFiber(AFiber, LFiber);
// If we get switched back to, we have been scheduled so exit
Break;
end;
end;
// For future expansion when can switch between weavers
AFiber.SetRelinquishHandler(Relinquish);
end;
procedure TIdFiberWeaverInline.ScheduleFiber(
ACurrentFiber: TIdFiberBase;
ANextFiber: TIdFiber
);
begin
DoSwitch(ANextFiber);
ACurrentFiber.SwitchTo(ANextFiber);
end;
function TIdFiberWeaverInline.WaitForFibers(
ATimeout: Cardinal = Infinite
): Boolean;
begin
if not FFiberList.IsEmpty then begin
Result := True;
end else begin
Result := (FAddEvent.WaitFor(ATimeout) = wrSignaled) and not FFiberList.IsEmpty;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -