热自助死机问题代码分析
流程图
热自助被激活时执行以下代码:
/* TSR 激活函数 */
void tsr_active(void)
{
if (dosbusy() && !int28_active)
{
hot_while_dosbusy = 1;
}
else
{
/* 设置自己的栈 */
enable();
/* 清键盘缓冲区 */
// while (bioskey(_KEYBRD_READY))
// bioskey(_KEYBRD_READ);
if (*(long far *)MK_FP(0, 0xd0 * 4))
{
_BX = FP_OFF(active);
asm{
mov ax, 0x0920
int 0xd0
}
else
active();
/* 恢复栈 */
}
}
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
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
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;
MOV AL ,1
XCHG MyHandleActive , AL
MOV isActive, AL
end;
if (not isActive) and (NumTaskCurrent > 0) then[xuzj11]
begin
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]
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(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);
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++)
mov ax, 0x1974
int 0xd0
}
… …
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;
MOV AL ,1
XCHG MyHandleActive , AL
MOV isActive, AL
end;
if (not isActive) and (NumTaskCurrent > 0) then[xuzj21]
begin
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;
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);
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]恢复下一任务的堆栈指针,使得退出中断时即可运行该任务的代码(此段代码在后台行情分析软件切换到热自助程序时应该不会执行)