热自助双活机制

热自助死机问题代码分析

流程图

 

热自助被激活时执行以下代码:

 

/* TSR 激活函数 */

void tsr_active(void)

{

    if (dosbusy() && !int28_active)

    {

       hot_while_dosbusy = 1;

    }

    else

    {

       /* 设置自己的栈 */

       enable();

       set_stack();[xuzj1] 

 

       /* 清键盘缓冲区 */

//     while (bioskey(_KEYBRD_READY))

//         bioskey(_KEYBRD_READ);

 

       if (*(long far *)MK_FP(0, 0xd0 * 4))

       {

           _ES = FP_SEG(active);

           _BX = FP_OFF(active);

           asm{

              mov ax, 0x0920

              int 0xd0

              }[xuzj2] 

       }

       else

           active();

 

       /* 恢复栈 */

       restore_stack();[xuzj3] 

    }

}

 

multask.exe程序中对应调用:

serv

procedure serv(_Flags, _CS, _IP, _AX, _BX, _CX, _DX, _SI, _DI, _DS, _ES, _BP: Word); interrupt;

begin

    case _ax of

        $0920:

            begin

                asm

                    mov tempstack.s,ss

                    mov tempstack.o,sp

                end;[xuzj4] 

                InsertTask(ptr(_ES, _BX), tempstack.p);[xuzj5] 

            end;

… …

InsertTask

procedure InsertTask(p, stack: pointer {;dta:pointer;psp:word});

var j: integer;

begin

    asm                     {Enter Critical Area}

        MOV   AL ,1

        XCHG  MyHandleActive , AL

        MOV   isActive, AL

    end;

    if (not isActive) and (NumTaskCurrent < MaxTask) then

    begin

        inc(NumTaskCurrent);

        Tasks[NumTaskCurrent].Start.p := p;[xuzj6] 

        Tasks[NumTaskCurrent].needkey := true;

        Tasks[NumTaskCurrent].havekey := false;

        if Tasks[NumTaskCurrent - 1].havekey then

        begin

            Tasks[NumTaskCurrent].havekey := true;

            Tasks[NumTaskCurrent - 1].havekey := false;

        end;

        if Tasks[0].havekey then

        begin

            Tasks[NumTaskCurrent].havekey := true;

            Tasks[0].havekey := false;

        end;

        Tasks[NumTaskCurrent].noDosCalls := false;

        Tasks[NumTaskCurrent].TickInc := 1;

        Tasks[NumTaskCurrent].CurrentTicks := Tasks[NumTaskCurrent].TickInc;

        for j := 0 to VideoParamNum - 1 do

            Tasks[NumTaskCurrent].video[j] := ParamData[j * 5 + 4];

        if stack <> nil then

            Tasks[NumTaskCurrent].OStack.p := stack;[xuzj7] 

    end;

    if not isActive then

        asm

        mov MyHandleActive,0;

        end; {Leave Critical Area}

end;

 

然后是通过时钟中断来激活运行热自助程序:

MyTimer

procedure MyTimer[xuzj8] ; interrupt;

begin

    inline($9C)[xuzj9] ;

    OldTimer;

    if (not DosBusy^) and (not Critical^) and (In13 = 0) and (not InTimer) and(InMyDOS = 0)

        and ((CurrentTask < NumTaskLast) or (CurrentTask = 0)) then

     {and (CurrentTask<>1) then}

    begin

        InTimer := true;

        inline($9C);

       asm call far [dotimer] end;[xuzj10] 

        InTimer := false;

    end

    else

    begin

        if (NumTaskLast > 0) and (CurrentTask = 0) and (not Transed) and (not noDosswitch) then

            inc(TransCount);

    end;

    inline($9C);

    OldTimer;

    dec(meml[$40: $6C]);

end;

DoTimer(前部分,用于启动热自助程序)

procedure DoTimer; interrupt;

begin

    InTimer := true;

    asm                     {Enter Critical Area}

        MOV   AL ,1

        XCHG  MyHandleActive , AL

        MOV   isActive, AL

    end;

    if (not isActive) and (NumTaskCurrent > 0) then[xuzj11] 

    begin

        asm

            CLI

            MOV   TempStack.S,SS

            MOV   TempStack.O,SP

        end;

[xuzj12]         if NumTaskCurrent > NumTaskLast then

        begin

            if NumTaskLast = 0 then

            begin

                GetIntVec($21, @OldDosServe);

                if noDosSwitch then

                    @MyDosServe := @OldDosServe

                else

                    @MyDosServe := @DosServe1;

                SetIntVec($21, @MyDosServe);

            end;

            PreviousTask := CurrentTask;

            Tasks[PreviousTask].stack := TempStack;[xuzj13] 

            inc(NumTaskLast);[xuzj14] 

            CurrentTask := NumTaskLast;

            Tasks[CurrentTask].stack := Tasks[CurrentTask].ostack;

            LastStack := Tasks[CurrentTask].stack;

            asm

                MOV  SS,LastStack.S

                MOV  SP,LastStack.O

            end;[xuzj15] 

            SaveVideo(CurrentTask - 1);

            if (Tasks[CurrentTask].havekey) or NoKeySwitch then

                SetIntVec($16, @OldKeyServe)

            else

                SetIntVec($16, @MyKeyServe);

            asm

                MOV  MyHandleActive,0 {Leave Critical Area}

            end;

            InTimer := false;

            inline($9C);

            Tasks[CurrentTask].Start.Proc;[xuzj16] 

            asm

                MOV  MyHandleActive,1 {Enter Critical Area}

            end;

            dec(NumTaskCurrent);

            dec(NumTaskLast);[xuzj17] 

 

            if NumTaskCurrent = 0 then

            begin

                GetIntVec($21, @MyDosServe);

                SetIntVec($21, @OldDosServe);

            end;

            for i := CurrentTask to NumTaskCurrent do

                Tasks[i] := Tasks[i + 1];

            for i := NumTaskCurrent downto 0 do

            begin

                if Tasks[i].needkey then Tasks[i].havekey := true;

            end;

            if CurrentTask > NumTaskCurrent then CurrentTask := 0;

            LastStack := Tasks[CurrentTask].Stack;

            RestoreVideo(CurrentTask);

            if (Tasks[CurrentTask].havekey) or NoKeySwitch then

                SetIntVec($16, @OldKeyServe)

            else

                SetIntVec($16, @MyKeyServe);

            asm

                MOV  SS,LastStack.S

                MOV  SP,LastStack.O

                MOV  BP,SP               {!!!}

                ADD  BP,2

            end;[xuzj18] 

        end

        else

 

… …

 

至此,热自助程序应该开始启动,并开动和后台行情分析软件间的切换工作!

 

热自助在键盘空闲之时会要求multask.exe
CPU切换给后台分析软件使用:

//GUI系统读键, 系统要求读键用此函数, 类似于bioskey()

int GuiKey(int cmd)

{

… …

       while (1)

       {

… …

              if(cmd == 0)

                     key = _bios_keybrd(_NKEYBRD_READY);

              else

                  key = bioskey(1);

… …

              else if (key == kbNoKey)

              {

… …

                     if(kbShiftTimes == 1 || !(Function&131072l))

                            if (getvect(0xd0))

                            {

                                   for(i=0;i<2;i++)

                                          asm{

                                          mov ax, 0x1974

                                          int 0xd0

                                             }[xuzj19] 

                            }

… …

 


multask.exe程序中对应调用:

serv

procedure serv(_Flags, _CS, _IP, _AX, _BX, _CX, _DX, _SI, _DI, _DS, _ES, _BP: Word); interrupt;

begin

    case _ax of

… …

        $1974:

            begin

                if (not InTimer) and (not DosBusy^) and (not Critical^) and (In13 = 0)

                    and (not NoTaskSwitch) then

                begin

                    InTimer := true;

                    inline($9C);

                   asm call far [dotimer] end;[xuzj20] 

                    InTimer := false;

                end;

            end;

… …

 

DoTimer(后半部分,用于任务间切换CPU)

procedure DoTimer; interrupt;

begin

    InTimer := true;

    asm                     {Enter Critical Area}

        MOV   AL ,1

        XCHG  MyHandleActive , AL

        MOV   isActive, AL

    end;

    if (not isActive) and (NumTaskCurrent > 0) then[xuzj21] 

    begin

        asm

            CLI

            MOV   TempStack.S,SS

            MOV   TempStack.O,SP

        end;

[xuzj22]         if NumTaskCurrent > NumTaskLast then[xuzj23] 

        begin

… …

        end

        else

            if not (NoTaskSwitch and (FixTask = CurrentTask)) then

            begin

 

                dec(Tasks[CurrentTask].CurrentTicks);

                if (Tasks[CurrentTask].CurrentTicks <= 0) then[xuzj24] 

                begin

                    PreviousTask := CurrentTask;

                    repeat

                        inc(Tasks[CurrentTask].CurrentTicks, Tasks[CurrentTask].TickInc);

                        CurrentTask := (CurrentTask + 1) mod (NumTaskCurrent + 1);

            {CurrentTask:=(CurrentTask+NumTaskCurrent) mod (NumTaskCurrent+1);}

                    until Tasks[CurrentTask].CurrentTicks > 0;[xuzj25] 

                    LastStack := Tasks[CurrentTask].Stack;

                    if (CurrentTask <> 0) then

                        asm

                            MOV SS,LastStack.S

                            MOV SP,LastStack.O

                            MOV BP,SP               {!!!}

                            ADD BP,2

                        end;[xuzj26] 

                    Tasks[PreviousTask].Stack := TempStack;[xuzj27] 

                    SaveVideo(PreviousTask);

                    RestoreVideo(CurrentTask);

                    if (Tasks[CurrentTask].havekey or NoKeySwitch) then

                        SetIntVec($16, @OldKeyServe)

                    else

                        SetIntVec($16, @MyKeyServe);

                    if (CurrentTask = 0) then

                        asm

                            MOV SS,LastStack.S

                            MOV SP,LastStack.O

                            MOV BP,SP               {!!!}

                            ADD BP,2

                        end;[xuzj28] 

                end;

            end

    end;

    TransCount := 0;

    if not isActive then

        asm

        mov MyHandleActive,0;

        end; {Leave Critical Area}

end;

 

InsertTask可见,行情分析软件在multask的管理队列Tasks数组中对应的下标为0,而热自助的程序的下标应该是1;

这段代码退出后,将开始继续运行后台行情分析软件的代码

 

等待下一个时钟中断时,执行MyTimer,并调用DoTimer时将后台行情分析软件切换到热自助:

以上应该就是实现双活机制的整个实现过程了.

 


 [xuzj1]设置热自助自己的堆栈地址

 [xuzj2]调用MULTASK.EXE提供的0x0920功能,插入一个任务,并由MULTASK去引导执行

 [xuzj3]回复堆栈地址(应该是行情分析软件的)

 [xuzj4]热自助程序自己的堆栈

 [xuzj5]插入在multask中任务并开始由其管理

 [xuzj6]热自助程序的入口程序

 [xuzj7]指定热自助程序的堆栈

 [xuzj8]用于重载0x08时钟中断向量

 [xuzj9]Pushf,防止执行OldTimer后破坏原来的堆栈

 [xuzj10]执行dotimer,其为启动热自助和实现双活的主要过程

 [xuzj11]此判断应该是为了防止重入或在无需任务切换时进入

 [xuzj12]保存当前的任务的堆栈信息

 [xuzj13]保存当前任务的堆栈指针;便于之后的任务切换或在退出时用于恢复原先的堆栈指针

 [xuzj14]增加一由MULTASK.EXE管理的任务

 [xuzj15]设置热自助任务的堆栈指针,使得启动热自助后使用此堆栈区间

 [xuzj16]执行到这儿,应该开始启动并显示热自助程序的主界面,并一直运行直到退出热自助程序

 [xuzj17]删除一热自助任务

 [xuzj18]恢复当前任务(应是后台行情分析软件)的堆栈指针

 [xuzj19]调用MULTASK.exe提供的0x1974功能进行切换CPU任务

 [xuzj20]调用dotimer的后半部分实现CPU切换

 [xuzj21]此判断应该是为了防止重入或在无需任务切换时进入

 [xuzj22]获取当前任务的堆栈指针

 [xuzj23]此段代码在有新任务加入时切换,其在前面已经有所描述

 [xuzj24]应该是用于控制任务切换的时间间隔,缺省应该是一个时钟中断间隔切换一次

 [xuzj25]依次对各任务的时钟占用增加指定间隔(缺省为1),若下一得到一任务的时钟占用大于0就跳出

 [xuzj26]恢复下一任务的堆栈指针,使得退出中断时即可运行该任务的代码(此段代码在热自助切换到后台行情分析软件时应该不会执行)

 [xuzj27]保存切换前的任务的堆栈指针

 [xuzj28]恢复下一任务的堆栈指针,使得退出中断时即可运行该任务的代码(此段代码在后台行情分析软件切换到热自助程序时应该不会执行)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值