Ignore:
Timestamp:
Jan 23, 2011, 7:25:13 PM (14 years ago)
Author:
george
Message:
  • Fixed: Switching micro thread using SP register only was not working. To switch method context BP register have to be switched too.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • Microthreading/umicrothreading.pas

    r133 r134  
    3030    FStack: Pointer;
    3131    FStackSize: Integer;
    32     FInstructionPointer: Pointer;
    3332    FExecutionStartTime: TDateTime;
    3433    FExecutionEndTime: TDateTime;
     34    FStackPointer: Pointer;
     35    FBasePointer: Pointer;
    3536    FWakeupTime: TDateTime;
    36     procedure Finish;
    37     procedure SaveContext;
    38     procedure RestoreContext;
    39     procedure Init;
    4037  public
    41     FStackPointer: Pointer;
    4238    Id: Integer;
    4339    Name: string;
     
    6561    RoundRobinIndex: Integer;
    6662    LastId: Integer;
    67     FStackPointer: Pointer;
     63    FMainStackPointer: Pointer;
     64    FMainBasePointer: Pointer;
     65    FSelected: TMicroThread;
     66    FTempPointer: Pointer;
    6867    procedure Yield(MicroThread: TMicroThread);
    6968  public
     
    9493  FStackSize := $10000;
    9594  FStack := GetMem(FStackSize);
    96   FStackPointer := FStack + FStackSize;
     95  FBasePointer := FStack + FStackSize;
     96  FStackPointer := FBasePointer - 20;
    9797end;
    9898
     
    101101  FreeMem(FStack);
    102102  inherited Destroy;
    103 end;
    104 
    105 procedure TMicroThread.SaveContext; assembler; nostackframe;
    106 asm
    107   mov eax, Self
    108   mov edx, esp
    109   mov [eax].FStackPointer, edx
    110   pop edx
    111   mov [eax].FInstructionPointer, edx
    112 end;
    113 
    114 procedure TMicroThread.RestoreContext; assembler; nostackframe;
    115 asm
    116   mov eax, Self
    117   mov edx, [eax].FStackPointer
    118   mov esp, edx
    119   mov edx, [eax].FInstructionPointer
    120   push edx
    121   ret
    122 end;
    123 
    124 procedure TMicroThread.Init;
    125 var
    126   FProc: TCallerAddr;
    127 begin
    128   FProc.A := Method;
    129   FInstructionPointer := FProc.B;
    130 end;
    131 
    132 procedure TMicroThread.Finish;
    133 begin
    134   // Microthread is finished, remove it from queue
    135   try
    136     Scheduler.Lock.Acquire;
    137     Scheduler.MicroThreads.Delete(Scheduler.MicroThreads.IndexOf(Self));
    138   finally
    139     Scheduler.Lock.Release;
    140   end;
    141103end;
    142104
     
    154116  Inc(LastId);
    155117  NewMicroThread.Id := LastId;
    156   NewMicroThread.Init;
    157118  MicroThreads.Add(NewMicroThread);
    158119end;
     
    175136procedure TMicroThreadScheduler.Start;
    176137begin
     138  RoundRobinIndex := -1;
    177139  Yield(nil);
    178140end;
     141
     142var
     143  StaticMicroThread: TMicroThread;
     144  StaticScheduler: TMicroThreadScheduler;
    179145
    180146procedure TMicroThreadScheduler.Yield(MicroThread: TMicroThread);
     
    184150  if Assigned(MicroThread) then begin
    185151    MicroThread.FExecutionStartTime := Now;
    186     MicroThread.SaveContext;
    187152    MicroThread.State := tsSleeping;
    188153    asm
     154      // Store microthread stack
     155      mov eax, MicroThread
     156      mov edx, esp
     157      mov [eax].TMicroThread.FStackPointer, edx
     158      mov edx, ebp
     159      mov [eax].TMicroThread.FBasePointer, edx
     160    end;
     161    StaticScheduler := MicroThread.Scheduler;
     162    asm
    189163      // Restore scheduler stack
    190       mov eax, Self
    191       mov edx, [eax].FStackPointer
     164      mov eax, StaticScheduler  // Self is invalid before BP restore
     165      mov edx, [eax].TMicroThreadScheduler.FMainStackPointer
    192166      mov esp, edx
     167      mov edx, [eax].TMicroThreadScheduler.FMainBasePointer
     168      mov ebp, edx
    193169    end;
    194170  end;
    195171
    196172  // Try to find new microthread for execution
     173  FSelected := nil;
    197174  try
    198175    Lock.Acquire;
    199176    I := 0;
    200     while (I < MicroThreads.Count) and (TMicroThread(MicroThreads[I]).State <> tsReady) do
     177    Inc(RoundRobinIndex);
     178    if RoundRobinIndex >= MicroThreads.Count then
     179      RoundRobinIndex := 0;
     180    while (I < MicroThreads.Count) and (TMicroThread(MicroThreads[RoundRobinIndex]).State <> tsReady) and
     181(TMicroThread(MicroThreads[RoundRobinIndex]).State <> tsSleeping) do begin
    201182      Inc(I);
     183      Inc(RoundRobinIndex);
     184      if RoundRobinIndex >= MicroThreads.Count then
     185        RoundRobinIndex := 0;
     186    end;
    202187    if I < MicroThreads.Count then begin
    203       MicroThread := TMicroThread(MicroThreads[I]);
     188      FSelected := TMicroThread(MicroThreads[RoundRobinIndex]);
    204189    end;
    205190  finally
     
    207192  end;
    208193
    209   if Assigned(MicroThread) then begin
     194  if Assigned(FSelected) then begin
    210195    asm
    211196      // Store scheduler stack
    212197      mov eax, Self
    213198      mov edx, esp
    214       mov [eax].FStackPointer, edx
    215     end;
    216     if MicroThread.State = tsReady then begin
    217       MicroThread.State := tsRunning;
    218       MicroThread.FExecutionStartTime := Now;
     199      mov [eax].TMicroThreadScheduler.FMainStackPointer, edx
     200      mov edx, ebp
     201      mov [eax].TMicroThreadScheduler.FMainBasePointer, edx
     202    end;
     203    if FSelected.State = tsReady then begin
     204      FSelected.State := tsRunning;
     205      FSelected.FExecutionStartTime := Now;
     206      FTempPointer := FSelected.FStackPointer;
    219207      asm
    220208        // Restore microthread stack
    221         mov eax, MicroThread
    222         mov edx, [eax].FStackPointer
     209        mov eax, Self
     210        mov edx, [eax].TMicroThreadScheduler.FTempPointer
    223211        mov esp, edx
    224212      end;
    225       MicroThread.Method(MicroThread);
     213      StaticMicroThread := FSelected; // BP will be change and Self pointer will be invalid
     214      FTempPointer := FSelected.FBasePointer;
     215      asm
     216        mov eax, Self
     217        mov edx, [eax].TMicroThreadScheduler.FTempPointer
     218        mov ebp, edx
     219      end;
     220      StaticMicroThread.Method(StaticMicroThread);
     221      //FSelected.Method(FSelected);
     222      StaticScheduler := StaticMicroThread.Scheduler;
    226223      asm
    227224        // Restore scheduler stack
    228         mov eax, Self
    229         mov edx, [eax].FStackPointer
     225        mov eax, StaticScheduler // Self is invalid before BP restore
     226        mov edx, [eax].TMicroThreadScheduler.FMainStackPointer
    230227        mov esp, edx
     228        mov edx, [eax].TMicroThreadScheduler.FMainBasePointer
     229        mov ebp, edx
     230      end;
     231      // Microthread is finished, remove it from queue
     232      try
     233        Lock.Acquire;
     234        MicroThreads.Delete(MicroThreads.IndexOf(FSelected));
     235      finally
     236        Lock.Release;
    231237      end;
    232238    end else
    233     if MicroThread.State = tsSleeping then begin
     239    if FSelected.State = tsSleeping then begin
    234240      // Execute selected thread
    235       MicroThread.State := tsRunning;
    236       MicroThread.FExecutionStartTime := Now;
    237       MicroThread.RestoreContext;
     241      FSelected.State := tsRunning;
     242      FSelected.FExecutionStartTime := Now;
     243      FTempPointer := FSelected.FStackPointer;
     244      asm
     245        // Restore microthread stack
     246        mov eax, Self
     247        mov edx, [eax].TMicroThreadScheduler.FTempPointer
     248        mov esp, edx
     249      end;
     250      FTempPointer := FSelected.FBasePointer;
     251      asm
     252        mov eax, Self
     253        mov edx, [eax].TMicroThreadScheduler.FTempPointer
     254        mov ebp, edx
     255      end;
    238256    end;
    239257  end;
Note: See TracChangeset for help on using the changeset viewer.