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