home *** CD-ROM | disk | FTP | other *** search
- (****************************************************************************
-
- Program : Concurrent Programming Executive
-
- Author : J.F.J. Passant
- Version : 1.00
- Date : December 3, 1986
-
- Modified : March 31, 1987
- Author : Gary Black
- Purpose : Correct bug in TaskSwitch
- Version : 1.01
-
- Modified : April 17, 1988
- Author : Steve Fox
- Purpose : Modify for use under TP 4.0
- Version : 2.0
-
- *****************************************************************************)
-
- {$S-} { Stack checking off }
-
- Unit CpExec;
-
- Interface
-
- Uses
- TPCrt;
-
- procedure ClaimInput;
- procedure ReleaseInput;
- procedure Delay(ms: word);
- procedure TaskInstall(address: Pointer; size: word;
- var task: word; var heap: pointer);
- procedure TaskRemove(task: word; sp: pointer; size: word);
- procedure TaskWindow(X1, Y1, X2, Y2, FAttr, HAttr, WAttr: byte;
- cursor: boolean; title: string);
- procedure TaskSwitch;
-
- {============================================================================}
-
- Implementation
-
- const
- InputBusy : boolean = False;
- FrameSize = 18; { Context frame size }
- MaxTask = 15; { Highest numbered task }
- type
- TaskArea = array[1..FrameSize] of word; { Start of context frame }
- StackPointer = ^TaskArea;
- var
- ActiveTasks : array[0..MaxTask] of byte; { Active task flags }
- StackSize : array[0..MaxTask] of word; { Size of stack allocated }
- SPTable : array[0..MaxTask] of Pointer; { Active task stack pointers }
- CurrentTask : word; { Currently active task }
-
- {$I TPINLINE.INC}
-
- (***************************** Support Routines *****************************)
-
- procedure ClaimInput;
- { Wait for keyboard }
- begin
- while InputBusy do
- TaskSwitch; { Wait until task releases input }
- InputBusy := True
- end;
-
- procedure ReleaseInput;
- { Release keyboard for another task to use }
- begin
- InputBusy := False
- end;
-
- procedure Delay(ms: word);
- { Delay task for <ms> milliseconds.
- The resolution of this operation is limited to approximately 55 ms (one
- clock tick). }
- const
- TicsMSec = 0.01820648193; { Ticks per millisecond }
- TicsDay = 1573040; { Ticks per day }
- var
- CurrentTime: LongInt absolute $0040:$006C; { Ticks since midnight }
- timer: LongInt;
- begin
- timer := CurrentTime + round(ms * TicsMSec) mod TicsDay;
- while (CurrentTime < timer) or (CurrentTime > (timer + 1092)) do
- TaskSwitch
- end;
-
- procedure TaskError(msg: string; val: word);
- { Display a fatal error message and terminate the program. }
- begin
- write(msg);
- if val = -1
- then writeln
- else writeln(val:1);
- write('--- Program Terminated ---');
- halt(1)
- end;
-
- (**************************** Task Installation *****************************)
-
- procedure TaskInstall(address: Pointer; size: word;
- var task: word; var heap: pointer);
- { Install task number <task> at <address> and allocate <size> bytes for its
- stack. The stack is initialized, ready for <TaskSwitch> to activate the
- task. }
- var
- sp: StackPointer;
- begin
- task := 1;
- while (task <= MaxTask) and (ActiveTasks[task] = 1) do
- Inc(task);
- if task > MaxTask
- then TaskError('Too many tasks ', task);
- if MaxAvail < size
- then TaskError('Not enough memory to install task ', task);
-
- StackSize[task] := size;
-
- GetMem(sp, size); { Point <sp> to top of stack }
- heap := sp;
- sp := Normalized(sp);
- sp := Normalized(ptr(Seg(sp^), Ofs(sp^) + size - SizeOf(TaskArea)));
- SPTable[task] := sp; { Save the task stack pointer }
-
- FillChar(sp^, SizeOf(TaskArea), #0); { Initialize the task registers }
- sp^[FrameSize ] := Seg(address^); { IP }
- sp^[FrameSize - 1] := Ofs(address^);
- sp^[FrameSize - 2] := $0200; { Flags, interrupts enabled }
- sp^[FrameSize - 3] := DSeg; { DS }
-
- ActiveTasks[task] := 1 { Task enabled }
- end;
-
- procedure TaskRemove(task: word; sp: pointer; size: word);
- { Remove a previously installed task }
- begin
- if CurrentTask <> task
- then
- begin
- ActiveTasks[task] := 0;
- FreeMem(sp, size)
- end
- end;
-
- procedure TaskWindow(X1, Y1, X2, Y2, Fattr, HAttr, WAttr: byte;
- cursor: boolean; title: string);
- { Prepare a portion of the screen for a task }
- begin
- FrameWindow(X1, Y1, X2, Y2, FAttr, HAttr, title);
- Window(succ(X1), succ(Y1), pred(X2), pred(Y2));
- TextColor(WAttr and $0F);
- TextBackground(WAttr shr 4);
- if not cursor
- then HiddenCursor
- end;
-
- (****************************** Task Switching ******************************)
-
- procedure TaskSwitch; external;
- { The task switcher }
- {$L CPEXEC.OBJ} { External assembly code }
-
- (**************************** Unit Initialization ***************************)
-
- begin
- FillChar(ActiveTasks, SizeOf(ActiveTasks), #0); { Disable all tasks }
- ActiveTasks[0] := 1; { Activate main program (task 0) }
- CurrentTask := 0 { and make it current }
- End.