Processes Control

advertisement
Processes Control
Process is a running program, so, let’s remind briefly the way of program
execution. Programs are usually prepared in the high-level programming language
(source files .c, .pas etc.), compiled into object codes (machine codes but with unresolved
references, .obj files), linked with other object and library files, resulting in executable
files (.exe, .com), which contain target processor memory image and practically without
any modifications are loaded into RAM memory, each cell of which (usually, byte) has
associated with it number – its address. To start program execution its entry point
(address of the cell, in which first command of the program is located) is loaded in
Program Counter (PC) register, which is represented in Intel Processors by register pair
CS:IP (CS – Code Segment, IP – Instruction Pointer). Each of these registers is 16-bits
wide and contains 2-byte word, so 4Gb address space is potentially available. Addresses
are 4-byte structures, having 2 parts: segment (2 senior bytes) and offset (2 junior bytes).
When address is loaded into PC, segment (offset) is loaded into CS (IP). So, addresses in
Intel processors are represented by 2 numbers, and calculation of the executable address
of the required byte (its number) is performed by the following:
Executable address = 16*Segment + Offset
in the real mode of execution of Intel processors. In the protected mode corresponding
calculations, mapping 2-part address representation into single number is performed in
more complicated manner. Such 2-part address keeping is useful for the sake of usage of
relative addressing while compiling program, when program is loaded it may be tuned
on the corresponding memory region just by setting registers and without program text
modifying.
+l
Program
Counter
l
CU
Program and
data in RAM
ALU
Central Processing Unit (CPU), having Control Unit (CU) and Arithmetic-Logic Unit
(ALU), works in rather simple manner. It repeats infinitely one and the same action:
reads byte pointed by PC, decodes it and understands what instruction is to be executed,
its structure (format), determining number of operands, their location (memory,
registers), way of addressing (direct, indirect), fetches operands into internal registers,
which are used by Arithmetic-Logic Unit as inputs together with command to be
performed on them, then gets results from internal registers and saves them according to
the format of the command being executed. This is the process of execution of only one
command, but program is represented by multiple commands which are to be executed
1
one by one. So, after termination of current command CPU again repeats described above
actions, fetching command from the location, pointed by PC. But this time it will be
address of the next command, following just previously executed, because (we have not
told it above) after decoding of the being executed command, PC is incremented by the
length of this command. So, after termination of the execution of the previous command,
PC will contain address of the 1st byte of the next command to be executed. So, linear
sequence of instructions may be realized in such a manner. But we know that usually
programs have conditional branches and loops, which don’t satisfy to such linear stream
instructions. Loops and branching are implemented by GOTO commands. This command
says that the next command to be executed is given by its operand. Such commands cause
modification of PC itself by this operand value, and next command which will be
executed, will be just command starting from address given by GOTO operand. So, we
see that notion of control yielding on the level of processor means just modification of
PC: to run any program we are simply to load its address (entry point) into PC register,
and next executed command will be desired one.
Run of the program is performed via PC, which originates stream of instructions: one
instruction after another, sequentially, which process associated with them single stream
of data. So, in the Flynn’s classification such computers working according to von
Neumann model of programming control may be classified as Single-Instruction streamSingle-Data stream. Stream of instructions usually is called as thread of control. So, in
our conventional processors we have one thread of control implemented via PC register.
Processes are running programs, having associated with them streams of
instructions, or threads of control. Switching between multiple processes (threads) may
be organized by loading into PC addresses of corresponding codes to be executed. So,
there can’t be a process without executable code, given by the program; each process is
associated with some program. But there may be many processes associated with one and
the same program (executing the same code, but being in different phases of this
execution). These entities (programs, processes) are in the one-to-many relationship (one
- from the side of program, many - from the side of processes). Thus, we can’t identify
processes by their programs. Processes are represented in Operating Systems by their
Process Control Blocks (PCB). Each process may be roughly speaking in the following
states:
 Execution (process got processor resource and is developing);
 Blocked (process execution is not possible since it waits for some external
event);
 Readiness.
Error, end
Process
selection
Execution
Waiting for I/O, signals
Time expired
Ready
Blocked
Process creation
I/O terminated, signaled
2
1. Sequential processes execution.
`
P1 P2
……Pn
1
CP
sequential
Processor
1
1
1
2
1
I/OP
2
2
Process develops
Overlapping of work time of
CP and I/OP
Process is suspended
Т1
1
Т2
2
1
1
1
2
2
1
Т1+T2
2. Non sequential cooperative execution, where idle resource is used by some waiting
process, is shown above, and total time of execution of 2 processes in this case is less
than in the case of sequential execution
3. Time slicing or round robin mode of execution.
CPU
Processes are served according to FIFO discipline (First-In-First-Out). Not served fully in
their time slice processes return again to the tail of the queue to wait for the next portion
of execution.
PCB –pointer to Process
Control Block
FQP – forward queue
pointer
3
FQP
5
0
1
8
6
2
3
4
0
2
5
6
5
7
8
9
10
Pointer to 1st element
Pointer to last element
PCB structure: process ID, state, other information about the process:
3
PSW
IP
CS
SP
SS
Registers contents
Program counter
When CPU switches from one process to another, monitor (dispatcher, scheduler) must
perform the following actions:
 Remember state of executing process in the PCB;
 Select next process for execution using Pointer to 1st element;
 Delete from the queue being transmitted to execution process by deleting
pointer to PCB of this process from the respective queue element and
setting Pointer to 1st element equal to FQP field of the deleted from the
queue process (i.e. for the case in the figure above, process No 3 is deleted
from the queue as pointed to by the Pointer to 1sr element, Pointer to 1st
element is set to 6, taken from the FQP field of the process No 3. After
such modification queue will contain 4 processes);
 If interrupted process must be in the ready for execution processes queue,
then it must be placed to the tail of this queue changing Pointer to last
element and FQP of the old last element (in our case it is Process No 5);
 Modify state of the process just selected for execution in its PCB to the
state of execution, restore machine state of this process and yield control
to it.
In the used above schema processes were identified by their positions in the queue
structure (table). They were assumed to be of the same priority.
4. Different priority processes. For RTS different processes may have different
importance, and this may be reflected by their priorities: high-priority processes are to
be processed at first, in the absence of higher-priority processes there can be executed
lower-priority processes. Let’s consider variants of such organization.
а) Processes enter queues of respective priority, after getting processor’s time quantum
they return to the tail of their queues.:
б) All new coming processes enter the same queue, and after obtaining processor’s time
quantum return to the tail of the queue of the lower priority. This will lead to
discrimination of tasks according to required execution time – tasks with shortest
processing times will be served quicker – this corresponds to maximization of throughput
4
using SPT algorithm, but here we don’t know in advance tasks execution times, they are
found out by granting processor’s time quantum.
Pointer to 1st
element
2nd priority
Pointer to last
element
BQP
9 3
2 5
10 10
0 0
FQP
0
4
0
1
9
7
2
0
0
3
7
0
1
0
5
4
0
1
2
3
4
5
9
10
6
7
8
BQP –
backward
queue
pointer
Previous schema is extended by several pairs of Pointers to 1st element and to last
element. Each of such pair determine queue of respective priority, elements of all queues
share one and the same table of processes. In figure above queue of the 1st priority
consists of processes: 9, 4, 1, 3, 0; queue of the 2nd priority is: 2, 7, 5, 0, and queue of the
3rd priority has only one 10-th process. For more effective working with processes in this
table processes are linked by bidirectional links, represented by FQP and BQP fields.
This may be useful for priority modification operations. If we should like to change
priority of process I to some value of x. We have bidirectional list, and i-th process is to
be deleted from its chain and to be appended to x-th chain’s tail. This may be done by
FQP (BQP(i))=FQP(i), BQP(FQP(i))=BQP(i)
i
5
Process’ states in more details
born
ready
passive
suspended
executes
Passive-suspended
Process transits from execution state into passive one when it issues system call
SLEEP or when waiting for I/O request. Call to SLEEP has time-out parameter. Process
transits from passive state into ready (active), or from passive-suspended state to
suspended state when time-out expires, or I/O operations terminate. Process transits from
execution state to suspended state when it suspends itself by system call SUSPEND
TASK, depth of suspension is assumed to be one in this case. Process transits from ready
(active) state into suspended state when some other process issues system call SUSPEND
TASK with our process ID as a parameter of this call; depth of suspension is also
assumed to be one. If such system call is made for process, already being in passivesuspended state, its state is not changed, but depth of suspension is incremented by 1.
Decrement of the depth of suspension is made when system call RESUME TASK is
made for process in the passive-suspended state. Suspended (passive-suspended) process
transits to ready (passive) state if depth of suspension becomes equal to 0.
Some information of interruptions and their handling
As we have seen organization of preemptive round-robin multitasking we need in
preemptions of execution of current process after expiration of time quantum. Computer
systems have special device – timer – signals of which are used for time counting in
system clocks, for working with disks, and also these signals may be used for
determining these time-outs. Idea of handling timer signals is the same as for handling
signals of other external relatively to CPU devices. This issue of interruption handling is
important not just for this task of organization of preemptive multitasking, but it is a
general way of interaction of a computer with other systems, which is especially
important for RTS, which are to interact intensively with such objects. So, let’s consider
6
notion of interruption and interruptions handling. These issues were also to be considered
in the course “Operating Systems”.
Interruptions are signals, coming from external devices in not predictable
moments of time, they may be generated any moment of the time, and our computer
system must be able to react on them adequately. These signals come to the special input
of the processor. There may be many devices of different types, and each of them may
require specific handling. Thus, each interruption signal comes together with its number,
defining type of the device, issued this signal. For example, signals from timer have
number 0x08. In Intel processors there are assumed 256 different types of interruptions
(interruption numbers), these are numbers 0,..,255. Each type of interruption signal must
be processed by respective procedure in the case of such signal arises. So, for each of 256
possible interruptions types there may be invoked specific program, and these programs
may be written not only be operating system developers, but also by other users, and
these programs may reside in different not known in advance memory regions. How
processor could know place of interruption handling procedure? Address of such
interruption handler must be kept in the predefined place of memory, namely in so called
interruptions table, occupying 1Kb starting from 0 byte. This table has so called
interruption vectors, which are really addresses of interruption handling procedures. Each
such interruption occupies 4 bytes, 2 junior bytes having offset of the interruption handler
address, and 2 senior bytes contain segment part of this address. Address of interruption
handler of interruption number N may be calculated as 4*N, so, interruption vector for
timer interruption signals is stored in bytes 32,33,34,35, where bytes 32,33 contain offset
of timer handler procedure, and bytes 34,34 have segment part of its address. So, to make
processor react on some hardware signals, it is sufficient to write into respective 4 bytes
of interruption vector address of your handler. But usually such things are not done,
because previously used interruption handler could do some useful for system job, and
we are not to make harm to our system just by replacement of the old interruption handler
by the new one. Hence, we are to make our new handling and preserve the old one. Also,
usually after termination of our program we are to clean memory after ourselves, and also
to restore previous old value of interruption vector. So, common way is to save old
interruption vector in some local area of our program, catch interruption by writing into
7
place for interruption vector address of our handler, in the handler, first operation which
is usually done is call the old interruption handler, responsible for some system job,
which may be not known to us. After returning control from the old interruption handler,
our handler makes its job. It must be noted that when interruption signal comes, after
finding address of interruption handler, but before yielding control to it, processor puts on
stack 3 words: Flags register (Processor Status Word – PSW), and registers CS, IP, this is
made to provide possibility to return control back to interrupted program (next instruction
in it to be performed is stored at program counter – register pair - CS:IP). Flags register is
used for analyzing of conditions, and is necessary for organization of branching of our
programs. So, usually, when interruption handler gets control, it saves in its internal
memory (usually, in stack) all registers, or at least used by it registers, performs
necessary job, restores all previously saved registers, and return control to interrupted
application by iret command (Interruption RETurn), which takes from stack in the
inverse order IP, CS, PSW and loads them into corresponding registers. After loading
previous values into these registers, interrupted application will continue its work, as it
was not interrupted. We are also to stress your attention, that interruption handling is
made only after full termination of the processor instruction which was fulfilled at the
moment of interruption signal coming. When we call old interruption handler from the
new one, and if it is made by usual program call, this will lead to saving in stack only
CS:IP pair, not PSW. But return from the old interruption handler will made by iret
command which will read from stack 3 words, instead of put there 2; that may lead to
corruption of stack and not valid working of the system. To avoid such situation, before
calling old interruption handler, PSW should be saved in the stack. But in compilers there
may exist special directives for declaration of procedures which are to be used as
interruption handlers, and when calling from program such procedures, 3 words are put
into stack.
We have just considered hardware interruptions, but the same interruption
handlers could be launched by special processor instruction int. This facility is widely
used in programming, for example, to control screen we use interruption 0x10, 0x13 – to
work with disks, 0x16 to work with the keyboard and so on. All considered above is valid
8
for program interruptions, but these signals are triggered not by hardware, but by our
programs.
9
Download