Process structure for interactive software There are applications in which both fast display movement and quick response to input signals are required. Programming for this becomes quite complicated when the display includes a number of independent activities. John Ogden describes a concurrent program, in MODULA-2, which overcomes these problems
The domestic personal microcomputer invites its owner to create applications for it. Prominent among these are games, some of which ca//for real-time responses from the user to a complex rapidly moving display, it is argued that BASIC and other conventional high level languages are unsuitable for such tasks. A program structure based on the concept of processes is described and advocated. microprocessors
processstructure
interactive software
Anyone writing software for a personal microcomputer will soon discover that there are situations (such as programs for dynamic games) where fast movement of the display is required, but at the same time the program must respond quickly to input signals from the user. This is not very difficult if only one fast-moving activity is taking place, but becomes very complicated indeed when the display includes a number of independent activities. Interpreted BASIC has two weakness for work of this kind. One is the fact that, being interpreted, it is often slow. The second is that it is a sequential programming language. A program in BASIC (or FORTRAN or PASCAL) defines a single sequence of calculations, or of manipulations of an external device such as a display, advancing in time as fast as the processor or interpreter will permit. Such a sequence of events we may call a process. Only with the greatest difficulty can such a language be used to define a number of separate processes advancing in time, independently of one another at different rates, and starting, pausing or stopping either at random or on receipt of signals either from the computer user or from other processes. Such processes are often referred to as concurrent. Writers of games may thus be forced into using assembly language to gain the advantage of speed. There are, however, considerable problems in organizing an assembly language program of this type. It is important 'to realize that more is called for than simply additional speed of execution if the full value of the machine-code Department of Computer Science, The University of Reading, Whiteknights, Reading, Berks RG6 2AX, UK
vol 6 no 6july/august i982
is to be obtained. If the program includes several independent activities on the monitor screen, or sliding tones on the sound channel, then a process routine structure such as that described in this article can greatly simplify these activities. Several authors 1-4 have addressed this problem. The programming languages including ALGOL 68, MODULA, Concurrent PASCAL, ADA and now Concurrent EUCLID have incorporated the notion of concurrent processes. They have offered a variety of mechanisms to provide for secure suspension and resumption of processes. Special attention has been given to the problems posed by cooperating processes, which share access to some system resource or data structure. It is critically important that at particular times one process should be able to enjoy exclusive access to the resource or data structure. Control is transferred between processes as a consequence of some event. One class of event is the interrupt, which signals that a resource awaited by a process is now free. Another class of event is the purely software incident, in which a process that has temporarily claimed exclusive access to a data structure releases it. Decisions concerning such transfer of control are taken by a program unit known as a scheduler. In some languages the scheduler is inaccessible and cannot be adapted. In others it is comparatively easy for an installation, even an individual user, to furnish his own. This paper describes a very simple scheduler, and the associated facilities required by authors of process routines, for controlling a number of processes so that each is activated briefly at regular intervals. In this way the processes appear to behave in the independent manner described above. The mechanisms are described in high level language terms, for the sake of clarity, but are very easily realized in assembly language. The primary objective of this system is to provide user interaction with complex moving graphical displays having a number of independent graphical components. The description is cast in terms of computer games. Industrial and education applications, for example in training and simulation, should not be hard to find. In the text we shall use a PASCAL-like notation to illustrate the logical structures in a clear way. An appendix contains a MODULA-2 implementation of the system.
0141-9331/82/060297-06 $03.00 © 1982 Butterworth & Co [Publishers) Ltd
297
PROCESS ROUTINES A process routine is a piece of program, including loops, branches, etc. which drives a process. One such process might be the movement of a graphical object across the monitor screen, or the generation of a complex sequence of sounds from the loudspeaker. The code of a process routine can be considered as being divided into subsections, each of which • advances the external process by a single step (for example, moving a graphical object a small interval across the screen, or raising the pitch of a sound by 5 Hz) • contains a call of a subroutine named suspend. Such a subsection may of course be embedded in a loop in the process routine. The call of suspend simply surrenders control to a master control routine, named the scheduler, which is then able to activate other processes before eventually returning to this present process routine. The suspend subroutine takes a single parameter, n, whose function will be described later. After a certain time, control returns from the suspend call, just as if it were an ordinary subroutine call. The process routine is resumed to nudge its process one step further forward before it is again suspended by a call of suspend. As far as a process routine is concerned, the calls of suspend accomplish nothing except to hand control temporarily to the scheduler. To illustrate the ideas involved, here is a process routine which will result in a sound gliding from 1 kHz to 2 kHz in steps of 10 Hz. PROCEDURE glide; VAR freq, incr, count: C A R D I N A L freq:0..66536; incr:0..255; count:0..255; BEGIN freq := 1000; incr := 10; count := 101; REPEAT
sound(frequency) suspend(3); freq := freq+incr;
A process is represented within the computer by a block of data called a PC block (process control). All the data that the process routine requires to drive the process are housed in a PC block. This information might include the coordinates on the display screen of the graphical object which is under the control of this process, details of its direction and manner of movement, etc. For a process driving a sound generator, the PC block might hold the frequency value last sent to the sound generator, and the next increment to be added to or subtracted from that frequency value to produce a gliding tone. In either of these cases there might also be a counter defining the number of times the process is to be activated. In the example above, the reserved word, PRIVATE, is intended to suggest the declaration of names by which the process routine will refer to these private areas of a PC block. The relationship between a process, a PC block and a process routine may be understood in a number of ways. Perhaps the most helpful is to suggest that a process is the result of the action of a process routine upon a PC block, as shown in Figure 1. Note particularly that the process routine consists exclusively of code, all data being accommodated in the PC block. Because of this rigid separation of code and data (familiar in ROM-based work), a given process routine can quite easily control a number of similar processes, each one having its own control block. This extension is described diagrammatically in Figure 2. In addition to the information used by the process routine, there are, in each PC block, two items required by the scheduler. These are a counter, called the sleeper, and an address called retadd (RETurn ADDress). We shall represent a PC block as a PASCAL record: TYPE PCBTYPE = RECORD sleeper:O..255; retadd:0..65535;
routine
298
\
ro,e,s) block control
---
Figure 1. The relationship between a process, a process control block and a process routine. The process is the result o f a routine acting on a PC block
count := count-1 UNTIL count=0 silence; suspend(O) END; The primitive operations sound and silence are assumed, to initiate and terminate the production of sound. The final call of suspend[O) is intended to extinguish this process completely. It is arguable that, in a high level notation, this final call of suspend(O) should be implicit in the END of the process routine, since control need not return from such a call. The greater part of a program will consist of a number of such processes each of which is activated, in turn, at sufficient speed to give the illusion of independent activities proceeding in parallel. In addition there will probably be a block of conventionally organized code at the beginning to set important variables and to initiate some of the processes. The program'will also end with a block of sequential code to display results.
'J
used by the scheduler
PCblockI )
F~ocess routi ne
PC block 2)
block
n)
Figure 2. The figure shown an extension o f Figure I with more than one PC block and more than one process
microprocessors and microsystems
. . . . .
..... ..... .....
other fields containing information private to a particular process
END; The size of each PC block depends solely on the amount of information required to describe the current state of an individual process - anything from 5 to 100 byte might be reasonable. These PC blocks might be organized in many ways. Provided their maximum size is not large, by far the simplest is to reserve an area of memory capable of containing (say) pcbmax PC blocks of fixed (maximum) size. In PASCAL we could declare these in the following way: PCB:ARRAY [1..pcbmax] OF PCBTYPE; providing for pcbmax PC blocks. Experience with a 2 MHz Z80 suggests that 20 is a reasonable upper limit for the number of concurrent processes. Using the PASCAL notation for referring to fields of a record, the sleeper field of the ith PC block is: PCB[i] .sleeper For some processes this technique will waste a good deal of space, but any more sophisticated memory-management package, such as would be required if PC blocks were to be of variable size, would suffer from two even more serious disadvantages. First, the code of a garbage-collector is likely to be large and complicated, thus cancelling any saving of space. Secondly, the garbage-collector is liable to be called at unpredictable times, thus causing hiccups in the smooth progress of the external processes. In such an array of PC blocks, each is in one of three states. • sleeper > 1 - this block corresponds to a suspended process • sleeper = 0 - this block is not in use by any process • sleeper = 1 - this block corresponds to a process which is currently active Control is switched between processes, via calls of the suspend subroutine, by the scheduler which consists essentially of two nested loops. The inner cycle of the scheduler inspects the PC blocks in turn. The outer cycle repeats the inner cycle until some condition arises (usually a timing condition) which indicates the end of the real-time section of the program. The outer cycle may also include calls of conventional subroutines to carry out tasks which must be performed regularly. For example, one such subroutine may initiate processes on the basis of a pseudo-random number generator. Another example would be a routine to read the keyboard and store the input character in some place accessible to all process routines. During each inner cycle then, each PC block is inspected once, the immediate focus of attention being the value of sleeper. The following is a high level description of the scheduler logic. REPEAT read keyboard; inputchar := character read; initiate random processes; FOR i := 1 TO pcbmax DO BEGIN IF PCB[i] .sleeper = 1
vol 6 no 6july/august 1982
(outer
cycle)
(inner cycle)
THEN GOTO PCB[i] .retadd ELSE IF PCB[i] .sleeper > 1 THEN PCB[i] .sleeper :=PCB[i] .sleeper - 1 ; 99: (suspend subroutine resumes the scheduler scan at this point) END UNTIL time is up; (Note that if the scheduler finds sleeper=0, nothing at all is done to that PCB because it does not correspond to any current process) The value of retadd is the return address of a suspend call in some process routine, so this transfer of control has the effect of resuming the suspended process routine at the instruction following that call. Control now resides in the process routine until the next call of suspend is encountered. The action of a suspend call is simply to place its own return address in the retadd field of the current PC block, place its parameter, n, in the sleeper field of the current PC block, and finally transfer control to the label 99 in the inner cycle, which steps along to the next block in the table. The effect of a call suspend(n) (n>0) is therefore to put this current process to sleep for n complete inner cycles of the scheduler. The call suspend(0) will kill the process completely. During the time a process is suspended, other processes may have been initiated, resumed, suspended or killed off. If a large value of n is used, the corresponding process will seem to run slowly: if a small value is used it will run more quickly. The chosen value of n may, of course, be embedded in the coding of the process routine as a constant. Alternatively, and more interestingly, it can be selected (perhaps at random) and stored in the PC block, thus permitting processes driven by the same process routine nevertheless to proceed at different rates. When the activity of a process is completed, the final action of the process routine is a call suspend(0), which kills a process completely.
IN I T I A T I N G PROCESSES In addition to the scheduler itself there must be a routine to initiate a new process. It must be possible to do this from within a process routine, i.e. any process when it is itself active, must be able to initiate another process. Initiating a new process requires the following steps: • find a free PC block - i.e. one whose sleeper field is 0 • set the sleeper field to 1 • place in retadd the start address of the process routine In our PASCAL-like notation, a statement: START slide; might carry out these operations.
I N P U T PROCESSES The processes described thus far communicate with the user by vision or by sound. The same mechanism also provides a convenient way of inspecting the keyboard or other input device at regular intervals - once in each inner cycle of the scheduler. Such a process routine might, for example, inspect the location in which the
299
read-keyboard routine leaves the current input character and inquire if a particular key has been depressed: if so, the rest of the process routine is executed; if not the process routine is simply suspended again. Thus: PROCESS-ROUTINE key A; BEGIN DO IF inputchar='A ' THEN BEGIN action required when key 'A' is depressed •
o
.
END; suspend (5) OD; END; this will check for the key A every five outer cycles. The D O . . . OD construction is a loop which is cycled endlessly: this process is assumed to go on for ever. If several keys are designated each with a particular function, the coding to check for the use of that key, and to carry out the corresponding function, is localized within a single process routine. In fact each key might have a process routine of its own. In essence the method described for handling input signals is very similar to the traditional busy loop, with one important difference. It is assumed that a separate executive deals with the interrupts and leaves the current signal (a character, say) in a globally accessible location. The important difference between the process routine and the busy loop, or other sequential technique, is that a process routine can regularly inspect the current signal location. This activity can be interleaved with other processes, which are not hindered by the delay. Should the process mechanism be employed in a context where there is no ready-made monitor to deal with interrupts, the design would have to be extended. A process would need to suspend itself awaiting a particular class of interrupt, rather than the lapse of a predetermined number of outer cycles. The scheduler would need to maintain a list of processes awaiting interrupts, and on receipt of an interrupt resume the appropriate process. This mechanism for control of input stands in marked contrast to that forced upon programmers by sequential languages such as BASIC where, typically, the code to inspect the keyboard is centralized in a particular place in the code and the character read is compared in turn with all meaningful alternatives. In the process structure it is extremely easy to add and delete complete processes, corresponding to complete user-image features of the program. In fairness, it must be said that there are advantages and disadvantages to both styles, depending on the nature of the program being written. Board games such as Othello and Chess can be characterized as 'your move next' games, and the sequential style of organization is perfectly satisfactory here. The process structure is valuable in the class of programs which we might call 'dynamically interactive' where real-time response is called for on the part of the computer user at the same time as the computer is carrying out other real-time tasks such as graphical movements. In the system described, interprocess communication is limited. The general philosophy is that no process ever
300
transfers control directly to another process: such transfers take place only via the scheduler. Further, data communication is possible only via global memory locations. Each of these represents a considerable simplification of the position adopted by the designer of a real-time high level language. One process might be producing characters destined to be consumed and output by another process. Between them lies a buffer capable of accommodating a finite number of characters. The producer process needs a way of discovering whether the buffer is not full and therefore able to receive a new character. Should the buffer be full, the producer must be capable of suspending itself in such a way that it will be resumed as soon as the consumer has removed a character from the buffer. The term semaphore has been widely adopted as denoting a class of variables providing precisely this type of interprocess communication. No attempt has yet been made to extend the present work to include such features. Indeed, in the author's judgement, it would be far preferable to urge the wider use of languages tht are capable of providing the security requisite in such applications.
CONCLUSIONS A process scheduler which relies on selfadministered selflimiting anaesthesia for its process routines has been described. It should be possible to augment the basic structure outlined here with a mechanism for resuming a suspended process when the scheduler encounters some predetermined condition, such as interrupts or time-of-day. This would depend very much on the characteristics of the particular microcomputer and its monitor• The mechanism that has been described for scheduling processes admirably suits the characteristics of the single-user systems available today. Its uses, as a strategy for structuring applications involving dynamic interactive graphics, range from domestic or arcade games to simulators training personnel to control complex and expensive dynamical systems. Though the control mechanism is simple to implement in assembly language, serious applications will not be so tractable. What is needed is a wider recognition of the value of languages which support concurrent processes. Such a language would be a great asset to a microcomputer user.
ACKNOWLEDGEMENTS The author is grateful to his colleagues, Dr M F Smith and Dr R J Loader, for advice, clarification, and encouragement.
REFERENCES 1 BrinchHansen,P Operating Systems Principles Prentice Hall, Englewood Cliffs, New Jersey, USA
(1973) 2 Dijkstra, E W 'Cooperating sequential processes' Programming Languages (ed Genuys, F) Academic Press, London, UK (1968) 3 Holt, R C 'A short introduction to concurrent Euclid' ACM 51GPLAN Notices Vol No 5 (May 1982) 4 Wirth, N Modula-2 Institut for Informatik, ETH, Zurich, Switzerland (1980)
microprocessors and microsystems
Foley, J D and Van Dam, A, Fundomentob of InteroctiveComputer Graphics, Addison-Wesley; Reading, Massachussetts, USA (1982) APPENDIX An implementation of the elements of the system is given below, written in MODULA-2. The principal differences between this implementation and that described in the paper lie in the structure of the PC block. Here the PC block as such is limited to the information required by the scheduler. All other information about a process is held in the local workspace of a particular 'incarnation' of the corresponding process routine. The program was developed and run under UNIX on a PDP-11/44. The 'main program' is a module called movers, whose listing appears last in the sequence. Before it, came two other implementation modules (definition modules are not given): TVI provides escape sequencesto a TVI DT2 terminal; Scheduler is, of course, the scheduler itself. 'With the comments these programs should be selfexplanatory.
1 2 3 4 5 6 7 8 9 10 ii 12 13 14 15 16 17 18 19
000000 000000 000000 000000 000006 000020 000040 000040 000040 000000 000006 000054 000054 000054 000066 000100 000120 000146 000146
I OOOUO0 2 0000UO 3 000000 4 O00OO0 5000000 6 000000 7 000000 8 000000 9 000000 10 000000 ll'O0000O 12 OOO000 15 OOO000 14 000000 15 000000 16 000000 17 000000 18 000000 ig 000000 20 0 0 0 0 0 0 21 O0000O 22 0 0 0 0 0 0 23 0 0 0 0 0 0 2 4 O000OO 25 O0000O 26 0 0 0 0 0 0 27 0 0 0 0 0 0 28 0 0 0 0 0 0 29 0 0 0 0 0 0 30 0 0 0 0 0 0 31 0 0 0 0 0 0 32 0 0 0 0 0 0 33 0 0 0 0 0 0 34 0 0 0 0 0 0 35 0 0 0 0 0 0 36 0 0 0 0 0 0 37 OOOU00 38 000000 39 0 0 0 0 0 0 40 000000 41 000000 42 OOOO00 43 OOOO00 44 000000 45 0 0 0 0 0 0 46 000000
IMPLE)~J(TATIUN MODULE TVI; F R O M T T I O IMPORT Write; PROCEDURE Clearnull; BEGIN Write(33C); (* ESC *) Write(52C); (* * *) E N D Clearnull; PROCEDURE CoOrdinates(x,y:CARDINAL); BEGIN IF (x80) U R (y24) T H E N RETURN END; Write(33C); (* ESC -) Write(75C); (* Write(CHR(y+31)); Write(CHR(x+31)) E N D CoOrdinates; E N D TVI.
.
w)
I)WLERY.NT&TION MODtTLE Scheduler; F R O N S Y S T E M IMPORT PROCZBS, ~'#PROCESS, TRANSFER, WORD, ADDRESS, ADR, SIZE; CONST wslen - 150; (*
The tlrpe ProcessControlBlock contains those items in a PCB which must be available to the Scheduler. o t h e r information, such as the local variables of the p r o c e d u r e eJ~xx]ying the code which drives the process, are housed in the w o r k s p e c e a r e a supplied w h e n each new process is initiated using NEWPROCESS
*)
TYPE ProcesaControlBlock - RECORD Sleeper: CARDINAL; Pr :pROCESS END;
47 48 49 50 51 52 53 54 55 56 57 58 59 50
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 32 83 B4 55 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 i01 102 103 104 105 106 107 ]08 109 ii0 I]] 112 113 114 115 116 ]17
000000 000000 V A R i :CARDINAL; 000O00 BEGIN (* Find a ProcessControlBlock whose Sleeper field is zero *) 000000 ,z-l; 000006 LOOP 000014 (* If no such Block available, abandon this attempt 000014 to launch a new process *) 000014 TF i>20 T R E N RETURN END; 000032 000032 ( * When a zero sleeper found quit the loop *) 000032 IF PCB[i].Sleeper = 0 THEN E X I T END; 000064 i:- i+l 000064 END; 000076
000112 000130 000142 000142 000142 000160 000160 000160 000160 000166 000166 000166 000216 000234 000234 000234 000234 000234 000234 000234 000234 000234 O00O00 000006 000012 000012 000034 000042 000056 000074 000106 000120 000136 000150 000166 000174 000224 000242 000242 000000 000000 000000 OOO000 000036 000106 000106 000106 000]32 000132 000132 000136 000164 000164 000164 000164 000224
CoOrdinates( Write( ' ' ) END;
x, y ) ;
(* when finished set tl - TRUE * ) tl :- TRUE; (* E ~ F l a g U P becomes true if both processes have finished * ) EndFlagb~ :- tl A N D t2; (- Finally kill this process *) Suspend( 0 ) END star; PROCEDtrR~ query; (*
T h i s procedure is exactly t h e same as star, but it moves a "?" from the b o t t o m left corner upwards and to the right. No further comments are necessary " ) ~rAR i, x, y:CARDZNAL; BEGIN t2 :- FALSE; F O R i :m i T O 24 DO X :" i; y :" 25-i; CoOrdinates( x, y ); Write( 77C ); (* ? *) Suspend( V2 ) ; CoOrdinates( x, y ); Write( ' ' ) END; t2 ~m TRUE, EndFlagUp :- tl A N D t2; Suspend( 0 ) END query ; BEGIN (* This is the "main program". First action is to read the values for vl and v2. *) WriteSt ring( "star speed :",11 ); ReadInt ( vl, nch, isnum); WriteString( "query speed :", 12 ); ReadInt( v2, nch, isnuM), (* Clear the screen *) Clearnull; (* Start the two processes *) StartProcess( star, ADR( starwsp ),wslen ) ; StartProcess( query, ADR( querywsp ),ws len ); (* This call of RunProcesses re-enters the Scheduler *)
RunProcesses END ~overs.
,tAR PCBtARRA¥[I.. 20]OF ProcessControlBlock; wSp:ARRAY[I..wslen] O F WORD; (* workspace for the Master process * ) Temp, ached :PRO(ZSS; (* T e R p is a strictly temporary process. It is USed to h o l d the current state of the m a i n program w h e n i n i t i a t i n g Master. Sched always holds the activation record of the Master process, the scheduler itself
*)
V A R CurrentProcese :CARDINAL; (* Used as a running variable b y M a s t e r when scanning the set of PCBS. It is global so that the Suspend routine can use i t . *) pROCEDURE StartProcess(P:PROC; A:ADDRESS; n=CARDINAL); (* Initiate a neW process. P is the name o f the procedure which w i l l drive the process; A is the address of the workepace w h i c h will hold the local variables of that p r o c e d u r e (and its working stack for nested procedure calls); n is a CARDINAL value giving the length of that workspace *)
vol 6 no 6july~august 1982
122 ]23 ]24 125 125 127 128 129 130 131 132 133 134 ]35 136 137 135 139 140 141 142 143 144 145
000250 000272 000272 000272 000272 000272 000272 000272 000272 000272 000000 000006 000030 000030 00OOOO 000000 000012 000012 000012 000016 000016 000016 000050 000072
TRANSFER( S c h e d , Temp ) F,ND M a s t e r ; PROCEDORE RunProcesses; (* This procedure is the user's route b a c k to the Scheduler. The Scheduler (Procedure Master) is resumed at the point immediately preceding its REPEAT loop - ) BEGIN TRANSFER( Temp, Sched ) E N D RunProcesses, BEGIN (* Initial value for BndFlagup * ) EndFlagUp :- FALSE; (* Create the Scheduler process .... *) NEWPROCESS(MasteE, ADR(wsp), SIZE(wsp), ached); (- .... and make the initial entry to it *) TRANSFER( T u ~ p , Sched ) E N D Scheduler.
301
1 2 3 4 5 6 7 8 9 i0 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000006 000006 000006 000006 000012 000012 000012 000012 000034 000042 000050 000050 000050 000066 000066 000066 000100 000100
302
M O D U L E movers; FROM TTIO IMPORT Write,ReadInt,WriteString; F R O M T%q I M P O R T C o O r d i n a t e s , c l e a r n u l l ; FROM Scheduler IR~ORT StartProcess, Suspend,EndYlagUp,RunProcesses; FROM SYSTEM IMPORTWORO,ADR; (* w s l e n s p e c i f i e s w o r k s p e c e *) C O N S T w s l e n - 150;
the length of p r o c e s s
(* s t a r w s p and q u e r y w s p are for the two p r o c e s s e s *) V A R s t a r w s p , q u e r y w s p : A R R A Y [ 1 . . w s l e n ] OF WORD; (* two b o o l e a n s t o i n d i c a t e the c o m p l e t i o n of the two p r o c e s s e s *) tl,t2:BOOLEAN; (* nch and i s n u m are r e q u i r e d only for the r a t h e r p e c u l i a r I/O r o u t i n e s used in this s y s t e m *) nch:CHAR; (* vl and v2 are the ( c o n s t a n t ) s l e e p e r v a l u e s used in the t w o p r o c e s s e s *) vl,v2:INTEGER; (* see above, isnum:BOOLEAN;
c o m m e n t on nch *)
P R O C E D U R E star; (* This p r o c e d u r e drives a p r o c e s s w h l c h m o v e s a c h a r a c t e r "," across the s c r e e n s t a r t i n g at the t o p left and p r o g r e s s i n g d i a g o n a l l y d o w n and right. It has no t e c h n i c a l i n t e r e s t b e y o n d i l l u s t r a t i n g the p r i n c i p l e s of the p a p e r *) V A R i,x,y:CARDINAL; BEGIN (* tl - F A L S E until this p r o c e s s h a s b e e n c o m p l e t e d tl :- FALSE;
*)
(* T h e r e are 24 lines on the d i s p l a y screen, t h e r e f o r e 24 p o s s i b l e p o s i t i o n s of the "*" *) FOR i :- i TO 24 DO (* x , y are the c o - o r ~ i n a t e s on the s c r e e n at w h i c h we w i s h to d i s p l a y the "*" *) x :- i; y z- i; CoOrdinates(x,y); (* now w r i t e the "*" itself *) Write(52C); (* * (* S u s p e n d this p r o c e s s S u s p e n d ( v 1 );
*)
*)
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 76 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 i00 101 102 103 104 105 106 107 ]08 109 Ii0 iii i12 113 114 115 116 117 118 119 120
000076 000076 00oi00 oo0100 oo0100 000126 000125 000210 000210 000210 00000o o00000 0oo000 000000 000006 000006 000030 000034 000056 000064 00006% 00006% 000064 000000 000000 000000 000000 O00000 000000 000054 000054 000054 000072 000072 000072 000106 000106 000106 000106 000106 000130 000130 000160 000200 000222 000222 000222 000222 000222 000222 000222 000222 000222 000240 000240 000240 000240 000240 000240
(*
Set the sleeper field of the to force an entry first time PCB[i].Sleeper : - 1;
new p r o c e s s round * )
to
1,
(* C r e a t e a new p r o c e s s *) NEWPROCESS( P, A, n, P C B [ i ] .Pr); END 3 t a r t P r o c e s s ; P R O C E D U R E Suspend( s ~C A R D I N A L ) ; BEGIN (- C u r r e n t P r o c e s s h o l d s the index, in PCB, of the p r o c e s s that has b e e n r u n n i n g -) WITH PCB[CurrentProcess ] DO S l e e p e r :- s; (* store s in its s l e e p e r field * ) T R A N S F E R ( P r , S c h e d ) (* and t r a n s f e r to the S c h e d u l e r *) E N D (* W I T H *) E N D Suspend; P R O C E D U R E Master; V A R i : INTEGER; BEGIN (* I N I T I A L E N T R Y TO THE S C ~ D U L E R , ARE LAUNCHED * )
BEFORE ANY PROCESSES
( * First c l e a r all s l e e p e r fields to zero * ) F O R i := 1 T O 20 DO P C B [ i ] . S l e e p e r :- 0 END;
(* Now t r a n s f e r c o n t r o l back to the b o d y of thls m o d u l e TRANSFER( Sched, T e m p ) ; (* This R E P E A T REPEAT
loop is the outer loop of the s c h e d u l e r
*)
*)
(" This F O R loop is the inner loop * ) F O R C u r r e n t p r o c e s s :- 1 TO 20 DO W I T H PCB[ C u r r e n t P r o c e s s ] DO IF S l e e p e r > 1 T H E N S l e e p e r :- S l e e p e r -i ELSIF Sleeper - 1 THEN TRANSFER(SChed,Pr) END END (* wITH * ) E N D (* F O R * ) (*
the B O O L E A N E n d F l a g U p is a v a i l a b l e to the user's p r o c e s s e s . I n i t i a l l y it is FALSE. W h e n set to TRUE it will cause the s c h e d u l e r to stop r u n n i n g p r o c e s s e s .... * )
U N T I L EndF lagUp; (*
.... a f t e r w h i c h c o n t r o l r e t u r n s to the m a i n - p r o g r a m module. In fact this T R A N S F E R r e t u r n s c o n t r o l to the p r o c e d u r e R u n P r o c e s s e s from w h i c h in turn c o n t r o l p a s s e s back to the main p r o g r a m *)
microprocessorsand microsystems