Unit Multi; {--------------------------------------------------------------------------------} { } { Hilfsfunktionen zur quasi-Multitaskingverarbeitung unter Turbo Pascal } { } { (c) 1994 by Hegel Udo } { } {--------------------------------------------------------------------------------} Interface {--------------------------------------------------------------------------------} Type StartProc = Procedure; {--------------------------------------------------------------------------------} Procedure AddTask (Start : StartProc;StackSize : Word); Procedure Transfer; {--------------------------------------------------------------------------------} Implementation {--------------------------------------------------------------------------------} Uses Dos; {--------------------------------------------------------------------------------} Type TaskPtr = ^TaskRec; TaskRec = Record StackSize : Word; Stack : Pointer; SPSave : Word; SSSave : Word; BPSave : Word; Next : TaskPtr; end; {--------------------------------------------------------------------------------} Const MinStack = 1024; MaxStack = 32768; {--------------------------------------------------------------------------------} Var Tasks : TaskPtr; AktTask : TaskPtr; OldExit : Pointer; {--------------------------------------------------------------------------------} Procedure AddTask (Start : StartProc;StackSize : Word); Type OS = Record O,S : Word; end; Var W : ^TaskPtr; SS : Word; SP : Word; begin W := @Tasks; While Assigned (W^) do W := @W^^.Next; New (W^); if StackSize < MinStack then StackSize := MinStack; if StackSize > MaxStack then StackSize := MaxStack; W^^.StackSize := StackSize; GetMem (W^^.Stack,StackSize); SS := OS(W^^.Stack).S; SP := OS(W^^.Stack).O+StackSize-4; Move (Start,Ptr(SS,SP)^,4); W^^.SPSave := SP; W^^.SSSave := SS; W^^.BPSave := W^^.SPSave; W^^.Next := NIL; end; {--------------------------------------------------------------------------------} Procedure Transfer; Assembler; Asm LES SI,AktTask { Alter Status sichern } MOV ES:[SI].TaskRec.SPSave,SP MOV ES:[SI].TaskRec.SSSave,SS MOV ES:[SI].TaskRec.BPSave,BP MOV AX,Word Ptr ES:[SI].TaskRec.Next { Neue Task bestimmen } OR AX,Word Ptr ES:[SI].TaskRec.Next+2 JE @InitNew LES SI,ES:[SI].TaskRec.Next JMP @DoJob @InitNew: LES SI,Tasks @DoJob: MOV Word Ptr AktTask,SI { Neue Task Sichern } MOV Word Ptr AktTask+2,ES CLI { Status wieder hertstellen } MOV SP,ES:[SI].TaskRec.SPSave MOV SS,ES:[SI].TaskRec.SSSave STI MOV BP,ES:[SI].TaskRec.BPSave end; {--------------------------------------------------------------------------------} BEGIN New (Tasks); { Hauptprogramm als Task anmelden } Tasks^.StackSize := 0; Tasks^.Stack := NIL; Tasks^.Next := NIL; AktTask := Tasks; END. { -------------------------- DEMO PROGRAM ---------------------- } Program Multi_Demo; Uses DOS, Crt, Multi; TYPE ScreenState = (free, used); { Is screen position free? } WindowType = Record { Window descriptor } X, Y, Xsize, Ysize : Integer; End; var screen : Array(.0..81,0..26.) of ScreenState; WindowTable : Array(.1..20.) of WindowType; i,j, { Index variables } NoWindows : Integer; { No. of windows on screen } Procedure MakeWindow(X, Y, Xsize, Ysize: Integer; Heading: String); { Reserves screenspace for window and draws border around it } const NEcorner = #187; { Characters for double-line border } SEcorner = #188; SWcorner = #200; NWcorner = #201; Hor = #205; Vert = #186; var i,j : Integer; Begin Window(1,1,80,25); { Reserve screen space } For i:=X to X+Xsize-1 Do For j:=Y to Y+Ysize-1 Do screen(.i,j.):=used; { Draw border - sides } i:=X; For j:=Y+1 to Y+Ysize-2 Do Begin GotoXY(i,j); Write(Vert); End; i:=X+Xsize-1; For j:=Y+1 to Y+Ysize-2 Do Begin GotoXY(i,j); Write(Vert); End; j:=Y; For i:=X+1 to X+Xsize-2 Do Begin GotoXY(i,j); Write(Hor); End; j:=Y+Ysize-1; For i:=X+1 to X+Xsize-2 Do Begin GotoXY(i,j); Write(Hor); End; { Draw border - corners } GotoXY(X,Y); Write(NWcorner); GotoXY(X+Xsize-1,Y); Write(NEcorner); GotoXY(X+Xsize-1,Y+Ysize-1); Write(SEcorner); GotoXY(X,Y+Ysize-1); Write(SWcorner); { Make Heading } GotoXY(X+(Xsize-Length(Heading)) div 2,Y); Write(heading); { Save in table } NoWindows:=NoWindows+1; WindowTable(.NoWindows.).X:=X; WindowTable(.NoWindows.).Y:=Y; WindowTable(.NoWindows.).Xsize:=Xsize; WindowTable(.NoWindows.).Ysize:=Ysize; End; { MakeWindow } Procedure SelectWindow(i : Integer); { Specifies which window will receive subsequent output } Begin With WindowTable(.i.) Do Begin Window(X+1,Y+1,X+Xsize-2,Y+Ysize-2); End; End; { SelectWindow } Procedure RemoveWindow(n: Integer); { Removes window number n } var i,j : Integer; Begin SelectWindow(n); With WindowTable(.n.) Do Begin Window(X,Y,X+Xsize,Y+Ysize); For i:=X to X+Xsize Do For j:=Y to Y+Ysize Do screen(.i,j.):=free; End; { With } ClrScr; End; { SelectWindow } Procedure Task1;Far; VAR SR : SearchRec; begin MakeWindow(27, 2,18,4,' Sub Task 1 '); REPEAT FINDFIRST('*.*',anyfile,SR); WHILE DOSERROR = 0 DO BEGIN Transfer; SelectWindow(2); WriteLn(SR.Name : 12); FINDNEXT(SR); Delay(10); END; UNTIL FALSE; end; Procedure Task2;Far; VAR SR : SearchRec; begin MakeWindow(27, 7,18,4,' Sub Task 2 '); REPEAT FINDFIRST('\TURBO\TP\*.*',anyfile,SR); WHILE DOSERROR = 0 DO BEGIN Transfer; SelectWindow(3); WriteLn(SR.Name : 12); FINDNEXT(SR); Delay(10); END; UNTIL FALSE; end; Procedure Task3;Far; VAR SR : SearchRec; begin MakeWindow(27,12,18,4,' Sub Task 3 '); REPEAT FINDFIRST('\TURBO\*.*',anyfile,SR); WHILE DOSERROR = 0 DO BEGIN Transfer; SelectWindow(4); WriteLn(SR.Name : 12); FINDNEXT(SR); Delay(10); END; UNTIL FALSE; end; Procedure Task4;Far; VAR SR : SearchRec; begin MakeWindow(27,17,18,4,' Sub Task 4 '); REPEAT FINDFIRST('\*.*',anyfile,SR); WHILE DOSERROR = 0 DO BEGIN Transfer; SelectWindow(5); WriteLn(SR.Name : 12); FINDNEXT(SR); Delay(10); END; UNTIL FALSE; end; BEGIN ClrScr; MakeWindow( 5,21,75,4,' Multi-Program Demo '); SelectWindow(1); WriteLn(' This is the MAIN task window and we will start 4 others too'); AddTask (Task1,8192); AddTask (Task2,8192); AddTask (Task3,8192); AddTask (Task4,8192); REPEAT Transfer; UNTIL KEYPRESSED; END.