AS & A Level Computer Science · Area 2 · A Level content

Purposes of an operating system and translation software

This is the A Level system software topic: what the operating system does for the hardware, how it manages processes and memory, and how a translator turns the program you wrote into something the processor can run. You have to be able to follow a process through the running, ready and blocked states, choose between scheduling routines, and explain paging, virtual memory and thrashing without confusing them with segmentation. Marks are lost by describing a compiler and an interpreter in one vague sentence, by saying virtual memory makes a computer faster, and by writing the stages of compilation without saying what each stage actually produces.

Not started

Syllabus coverage

  • How an operating system can maximise the use of resources
  • The ways in which the user interface hides the complexities of the hardware from the user
  • Process management: the concept of multi-tasking and of a process, and the process states running, ready and blocked
  • The need for scheduling and the function and benefits of different scheduling routines, including round robin, shortest job first, first come first served and shortest remaining time
  • Virtual memory, paging and segmentation for memory management
  • How the kernel of the operating system acts as an interrupt handler, and how interrupt handling is used to manage low-level scheduling
  • The concepts of paging, virtual memory and segmentation, and the difference between paging and segmentation
  • How pages can be replaced, and how disk thrashing can occur
  • How an interpreter can execute programs without producing a translated version
  • The various stages in the compilation of a program, including lexical analysis, syntax analysis, code generation and optimisation
  • How the grammar of a language can be expressed using syntax diagrams or Backus-Naur Form (BNF) notation
  • How Reverse Polish Notation (RPN) can be used to carry out the evaluation of expressions

Part of the AS & A Level Computer Science syllabus 9618.

What an operating system is for

An operating system (OS) is system software that sits between the hardware and the programs the user runs. Nothing else can touch the hardware directly: a word processor does not know which disk controller your machine has or which memory addresses are free, and it does not need to, because the OS provides the services it asks for. The OS is loaded by the boot program when the machine is switched on and stays in memory while the machine is running.

The first purpose in the syllabus is that the OS maximises the use of resources. The resources are the processor, main memory, backing store and the input/output devices, and they are all slower to share out than they look. The processor is thousands of times faster than a disk, so if the OS let one program wait for a disk read, the processor would stand idle for the whole wait. The OS avoids that by keeping several processes in memory, giving the processor to another one whenever the current one has to wait, and using interrupts to be told the instant a device has finished instead of repeatedly asking it. It also buffers and spools data, so a slow printer receives a job at its own speed from a queue while the processor carries on. Add memory management, which keeps each process in its own area, and file management, which tracks where every block of every file is stored, and the picture is complete: the OS is what turns a set of separate components into a machine that is busy nearly all of the time.

The second purpose is that the OS provides a user interface that hides the complexity of the hardware. You click an icon and a document opens; you never think about tracks, sectors, cylinder numbers, device registers, interrupt lines or memory addresses. The interface may be a graphical user interface (GUI) with windows, icons, menus and a pointer, or a command line interface where you type a command such as `copy report.txt backup`, or both. Whichever it is, the same hiding is going on: a single instruction from the user is translated by the OS into hundreds of low-level operations, and the hardware is presented as a small set of simple, familiar objects - files, folders, printers, windows - rather than as electrical components.

The hiding runs in several directions at once. Device drivers give every printer, graphics card and network adapter the same set of commands, so a program does not have to be rewritten for each make of hardware. The file system gives the user named files in named folders instead of numbered blocks scattered across a disk. Memory management gives each program a clean block of addresses starting from zero, so the programmer never handles a real physical address and two programs cannot overwrite each other. And error handling means a disk failure appears as a message box, not as a crash: the OS detects the problem, tries to recover, and reports it in terms the user can act on.

  • Resource management: the OS allocates processor time, memory, backing store and I/O devices to processes, and stops them interfering with one another.
  • Maximising use: multi-tasking keeps the processor busy while a process waits for I/O; interrupts report device completion immediately; buffering and spooling let slow peripherals work in parallel with the processor.
  • Hiding complexity: the user issues one high-level command (print, save, open) and the OS carries out the low-level device and memory operations needed to satisfy it.
  • Uniform interface to hardware: device drivers present different makes of device in the same way, so application software is not tied to particular hardware.
  • File system: named files and folders instead of physical disk addresses, with the OS keeping the mapping and the free-space list.
  • Memory protection: each process is given its own address space, so a fault in one program cannot corrupt another or the OS itself.
If a question asks how the OS maximises the use of resources, do not answer with 'it manages things efficiently'. Name the mechanism - scheduling, interrupts, buffering, spooling, virtual memory - and say which resource it keeps busy.

Processes, the process control block and the three process states

A program is a passive list of instructions stored on disk. A process is that program in execution: it has instructions being carried out, values in registers, a program counter, memory allocated to it and files or devices open. The same program can be run twice and produce two separate processes, each with its own state. Multi-tasking (multiprogramming) is the technique of holding several processes in memory and switching the processor between them so quickly that they appear to run at the same time; on a single-core processor only one instruction is genuinely being executed at any instant, and the switching is what creates the illusion.

To switch between processes the OS must be able to stop one and later resume it exactly where it left off. It does this with a process control block (PCB) for every process, a record held by the OS containing the process identifier, the process state, the program counter and saved register values, the scheduling priority, the memory allocated (page table or segment table), the files and I/O devices in use, and accounting information such as CPU time used. When a process is taken off the processor, its current register values and program counter are saved into its PCB; when it is put back, they are restored. This save-and-restore is a context switch, and it costs time, because no useful work is done by the process during it.

The syllabus names three process states, and exam questions nearly always turn on the transitions between them. Running means the process currently has the processor and its instructions are being executed. Ready means the process could run immediately if it were given the processor, but another process has it. Blocked (waiting) means the process cannot continue at all until some event happens, usually the completion of an input/output operation it has requested, or a signal from another process.

The transitions are worth learning as a diagram in your head. A process moves from ready to running when the scheduler chooses it; from running to ready when its time slice runs out or a higher-priority process becomes ready (it is pre-empted); from running to blocked when it requests a file, a keystroke or a print and must wait; from blocked to ready when the interrupt arrives saying the I/O is complete; and out of running altogether when it finishes or is terminated. Notice that a blocked process cannot become running directly - it has to go back through ready and wait its turn, because the OS cannot know how long it will take to be scheduled.

StateWhat it meansHow the process leaves this state
RunningThe process has the processor and its instructions are being executedTime slice expires -> ready; requests I/O -> blocked; finishes -> terminated
ReadyThe process could run but another process has the processor; it is in the ready queueThe scheduler dispatches it -> running
Blocked (waiting)The process cannot continue until an event occurs, typically an I/O operation completingThe event occurs and an interrupt is raised -> ready
Blocked and ready are not the same thing. A ready process is only waiting for the processor; a blocked process is waiting for something outside the processor and could not run even if you gave it the CPU.

Scheduling and the four scheduling routines

Scheduling is the OS deciding which of the ready processes gets the processor next and for how long. It is needed because there is one processor and many processes, because processes arrive at unpredictable times, and because some are far more urgent than others. A scheduler is judged on throughput (how many processes are completed per unit time), CPU utilisation (how little time the processor spends idle), turnaround time (how long a process takes from arrival to completion), waiting time and response time (how quickly an interactive user sees something happen). It must also be fair, so that no process is left in the queue indefinitely - a condition called starvation.

First come, first served (FCFS) is the simplest: processes are served in the order they arrive, like a queue at a till, and each runs to completion or until it blocks. It is easy to implement and cannot starve anyone, but it is poor for interactive use, because a single long process at the front holds everyone up. This is the convoy effect: a queue of short jobs stuck behind one long one, giving a very long average waiting time.

Shortest job first (SJF) always picks the ready process with the smallest expected total processor time. If the times are known, it gives the lowest possible average waiting time, which is why it is the benchmark against which others are measured. In practice the times are not known and have to be estimated from past behaviour, long jobs can be starved if short ones keep arriving, and it is not usable in an interactive system where you cannot know how long the user's next command will take. Shortest remaining time (SRT) is SJF made pre-emptive: whenever a new process arrives, the scheduler compares its expected time with the remaining time of the running process and switches if the newcomer is shorter. It gives even better average turnaround and responds quickly to short jobs, but it needs a running estimate of remaining time and it causes more context switches.

Round robin (RR) gives each process a fixed time slice (quantum) in turn, cycling through the ready queue; when the slice expires a timer interrupt returns control to the OS and the process goes to the back of the queue. It is pre-emptive, it is fair, no process can starve, and response time is good, which is why it is the standard choice for time-shared and interactive systems. The size of the slice is the whole design decision: too small and the processor spends a large fraction of its time on context switches; too large and round robin behaves like FCFS, with long waits for the processes at the back.

RoutineHow it choosesMain benefitMain drawback
First come, first servedIn arrival order; each process runs until it finishes or blocksSimple, no starvation, little overheadConvoy effect: one long job delays every short one behind it, so average waiting time is poor and interactive response is bad
Shortest job firstThe ready process with the smallest expected total processor timeGives the lowest average waiting time if the times are knownTimes must be estimated; long jobs can starve; unsuitable for interactive systems
Shortest remaining timePre-emptive SJF: compares the new process with the remaining time of the running one and switches if shorterBetter average turnaround than SJF and short jobs get the processor almost at onceNeeds a running estimate of remaining time and causes more context switches
Round robinEach process gets a fixed time slice in queue order, then goes to the backFair, no starvation, good response time for interactive usersSlice too small wastes time on context switching; slice too large behaves like FCFS
A pre-emptive routine can take the processor away from a running process; a non-pre-emptive one cannot. RR and SRT are pre-emptive, FCFS and plain SJF are not - that single word often carries the mark.

Paging, virtual memory and disk thrashing

Paging divides the virtual (logical) address space of a process into pages of a fixed size, typically 4 KiB, and divides physical memory into frames of exactly the same size. Any page can be loaded into any free frame, so memory does not have to be contiguous: the program is scattered around memory and a page table for each process maps each page number to the frame number where it currently sits along with a present/absent bit. Because every page is the same size, there are no awkward gaps between loaded pieces - no external fragmentation - though the last page of a program is usually only partly used, which wastes a little space inside that frame (internal fragmentation).

Virtual memory uses backing store as an extension of main memory. Only the pages a process is actually using are held in memory; the rest stay in a page file (swap file) on disk. The processor generates virtual addresses that are translated through the page table into physical addresses, so a program can be written as though it had far more memory than the machine really has, and more processes can be resident at once because each one occupies only a few of its pages.

The mechanism only works because of the page fault. When a process refers to a page whose present bit is clear, the processor traps to the OS, which finds a free frame, reads the page in from disk, updates the page table and restarts the instruction. The process is blocked while the transfer happens, because a disk read takes milliseconds while the processor works in nanoseconds. If there is no free frame, a resident page must be evicted to make room; if that page has been changed (it is dirty) it must first be written back to disk. The rule for choosing the victim is the page replacement algorithm: first in, first out (evict the oldest page, simple but can evict a heavily used page), least recently used (evict the page not used for the longest time, better because it follows the pattern of use), and optimal (evict the page that will not be needed for the longest time - the best possible, but it needs knowledge of the future, so it is only a theoretical comparison).

The benefit of all this is that programs can be larger than physical memory, more programs can run at once, and less memory is wasted. The cost is speed: a page fault means a disk access, which is thousands of times slower than a memory access. Disk thrashing is what happens when the system spends almost all of its time moving pages between memory and disk and almost none of it executing instructions. It is caused by there being too little physical memory for the number of processes running, or by running too many processes at once, so that every process is constantly faulting on pages that another process has just evicted. The symptoms are continuous disk activity, a queue of processes all in the blocked state waiting for pages, and low processor utilisation - which is the trap, because a naive OS responds to low utilisation by admitting yet another process, making the thrashing worse. The cures are to reduce the number of processes running, add more memory, use a better replacement algorithm, or give each process a working set of pages large enough that it does not keep faulting.

  • Page: a fixed-size block of a program's virtual address space. Frame: a fixed-size block of physical memory, the same size as a page.
  • Page table: one per process, mapping page number to frame number and recording whether the page is currently in memory.
  • Page fault: the trap raised when a referenced page is not in memory; the OS loads it from disk, possibly evicting another page, and the process is blocked meanwhile.
  • Replacement algorithms: FIFO, least recently used, and optimal (theoretical) decide which page to evict when memory is full.
  • Benefits of virtual memory: programs larger than RAM can run, more processes fit in memory, and physical memory is used more fully.
  • Costs: a page fault is a disk access and is far slower than memory; heavy faulting reduces performance and wears the disk.
  • Thrashing: continuous paging, so the system spends nearly all its time swapping rather than executing. Cause: too little memory for the number of processes. Symptoms: high disk activity and low CPU utilisation.
Virtual memory does not make a computer faster - it makes a bigger program possible. Every page fault costs a disk access, and if there are too many of them the machine slows to a crawl. That is the whole point of the thrashing question.

Segmentation and how it differs from paging

Segmentation divides a program into segments that are variable in length and chosen to match the logical structure of the program: one segment for the main program, one for each procedure or function, one for global data, one for the stack, one for a shared library. Each segment has a number and a length, and the segment table stores the base address of each segment in memory together with its limit, so that every address is checked against the limit and an attempt to read past the end of a segment is trapped. Because the divisions follow the program's structure, a segment can be given its own protection (read-only for code, read/write for data) and can be shared between processes - a single copy of a library segment can be mapped into several processes at once.

The cost of variable sizes is external fragmentation. As segments are loaded and removed, memory fills with gaps of various sizes, and a new segment may not fit into any one of them even when the total free space is large enough. The OS then has to compact memory - shuffle the loaded segments together to make one big free block - which costs processor time, or it must refuse the request.

The difference between the two is the classic exam comparison. In paging the divisions are fixed in size and are made by the system, invisible to the programmer; the address is a page number plus an offset, memory suffers internal fragmentation in the partly used final page, and the page table is a simple array. In segmentation the divisions are variable in size and reflect the logical parts of the program, visible to the programmer; the address is a segment number plus an offset that must be checked against the limit, memory suffers external fragmentation that may need compaction, and the segment table must store both a base and a limit for each entry. Paging exists to solve the mechanics of fitting a program into memory; segmentation exists to reflect and protect the structure of the program. Real systems often combine them: a program is divided into segments, and each segment is itself divided into pages, which gives the logical structure of segmentation with the fixed-size convenience of paging for loading.

FeaturePagingSegmentation
Size of the divisionsFixed, all the same size (pages and frames)Variable, as long as the logical part requires
Basis of the divisionMade by the system, splitting the address space by sizeMade to match the logical structure of the program (code, data, stack, procedures)
Visibility to the programmerInvisible - the programmer is unaware of itVisible - the programmer or compiler defines the segments
AddressPage number + offset, translated using the page tableSegment number + offset, checked against a limit then added to a base address
FragmentationInternal fragmentation in the last page of a program; no external fragmentationExternal fragmentation as segments are loaded and removed; may need compaction
Table entryFrame number and a present bitBase address and length (limit)
Main purposeTo load a program into non-contiguous free frames so that memory is used efficientlyTo reflect and protect the logical structure of the program, and to allow sharing of segments
The one-line version: pages are fixed-size and invisible, segments are variable-size and logical. If your answer does not contain the phrase 'fixed' for paging and 'variable' for segmentation, you are probably about to lose the mark.

Interrupts and the kernel as interrupt handler

An interrupt is a signal to the processor that an event needs immediate attention, causing it to suspend what it is doing and transfer control to a handler routine. Interrupts can come from hardware - a keystroke, a printer signalling that it has finished, a disk completing a read, the system timer ticking - or from software: a program making a system call (a trap), a divide-by-zero, or an attempt to access memory that is not there, such as a page fault. Without interrupts the processor would have to keep stopping to check every device (polling), which wastes enormous amounts of time; an interrupt lets the processor work at full speed until a device actually needs it.

The kernel is the core of the operating system: the part that stays in memory all the time, runs in privileged mode and has direct access to the hardware. It is the kernel that acts as the interrupt handler. When an interrupt arrives, the processor finishes the instruction it is executing, saves the current state - the program counter and register contents - into the PCB of the running process, and jumps to the handler whose address it finds in the interrupt vector table. The handler identifies the source, performs the small amount of work needed (for example copying the arriving data out of the device's buffer, or updating the page table after a page fault), records that the event has happened, and then the scheduler decides what runs next. The saved state is restored and the interrupted process continues, apparently unaware that anything happened.

Two refinements matter. Interrupts have priorities, so that a power failure or a disk error is dealt with before a keystroke, and a higher-priority interrupt can itself interrupt a lower-priority handler. Interrupts can also be temporarily disabled (masked) while the kernel is in a critical section, so that a data structure cannot be changed half-way through; the interrupt is not lost, only held until the section ends.

This is how interrupt handling manages low-level scheduling. The timer interrupt is the mechanism that makes pre-emptive scheduling possible: it fires at the end of each process's time slice, hands control back to the kernel, and the kernel saves the running process, moves it to the ready queue and dispatches the next one. An I/O completion interrupt is what moves a process from blocked to ready - the disk finishes reading, the handler updates the PCB, and the process is now eligible to run again. Every context switch in a multi-tasking system therefore depends on an interrupt, which is why interrupt handling is described as the low-level half of scheduling: the scheduler decides policy, the interrupt mechanism supplies the opportunities.

  • Interrupt: a signal that causes the processor to suspend the current process and run a handler.
  • Sources: hardware (timer, keyboard, disk completion, printer) and software (system call, error, page fault).
  • Sequence: finish the current instruction, save the state in the PCB, look up the handler through the interrupt vector table, run the handler, restore the state, resume.
  • The kernel is the resident, privileged core of the OS and the part that handles interrupts.
  • Priorities let urgent interrupts pre-empt less urgent ones; interrupts can be masked during critical sections.
  • Low-level scheduling: the timer interrupt ends a time slice and forces a context switch, and I/O completion interrupts return blocked processes to the ready state.
Do not write 'the OS stops the program'. The processor finishes the current instruction, saves the state, runs the handler, and later resumes the process exactly where it was - the process never knows.

Compilers and interpreters

Source code written in a high-level language has to be translated before the processor can execute it, and there are two ways of doing it. A compiler translates the whole program in one go, before it is run, and produces an object code file that is combined with libraries to make an executable. Once compiled, the program can be run any number of times without the compiler or the source code being present, and it runs at the speed of machine code. Compilation is a separate step that takes time, and the compiler reports errors only after it has examined the whole program, in a list, which is harder for a beginner because the first error may have been caused by something earlier.

An interpreter does not produce a translated version of the program. It takes the source code, translates one statement, executes it, then translates and executes the next, and so on until the program ends or an error is found. Nothing is saved, so the next run starts the translation all over again. This makes an interpreter slow to run, because translation happens every time, and the source code must be available every time. In exchange it is excellent for learning and for development: the program starts immediately without a compile step, and it stops at the first error it reaches, pointing at the exact statement, so bugs are found one at a time and fixed quickly. It is also easy to run the same source on any machine that has an interpreter.

The two are often combined. Many modern languages are translated to an intermediate bytecode which is then executed by a virtual machine: the source is compiled once into bytecode, and the bytecode is interpreted (or compiled further) at run time. Python is the standard example - the standard implementation compiles the source to bytecode and then interprets it - and Java compiles to bytecode that runs on the Java Virtual Machine. This gives some of the speed and error-checking of compilation with some of the portability of interpretation.

FeatureCompilerInterpreter
What it producesObject code / an executable file, which is keptNo translated version - each statement is translated and executed as it is reached
When translation happensOnce, before the program is runEvery time the program is run, statement by statement
Speed of the running programFast: the executable is machine codeSlow: translation is repeated on every run and adds to execution time
ErrorsReported as a list after the whole program is examined; one error can cause many messagesStops at the first error reached, with its exact position
Use of source codeNot needed at run time, so the source can be kept secretMust be present at run time, so the source is visible
PortabilityThe executable is written for one type of processor and operating system, so it must be recompiled for anotherAny machine with an interpreter for that language can run the same source
Best forProducing finished software for distributionLearning, debugging and rapid development
The single sentence that earns the mark: an interpreter executes the source directly without producing a translated object file, whereas a compiler produces an executable that runs without the compiler. Everything else in a comparison question follows from that.

The stages of compilation

A compiler does not translate in one leap. It works through a pipeline of stages, and each stage takes the output of the previous one and produces something more machine-like. The syllabus names four: lexical analysis, syntax analysis, code generation and optimisation.

Lexical analysis (tokenising) reads the source as a stream of characters and groups them into tokens: keywords, identifiers, constants, operators and punctuation. It discards whitespace and comments, since they mean nothing to the compiler, and it builds the symbol table, the list of every identifier used with its type, scope and location, which later stages keep updating and the final code generation uses to attach addresses. A character that cannot begin any token - an illegal symbol, or an unterminated string - produces an error at this stage.

Syntax analysis (parsing) checks that the sequence of tokens obeys the grammar of the language, using rules that can be written as BNF or drawn as syntax diagrams. It builds a parse tree (or abstract syntax tree) showing how the tokens combine into statements and expressions, and it reports syntax errors such as a missing bracket or a missing `then`. It is important to be clear about the difference: lexical analysis would accept `total = 4` token by token, because each token is legal; only syntax analysis can object that `` cannot follow `=`.

Code generation turns the parse tree into object code - machine code for the target processor, or an intermediate code - allocating registers and memory addresses, choosing instructions for each operation, and resolving identifiers using the symbol table. Optimisation then improves that code without changing what it does: removing code that can never be reached, removing repeated calculations that can be done once, folding constants (`2 * 3` becomes `6`), and keeping frequently used variables in registers instead of memory. Optimisation can be done on the intermediate code before machine code is produced, which is why it is often described as sitting between syntax analysis and final code generation. The result is an object file, which the linker joins with library routines to make the executable.

StageWhat it doesWhat it producesErrors it can detect
Lexical analysisGroups characters into tokens, removes whitespace and comments, builds the symbol tableA stream of tokens and a symbol tableIllegal characters, malformed numbers, unterminated strings
Syntax analysisChecks the token sequence against the grammar (BNF or syntax diagrams) and builds a parse treeA parse tree or abstract syntax treeMissing or extra tokens, unbalanced brackets, misplaced keywords
Code generationConverts the parse tree into machine or intermediate instructions, allocating registers and addressesObject codeRarely user errors; may report that a construct cannot be translated
OptimisationRewrites the code to make it smaller or faster without changing its effectMore efficient object or intermediate codeNo errors as such - it must preserve the meaning of the program
Examiners ask for the stage that detects a particular error. An illegal character or an unknown symbol is lexical; a missing bracket or a keyword in the wrong place is syntax. Learn one example of each and you can answer either way round.

BNF, syntax diagrams and Reverse Polish Notation

The grammar of a language can be written formally, and the syllabus requires two notations for it. Backus-Naur Form (BNF) is a set of rules in which a non-terminal symbol (written in angle brackets) is defined in terms of other symbols, with `::=` meaning 'is defined as' and `|` meaning 'or'. Terminals - the actual characters or keywords of the language - appear literally or in quotes. A rule can be recursive, defining a symbol partly in terms of itself, which is how repetition is expressed. For example: <digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 <integer> ::= <digit> | <digit><integer> <identifier> ::= <letter> | <identifier><letter> | <identifier><digit> Read the second line as: an integer is either a single digit, or a digit followed by an integer - which is exactly 'one or more digits'.

A syntax diagram is the graphical equivalent: terminals are drawn in circles, non-terminals in rounded rectangles, and the arrows show the paths that are allowed through the rule. A path that loops back expresses repetition, and a fork expresses a choice, so a syntax diagram and a set of BNF rules can always be converted into one another. Both are used to check whether a string is valid in the language, and both are used by the syntax analyser as the specification of the grammar it must enforce.

Reverse Polish Notation (RPN), or postfix notation, is a way of writing arithmetic in which the operator comes after its two operands: `3 4 +` instead of `3 + 4`. Because every operator knows exactly where its operands are, brackets are never needed and there is no ambiguity about precedence. RPN is evaluated with a stack: read the expression left to right, push each number as it arrives, and when an operator arrives pop the top two values, apply the operator to them (the second popped is the left operand) and push the result. At the end, the single value left on the stack is the answer.

Work through `(3 + 4) 5`, which in RPN is `3 4 + 5 `. Push 3, push 4; `+` pops 4 and 3, adds them and pushes 7; push 5; `` pops 5 and 7 and pushes 35. The answer is 35. Converting from infix needs the precedence rules: deal with the bracketed expression first, so inside the bracket `3 + 4` becomes `3 4 +`, then the multiplication needs its left operand (the result of the bracket) and its right operand `5`, giving `3 4 + 5 `. Getting the operand order right matters for subtraction and division: `8 3 -` is 8 - 3 = 5, not 3 - 8.

NotationFormHow alternatives are shownHow repetition is shown
BNFText rules of the form <symbol> ::= definitionThe vertical bar |, meaning 'or'Recursion - the symbol appears in its own definition
Syntax diagramA diagram of circles (terminals) and rounded rectangles (non-terminals) joined by arrowsA fork in the pathA loop back to an earlier point in the path
RPN (postfix)Operands first, then the operator, e.g. 3 4 +Not applicable - it is an expression notation, not a grammarNot applicable
In RPN the operator always applies to the two most recently pushed values, and the first one popped is the right-hand operand. Swap them on a subtraction and every later mark in the question is wrong.

Key terms you must be able to define

Operating system
System software that manages the hardware and software resources of a computer and provides a user interface. It allocates processor time, memory and devices to processes, hides the complexity of the hardware, and acts as an interrupt handler.
Process
A program in execution. It has its own program counter, register values, memory allocation and state, so the same program can be running as several separate processes at once.
Process control block (PCB)
The data structure the operating system keeps for each process, holding its identifier, state, program counter, saved register values, priority, memory allocation and the files and devices it is using. It is what makes it possible to stop a process and resume it later.
Process states (running, ready, blocked)
Running: the process has the processor and is executing. Ready: it could run but is waiting for the processor. Blocked: it cannot run until an event, usually an I/O operation, has completed. A blocked process must return to ready before it can run again.
Round robin scheduling
A pre-emptive scheduling routine in which each process is given a fixed time slice (quantum) in turn, then placed at the back of the ready queue. It is fair, prevents starvation and gives good response times, which suits interactive systems; the slice must be neither too short nor too long.
Virtual memory
A technique that uses backing store (a page or swap file) as an extension of main memory, so that only the pages currently in use need to be held in memory. It lets programs larger than physical memory run and allows more processes to be resident, but a page fault costs a slow disk access.
Paging
Dividing a program's address space into fixed-size pages and physical memory into frames of the same size, with a page table mapping pages to frames. Pages are invisible to the programmer, can be loaded into any free frame, and avoid external fragmentation but can cause slight internal fragmentation.
Segmentation
Dividing a program into variable-length segments that match its logical structure, such as code, data and stack, with a segment table giving the base address and limit of each. Segments are visible to the programmer and can be shared or protected, but variable sizes cause external fragmentation.
Disk thrashing
A condition in which the system spends almost all of its time transferring pages between memory and disk instead of executing instructions, because there is too little physical memory for the number of processes running. It shows as continuous disk activity, many blocked processes and low processor utilisation.
Interrupt
A signal to the processor that an event needs attention, causing it to finish the current instruction, save the state of the running process and transfer control to a handler routine. Hardware interrupts come from devices and the timer; software interrupts come from system calls and errors such as page faults.
Compiler
A translator that converts a whole program written in a high-level language into object code before it is run, producing an executable that can be run repeatedly without the compiler or source code. It reports errors as a list after examining the whole program, and the resulting program runs faster than an interpreted one.
Interpreter
A translator that translates and executes a program statement by statement at run time without producing a translated version. It stops at the first error it reaches, which makes it good for learning and debugging, but execution is slower and the source code must be present each time.
Backus-Naur Form (BNF)
A notation for expressing the grammar of a language as a set of rules in which a non-terminal in angle brackets is defined using ::= , with the vertical bar | meaning 'or' and recursion used to express repetition, e.g. <integer> ::= <digit> | <digit><integer>.
Reverse Polish Notation (RPN)
A postfix way of writing expressions in which each operator follows its two operands, so no brackets are needed. It is evaluated with a stack: push operands, and on reaching an operator pop two values, apply the operator and push the result.

Applied to real systems

9618 sets its questions inside systems you already use - a phone, a school network, a supermarket till, a website, a bank. These show how to apply the theory to a context you have not seen before, then you write your own.

Process states in a desktop operating system

You are typing in a word processor and send a document to a printer. While the processor is executing the word processor's instructions the process is running. The moment it asks the OS to send the document to the printer it has to wait for a slow device, so it becomes blocked and the OS gives the processor to another process - your browser, say, which was ready and now runs. When the printer signals completion with an interrupt, the kernel's handler moves the word processor from blocked back to ready, and it runs again when the scheduler next chooses it. This is multi-tasking on a single core: only one process is ever running, and the states explain precisely what the others are doing.

Compiling C with GCC

When a C program is compiled with GCC, the toolchain works through the stages in order: the preprocessor and lexical analysis produce a token stream and symbol table, the parser checks the tokens against the grammar of C and builds a parse tree, optimisation rewrites the intermediate code to remove redundant work, and code generation produces an object file for the target processor. That object file is then linked with the C library to make an executable. The stages are visible as separate steps, which is why C is the standard example of a compiled language: the executable runs without GCC and without the source file.

Python running under an interpreter

A Python program is run by the Python interpreter rather than turned into a stand-alone executable. The standard implementation first compiles the source to bytecode and then interprets that bytecode statement by statement, which is why a Python program starts immediately, why a syntax error is reported the moment the interpreter reaches that line, and why the interpreter has to be installed on every machine that runs the program. The source file is still needed at run time, so a Python program cannot be distributed as a single executable without extra packaging tools.

RPN in a Hewlett-Packard calculator

Hewlett-Packard's scientific and financial calculators have long used Reverse Polish Notation as their entry system: you key in the first number, press ENTER to put it on the stack, key in the second number, then press the operator, and the display shows the result. There is no equals key and no need for brackets, because the stack keeps track of the operands. Working `(8 - 3) 4` on such a calculator means 8, ENTER, 3, minus (display 5), 4, multiply (display 20) - exactly the sequence of operations used to evaluate `8 3 - 4 `.

Thrashing on an under-powered machine

A machine with 4 GB of RAM running a modern operating system, several browser tabs, a video call and an image editor will hold far more pages than it has frames. The OS keeps evicting pages that another process is about to use, so almost every memory reference faults, the disk light stays on, and the machine becomes unresponsive even though the processor is idle most of the time. That combination - heavy disk activity with low processor utilisation - is the signature of thrashing, and the cure is to close processes or add memory, not to start more work.

Flashcards

Click a card to flip it. Mark honestly — the tracker uses this.

Q1State the two purposes of an operating system named in the syllabus.
To maximise the use of resources - the processor, memory, backing store and I/O devices - through scheduling, interrupts, buffering, spooling and memory management; and to provide a user interface that hides the complexity of the hardware from the user.
Q2What is the difference between a program and a process, and what does the process control block hold?
A program is a passive set of instructions stored on disk; a process is that program in execution, with its own program counter, registers, memory and state. Its PCB holds the process identifier, state, program counter, saved registers, priority, memory allocation, open files and devices, and CPU time used, so the process can be stopped and resumed.
Q3Describe the three process states and the transitions between them.
Running: has the processor and is executing. Ready: could run but is waiting for the processor. Blocked: cannot run until an event such as I/O completes. Ready -> running when scheduled; running -> ready when the time slice ends or it is pre-empted; running -> blocked when it requests I/O; blocked -> ready when the interrupt reports completion. A blocked process never goes straight to running.
Q4How do first come first served, shortest job first, shortest remaining time and round robin choose the next process?
FCFS: arrival order, simple but causes the convoy effect. SJF: smallest expected total processor time, lowest average waiting time but needs estimates and can starve long jobs. SRT: pre-emptive SJF, compares a new process with the remaining time of the running one. RR: a fixed time slice each in queue order, pre-emptive, fair and starvation-free, with the slice size trading context-switch overhead against response time.
Q5Define paging, explain the page table and say what happens on a page fault.
Paging divides a program's address space into fixed-size pages and memory into frames of the same size, so pages can go into any free frame. The page table maps each page number to a frame and records a present bit. A page fault is a trap when a page is not in memory: the process is blocked, the OS loads the page from disk (evicting and writing back another page if needed), updates the table and restarts the instruction.
Q6How does virtual memory work, what does it cost, and what is disk thrashing?
Only the active pages are held in memory; the rest stay in a page or swap file on disk, so programs larger than physical memory can run and more processes fit. The cost is time, because every page fault is a disk access. Thrashing is continuous paging caused by too little memory for the number of processes: high disk activity, many blocked processes and low processor utilisation.
Q7Give four differences between paging and segmentation.
Pages are fixed size; segments vary in length. Pages are created by the system and invisible to the programmer; segments match the logical structure of the program and are visible. Paging causes internal fragmentation but no external fragmentation; segmentation causes external fragmentation and may need compaction. A page table entry holds a frame number and present bit; a segment table entry holds a base address and a limit.
Q8How does an interrupt work, and how does the kernel use interrupts for low-level scheduling?
The processor finishes the current instruction, saves the program counter and registers in the PCB, finds the handler through the interrupt vector table, runs it, then restores the state and resumes. The timer interrupt ends a time slice and forces a context switch, making pre-emptive scheduling possible; an I/O completion interrupt moves a blocked process back to ready.
Q9Compare a compiler and an interpreter, giving one advantage of each.
A compiler translates the whole program into object code before it runs, producing an executable that runs without the compiler or source: fast execution, and the source can be kept secret. An interpreter translates and executes statement by statement without producing a translated version: the program starts at once and stops at the first error, which makes it easier to debug and good for learning.
Q10Name the four stages of compilation and what each produces.
Lexical analysis: characters grouped into tokens, with a symbol table. Syntax analysis: tokens checked against the grammar, producing a parse tree and syntax errors. Code generation: the parse tree converted into object or intermediate code. Optimisation: code rewritten to be smaller or faster without changing what it does.
Q11Write BNF for an integer and explain how repetition is expressed.
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 and <integer> ::= <digit> | <digit><integer>. Repetition is expressed by recursion: an integer is a digit, or a digit followed by another integer. A syntax diagram shows the same thing as a loop back along the arrows.
Q12Evaluate the RPN expression 8 3 - 4 2 + * using a stack.
Push 8, push 3; the '-' gives 8 - 3 = 5, push 5; push 4, push 2; the '+' gives 6, push 6; the '*' gives 5 x 6 = 30. The answer is 30, which is (8 - 3) x (4 + 2). The first value popped is the right-hand operand, so the order matters for subtraction and division.
0 of 12 marked as known

Exam-style questions

8 questions, 27 marks. Write your answer, then reveal the mark scheme and tick each point you actually made. Answering honestly here is what makes the rest of the site useful.

StateAO11 mark
State the term used to describe a program that is in execution.

Mark scheme — tick each point you actually made

Examiner tip: One mark for one word. Do not write 'a running program' as well as 'process' - give the term the syllabus uses.
DescribeAO13 marks
Describe how the grammar of a programming language can be expressed using Backus-Naur Form (BNF), using an example in your answer.

Mark scheme — tick each point you actually made

Examiner tip: The example is not decoration - it is where the third mark usually comes from. Write a rule that is actually recursive, not just a list of alternatives.
ExplainAO23 marks
A time-shared computer system uses round robin scheduling. Explain why round robin is suitable for this system and describe the effect of making the time slice very small.

Mark scheme — tick each point you actually made

Examiner tip: Say what the routine does, why that suits interactive use, and what the slice size trades off. 'It is fair' on its own earns nothing.
DescribeAO14 marks
Describe what happens during lexical analysis and during syntax analysis in the compilation of a program.

Mark scheme — tick each point you actually made

Examiner tip: Each stage needs both what it does and what it produces. A description of lexical analysis with no mention of tokens, or of syntax analysis with no parse tree, stops at half marks.
ExplainAO23 marks
Explain how the kernel of an operating system handles an interrupt, and how interrupt handling is used to manage low-level scheduling.

Mark scheme — tick each point you actually made

Examiner tip: Do not say the OS 'stops the program'. The sequence - finish instruction, save state, run handler, schedule, restore - is what is being marked, and the timer and I/O interrupts are the two scheduling examples you need.
ExplainAO24 marks
Explain how virtual memory with paging allows a program larger than the available physical memory to be executed, and how disk thrashing can occur.

Mark scheme — tick each point you actually made

Examiner tip: The mechanism earns three of the four marks: page table, page fault, load from disk. The fourth is the consequence. Mentioning 'more memory' as the whole answer scores zero.
CalculateAO23 marks
The expression 8 3 - 4 2 + * is written in Reverse Polish Notation. Showing the contents of the stack after each step, calculate the value of the expression.

Mark scheme — tick each point you actually made

Examiner tip: Show the stack after every operation, as the question asks. Only the final answer, even when correct, cannot be given full marks because the method is not demonstrated.
EvaluateAO26 marks
A school teaches programming to beginners and also wants to distribute a finished program to parents' computers. Evaluate the use of an interpreter for the teaching and a compiler for the distribution.

Mark scheme — tick each point you actually made

Examiner tip: This is an evaluate question, so a list of differences caps you below the top band. Take each context in turn, say what the translator gives it and what it costs, then finish with an explicit judgement about which suits which purpose.

Exam technique for this topic

  • Learn the process states as a set of transitions, not three definitions. A question that says 'the process is blocked' is asking what can happen next, and the answer is 'it returns to ready when the I/O completes, then waits to be scheduled' - it never goes straight to running.
  • When a question asks you to compare scheduling routines, give each one a name, its rule for choosing, one benefit and one drawback. Naming the routine without saying how it chooses scores nothing, and 'it is efficient' is never a mark.
  • Keep paging and segmentation in separate sentences all the way through: fixed versus variable, invisible versus logical, internal versus external fragmentation, page table versus base-and-limit. If you write 'pages and segments are both blocks of memory', you have answered nothing.
  • Virtual memory questions want the mechanism, not the benefit: page table, page fault, page loaded from disk, process blocked, page replacement, dirty page written back. Then add the cost - it is slower than RAM, and too much of it is thrashing.
  • For the translation half, always say what each stage takes in and what it produces: characters to tokens, tokens to a parse tree, parse tree to object code, then optimisation. For RPN, show the stack state after each step rather than only the final answer - the working is where the marks are.

Why students lose marks here

A student wroteA student wrote: 'Virtual memory is extra RAM that the operating system adds when the computer is running slowly, so it makes the computer faster.'
Why it loses marksVirtual memory is not extra RAM and it does not make a machine faster. It is an area of backing store used as an extension of main memory, and every access to a page that is not in memory costs a disk read, which is far slower than a memory access.
The answer that scoresVirtual memory is a memory management technique in which the pages of a process that are not currently needed are held on disk in a page or swap file, while the active pages stay in main memory. A page table maps each virtual page to a frame, and when the processor refers to a page that is not present a page fault occurs: the OS finds a frame, loads the page from disk, updates the page table and restarts the instruction, blocking the process meanwhile. This allows a program larger than physical memory to run and allows more processes to be resident, but it does not add RAM and it slows execution, because a page fault is a disk access. If faults happen constantly the system thrashes.
A student wroteA student wrote: 'Paging and segmentation are the same thing, except that paging is used by the operating system and segmentation is used by the programmer. Both divide memory into blocks of the same size.'
Why it loses marksThe blocks are not the same size: pages are fixed and segments are variable. The consequences follow from that - paging can suffer internal fragmentation but never external, segmentation can suffer external fragmentation and may need compaction, and only segmentation allows protection and sharing of a logical unit.
The answer that scoresPaging divides the address space into fixed-size pages and physical memory into frames of the same size, invisible to the programmer, mapped by a page table from page number to frame number. Because all pages are the same size there is no external fragmentation, though the last page of a program wastes part of its frame. Segmentation divides the program into variable-length segments that match its logical structure, such as code, data and stack, with a segment table holding a base address and a limit for each. Segments are visible to the programmer, can be shared between processes and can be given their own protection, but their variable size leaves gaps in memory, so external fragmentation can occur and compaction may be needed.
A student wroteA student wrote: 'An interpreter is better than a compiler because interpreted programs run faster, since the computer does not have to wait for the whole program to be compiled.'
Why it loses marksThat confuses start-up time with running time. An interpreter avoids the compile step, so the program starts sooner, but it translates every statement every time it runs, so the program itself executes far more slowly than a compiled executable.
The answer that scoresAn interpreter translates and executes the source one statement at a time and produces no translated version, so there is no compile step and the program starts straight away. It also stops at the first error it reaches, pointing at the exact statement, which makes it much easier to debug - the reasons it is used for teaching and development. But translation is repeated on every run, so an interpreted program is slower than a compiled one, and the source code must be present, so it cannot be hidden. A compiler translates the whole program once into object code, producing an executable that runs at machine-code speed without the compiler or source and can be distributed commercially, at the cost of a compile step, a list of errors rather than one, and the need to recompile for a different platform.
A student wroteA student wrote: 'When a process is blocked it goes straight to the running state as soon as the printer finishes, because it is next in line.'
Why it loses marksA blocked process becomes ready, not running. The scheduler chooses which ready process runs next, and another process may be ahead of it. Skipping the ready state breaks the model the examiner is testing.
The answer that scoresA blocked process is waiting for an event outside the processor, such as an I/O operation completing. When the device finishes it raises an interrupt, the kernel's handler notes that the event has occurred, and the process is moved from blocked to ready - it is now able to run but does not have the processor. It runs only when the scheduler selects it from the ready queue and performs a context switch, restoring its program counter and register values from its process control block. So the sequence is blocked -> ready -> running, and the time spent in ready depends on the scheduling routine and on the priorities of the other processes.
A student wroteA student wrote: 'Lexical analysis checks that the program is grammatically correct, and syntax analysis produces the machine code.'
Why it loses marksThe two stages are the wrong way round and the second is simply false. Lexical analysis only groups characters into tokens; grammar is the business of syntax analysis; and machine code comes from code generation.
The answer that scoresLexical analysis reads the source as characters and groups them into tokens - keywords, identifiers, constants and operators - discarding whitespace and comments and building the symbol table. Syntax analysis takes that token stream and checks it against the grammar of the language, expressed in BNF or syntax diagrams, building a parse tree and reporting syntax errors such as a missing bracket. Code generation then converts the parse tree into object code, and optimisation improves that code before it is finally assembled and linked into an executable.
A student wroteA student wrote: 'To evaluate 8 3 - 4 * in RPN, subtract 8 from 3 and then multiply by 4, giving -20.'
Why it loses marksThe operands were taken in the wrong order. In RPN the first value popped from the stack is the right-hand operand, so `8 3 -` means 8 minus 3, not 3 minus 8. Subtraction and division are the operations where this error shows.
The answer that scoresRead the expression left to right, pushing operands and applying operators to the top two stack values. Push 8, push 3; the `-` pops 3 first and 8 second, so the calculation is 8 - 3 = 5, and 5 is pushed. Push 4; the `*` pops 4 and 5 and multiplies them, so the result is 20. Writing the stack after each step makes the order explicit and prevents the error.