Ignore:
Timestamp:
Jan 28, 2011, 2:12:42 PM (14 years ago)
Author:
george
Message:
  • Modified: Restructuralized code for support for pending state changes.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • MicroThreading/UMicroThreading.pas

    r155 r156  
    2828  TMicroThreadManager = class;
    2929
    30   TMicroThreadState = (tsWaiting, tsRunning, tsBlocked, tsSuspended);
     30  TMicroThreadState = (tsNone, tsWaiting, tsRunning, tsBlocked, tsSuspended);
    3131  TMicroThreadBlockState = (tbsNone, tbsSleeping, tbsWaitFor, tbsTerminating,
    3232    tbsTerminated);
     
    5858    FExecutionEndTime: TDateTime;
    5959    FExecutionTime: TDateTime;
     60    FExecutionCount: Integer;
    6061    FStack: Pointer;
    6162    FStackPointer: Pointer;
     
    7374    function GetStackUsed: Integer;
    7475    function GetTerminated: Boolean;
     76    procedure SetManager(const AValue: TMicroThreadManager);
    7577    procedure SetScheduler(const AValue: TMicroThreadScheduler);
     78    procedure CheckStack;
    7679  public
    7780    Name: string;
     
    97100    property BlockState: TMicroThreadBlockState read FBlockState;
    98101    property ExecutionTime: TDateTime read FExecutionTime;
     102    property ExecutionCount: Integer read FExecutionCount;
    99103    property FreeOnTerminate: Boolean read FFreeOnTerminate
    100104      write FFreeOnTerminate;
     
    102106    property Scheduler: TMicroThreadScheduler read FScheduler
    103107      write SetScheduler;
    104     property Manager: TMicroThreadManager read FManager;
     108    property Manager: TMicroThreadManager read FManager write SetManager;
    105109    property StackUsed: Integer read GetStackUsed;
    106110  end;
     
    140144    FScheduler: TMicroThreadScheduler;
    141145    FThread: TMicroThreadThread;
     146    FId: Integer;
     147    procedure SetCurrentMicroThread(const AValue: TMicroThread);
    142148    function Execute(Count: Integer): Integer;
     149    property CurrentMicroThread: TMicroThread read FCurrentMicroThread
     150      write SetCurrentMicroThread;
    143151  public
    144     Id: Integer;
    145152    procedure Yield;
    146153    procedure Synchronize(AMethod: TThreadMethod);
     
    148155    destructor Destroy; override;
    149156    property Scheduler: TMicroThreadScheduler read FScheduler;
    150     property CurrentMicroThread: TMicroThread read FCurrentMicroThread;
    151157  end;
    152158
     
    176182    procedure SetActive(const AValue: Boolean);
    177183    procedure SetThreadPoolSize(const AValue: Integer);
    178     function GetNextMicroThread: TMicroThread;
     184    procedure GetNextMicroThread(Manager: TMicroThreadManager);
    179185    procedure ReleaseMicroThread(MicroThread: TMicroThread);
    180186    procedure SetUseMainThread(const AValue: Boolean);
     
    206212
    207213const
    208   MicroThreadStateText: array[TMicroThreadState] of string = ('Waiting',
     214  MicroThreadStateText: array[TMicroThreadState] of string = ('None', 'Waiting',
    209215    'Running', 'Blocked', 'Suspended');
    210216  MicroThreadBlockStateText: array[TMicroThreadBlockState] of string = ('None',
     
    214220procedure MTSleep(Duration: TDateTime);
    215221function MTWaitForEvent(Event: TMicroThreadEvent; Duration: TDateTime): TWaitResult;
     222procedure Log(Text: string);
     223
     224const
     225  LogFileName: string = 'Log.txt';
    216226
    217227implementation
     
    284294end;
    285295
     296var
     297  LogLock: TCriticalSection;
     298
     299procedure Log(Text: string);
     300var
     301  LogFile: TextFile;
     302begin
     303  try
     304    LogLock.Acquire;
     305    AssignFile(LogFile, LogFileName);
     306    if FileExists(LogFileName) then Append(LogFile)
     307      else Rewrite(LogFile);
     308    WriteLn(LogFile, Text);
     309    CloseFile(LogFile);
     310  finally
     311    LogLock.Release;
     312  end;
     313end;
     314
    286315{ TMicroThreadMethod }
    287316
     
    323352
    324353{ TMicroThreadManager }
     354
     355procedure TMicroThreadManager.SetCurrentMicroThread(const AValue: TMicroThread
     356  );
     357begin
     358  if FCurrentMicroThread = AValue then Exit;
     359  if Assigned(FCurrentMicroThread) then
     360    FCurrentMicroThread.FManager := nil;
     361  FCurrentMicroThread := AValue;
     362  if Assigned(FCurrentMicroThread) then
     363    FCurrentMicroThread.FManager := Self;
     364end;
    325365
    326366function TMicroThreadManager.Execute(Count: Integer): Integer;
     
    345385      mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread
    346386      mov edx, esp
     387      mov ebx, ebp
    347388      mov [eax].TMicroThread.FStackPointer, edx
    348       mov edx, ebp
    349       mov [eax].TMicroThread.FBasePointer, edx
    350 
    351       // Restore FScheduler stack
     389      mov [eax].TMicroThread.FBasePointer, ebx
     390
     391      // Restore manager stack
    352392      mov edx, [ecx].TMicroThreadManager.FStackPointer
     393      mov ebx, [ecx].TMicroThreadManager.FBasePointer
    353394      mov esp, edx
    354       mov edx, [ecx].TMicroThreadManager.FBasePointer
    355       mov ebp, edx
     395      mov ebp, ebx
    356396    end;
    357     FCurrentMicroThread.FManager := nil;
     397    FCurrentMicroThread.CheckStack;
     398    if FCurrentMicroThread = nil then
     399      raise Exception.Create('x');
    358400    FScheduler.ReleaseMicroThread(FCurrentMicroThread);
    359     FCurrentMicroThread := nil;
    360401  end;
    361402
    362403  if FExecutedCount < FExecuteCount then begin
    363     FCurrentMicroThread := FScheduler.GetNextMicroThread;
    364 
     404    FScheduler.GetNextMicroThread(Self);
    365405    if Assigned(FCurrentMicroThread) then begin
    366406      Inc(FExecutedCount);
    367407      FCurrentMicroThread.FExecutionStartTime := NowPrecise;
    368       FCurrentMicroThread.FManager := Self;
    369408      asm
    370         // Store FScheduler stack
     409        // Store manager stack
    371410        mov eax, Self
    372411        mov edx, esp
     412        mov ebx, ebp
    373413        mov [eax].TMicroThreadManager.FStackPointer, edx
    374         mov edx, ebp
    375         mov [eax].TMicroThreadManager.FBasePointer, edx
     414        mov [eax].TMicroThreadManager.FBasePointer, ebx
    376415      end;
    377416      if not FCurrentMicroThread.FExecuted then begin
     417        // First time micro thread execution
    378418        FCurrentMicroThread.FExecuted := True;
    379419        asm
     
    382422          mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread
    383423          mov edx, [eax].TMicroThread.FStackPointer
     424          mov ebx, [eax].TMicroThread.FBasePointer
    384425          mov esp, edx
    385           mov edx, [eax].TMicroThread.FBasePointer
    386           mov ebp, edx
     426          mov ebp, ebx
    387427          // We want to call virtual method Execute
    388428          // but virtual methods can be called only statically
     
    390430          call TMicroThread.CallExecute
    391431
    392           // Restore FScheduler stack
     432          // Restore manager stack
    393433          // ecx register is set by CallExecute to running micro thread
    394434          mov eax, [ecx].TMicroThread.FManager
    395435          mov edx, [eax].TMicroThreadManager.FStackPointer
     436          mov ebx, [eax].TMicroThreadManager.FBasePointer
    396437          mov esp, edx
    397           mov edx, [eax].TMicroThreadManager.FBasePointer
    398           mov ebp, edx
     438          mov ebp, ebx
    399439        end;
    400 
     440        FCurrentMicroThread.CheckStack;
    401441        FCurrentMicroThread.FExecutionEndTime := NowPrecise;
    402442        FCurrentMicroThread.FExecutionTime := FCurrentMicroThread.FExecutionTime +
    403443         (FCurrentMicroThread.FExecutionEndTime - FCurrentMicroThread.FExecutionStartTime);
    404         FCurrentMicroThread.FState := tsBlocked;
     444        FCurrentMicroThread.FStatePending := tsBlocked;
    405445        FCurrentMicroThread.FBlockState := tbsTerminated;
    406446        if FCurrentMicroThread.FFreeOnTerminate then begin
     
    414454          end;
    415455        end else begin
    416           FCurrentMicroThread.FManager := nil;
    417456          FScheduler.ReleaseMicroThread(FCurrentMicroThread);
    418457        end;
    419458        //FCurrentMicroThread.FManager := nil;
    420459        //FScheduler.ReleaseMicroThread(FCurrentMicroThread);
    421         FCurrentMicroThread := nil;
     460        //FCurrentMicroThread := nil;
    422461      end else
    423       //if FCurrentMicroThread.State = tsWaiting then
    424462      begin
    425         // Execute selected thread
     463        // Regular selected microthread execution
     464        FCurrentMicroThread.CheckStack;
    426465        asm
    427466          // Restore microthread stack
     
    429468          mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread
    430469          mov edx, [eax].TMicroThread.FStackPointer
     470          mov ebx, [eax].TMicroThread.FBasePointer
    431471          mov esp, edx
    432           mov edx, [eax].TMicroThread.FBasePointer
    433           mov ebp, edx
     472          mov ebp, ebx
    434473        end;
    435474      end;
     
    464503  try
    465504    repeat
    466       ExecutedCount := Manager.Execute(10);
     505      ExecutedCount := Manager.Execute(100000);
    467506      if ExecutedCount = 0 then Sleep(1);
    468507    until Terminated;
    469508  except
    470     on E: Exception do
     509    on E: Exception do ;
    471510      //ExceptionHandler(E);
    472511  end;
     
    485524  Terminate;
    486525  repeat
    487     Application.ProcessMessages;
    488526    Sleep(1);
    489527  until ExecuteTerminated;
     
    522560end;
    523561
     562procedure TMicroThread.SetManager(const AValue: TMicroThreadManager);
     563begin
     564  if FManager = AValue then Exit;
     565  if Assigned(FManager) then FManager.CurrentMicroThread := nil;
     566  FManager := AValue;
     567  if Assigned(FManager) then FManager.CurrentMicroThread := Self;
     568end;
     569
    524570procedure TMicroThread.SetScheduler(const AValue: TMicroThreadScheduler);
    525571begin
     
    527573end;
    528574
     575procedure TMicroThread.CheckStack;
     576begin
     577  if not ((FStackPointer > FStack) and (FStackPointer < (FStack + FStackSize)))
     578    then raise EStackOverflow.Create(Format('Microthread %d stack error', [FId]));
     579end;
     580
    529581procedure TMicroThread.Execute;
    530582begin
     
    534586procedure TMicroThread.Yield;
    535587begin
     588  if not Assigned(FManager) then
     589    raise Exception.Create('Manager reference lost');
     590  FStatePending := tsWaiting;
    536591  FManager.Yield;
    537592end;
     
    582637  FExecutionTime := 0;
    583638  FState := tsWaiting;
    584   FStatePending := tsWaiting;
     639  FStatePending := tsNone;
    585640  if CreateSuspended then begin
    586641    FState := tsSuspended;
    587     FStatePending := tsSuspended;
    588642  end;
    589643  FFreeOnTerminate := True;
     
    717771    Application.ProcessMessages;
    718772    Sleep(1);
    719   until FMainThreadTerminated and (ThreadPoolSize = 0);
     773  until FMainThreadTerminated and (ThreadPoolCount = 0);
    720774  FState := ssStopped;
    721775end;
     
    730784    FThreadPool.OwnsObjects := False;
    731785    ThreadIndex := FThreadPool.IndexOf(Sender);
    732     if ThreadIndex <> -1 then FThreadPool.Delete(ThreadIndex);
     786    if ThreadIndex = -1 then
     787      raise Exception.Create('Trying to free thread not found in thread pool');
     788    FThreadPool.Delete(ThreadIndex);
     789  finally
    733790    FThreadPool.OwnsObjects := True;
    734   finally
    735791    FThreadPoolLock.Release;
    736792  end;
     
    748804        NewThread := TMicroThreadThread.Create(True);
    749805        NewThread.Manager.FScheduler := Self;
    750         NewThread.Manager.Id := FThreadPool.Count + 1;
     806        NewThread.Manager.FId := FThreadPool.Count + 1;
    751807        NewThread.Manager.FThread := NewThread;
    752808        NewThread.OnTerminate := PoolThreadTerminated;
     809        NewThread.FreeOnTerminate := True;
    753810        ThreadPool.Add(NewThread);
    754811        NewThread.Resume;
     
    778835end;
    779836
    780 function TMicroThreadScheduler.GetNextMicroThread: TMicroThread;
     837procedure TMicroThreadScheduler.GetNextMicroThread(Manager: TMicroThreadManager);
    781838var
    782839  I: Integer;
    783840  CurrentTime: TDateTime;
    784 begin
    785   CurrentTime := NowPrecise;
    786   Result := nil;
     841  Selected: TMicroThread;
     842begin
    787843  try
    788844    FMicroThreadsLock.Acquire;
     845    CurrentTime := NowPrecise;
    789846    I := 0;
     847    Selected := nil;
    790848    Inc(FRoundRobinIndex);
    791849    if FRoundRobinIndex >= FMicroThreads.Count then
     
    793851    while (I < FMicroThreads.Count) do
    794852    with TMicroThread(FMicroThreads[FRoundRobinIndex]) do begin
    795       FState := FStatePending;
    796853      if (FState = tsWaiting) then Break
    797854      else
     
    815872      // Go to next thread
    816873      Inc(I);
    817       Inc(FRoundRobinIndex);
    818       if FRoundRobinIndex >= FMicroThreads.Count then
    819         FRoundRobinIndex := 0;
     874      FRoundRobinIndex := (FRoundRobinIndex + 1) mod FMicroThreads.Count;
    820875    end;
    821876    if I < FMicroThreads.Count then begin
    822       Result := TMicroThread(FMicroThreads[FRoundRobinIndex]);
    823       Result.FState := tsRunning;
    824       Result.FStatePending := tsWaiting;
     877      if Assigned(Manager.FCurrentMicroThread) then
     878        raise Exception.Create('Manager have already have running microthread');
     879      Selected := TMicroThread(FMicroThreads[FRoundRobinIndex]);
     880      Selected.FState := tsRunning;
     881      Inc(Selected.FExecutionCount);
    825882    end;
     883    Manager.CurrentMicroThread := Selected;
    826884  finally
    827885    FMicroThreadsLock.Release;
     
    831889procedure TMicroThreadScheduler.ReleaseMicroThread(MicroThread: TMicroThread);
    832890begin
     891  if not Assigned(MicroThread) then
     892    raise Exception.Create('Can''t realease nil thread.');
    833893  try
    834894    FMicroThreadsLock.Acquire;
    835     MicroThread.FState := MicroThread.FStatePending;
     895    if MicroThread.FStatePending <> tsNone then begin
     896      MicroThread.FState := MicroThread.FStatePending;
     897      MicroThread.FStatePending := tsNone;
     898    end;
     899    MicroThread.Manager := nil;
    836900  finally
    837901    FMicroThreadsLock.Release;
     
    893957initialization
    894958
     959DeleteFile(LogFileName);
     960LogLock := TCriticalSection.Create;
    895961MainScheduler := TMicroThreadScheduler.Create;
    896962
     
    898964
    899965MainScheduler.Free;
     966LogLock.Free;
    900967
    901968end.
Note: See TracChangeset for help on using the changeset viewer.