Types of operating system and virtual machines
Multi-tasking, multi-user, real-time, embedded and distributed systems, and a bytecode virtual machine that drives the robot.
Do this lesson in the simulatorA phone, a supercomputer, a car's airbag controller and BugBot all have operating systems, but not the same kind. At GCSE (F9.8) you met embedded systems. At A level you need to name five types of operating system, say what makes each one different, and explain virtual machines: software that pretends to be a machine.
Five types of operating system
The five types are not exclusive. A laptop's operating system is both multi-tasking and multi-user; BugBot's FreeRTOS is both embedded and real-time.
Multi-tasking. More than one process appears to run at once. The scheduler switches the processor between processes so quickly that the user sees them all running together (A10.5). Every desktop and phone operating system is multi-tasking.
Multi-user. Several users can use one computer, often at the same time from different terminals, as on a mainframe or a server. Each user has their own account, files and permissions. The operating system must share the processor fairly between users (often with round robin), and must keep each user's processes and files safe from the others.
Real-time. The operating system guarantees to respond to an input within a fixed time (a deadline). What matters is not that it is fast on average, but that it is never late. Real-time systems are designed for the worst case, with spare capacity and usually some redundancy. In a hard real-time system a missed deadline is a failure: an airbag, a pacemaker, a fly-by-wire aircraft. In a soft real-time system it only makes the result worse: a dropped frame in a video call. BugBot's motor control loop is real-time, because a correction applied late makes the robot wobble.
Embedded. The operating system runs inside a device that has one dedicated job, such as a washing machine, a router or a robot. Embedded operating systems are small, run with limited memory and processing power, often use little energy, usually have a minimal user interface or none, and are often stored in ROM or flash so they cannot easily be changed. Many are also real-time.
Distributed. One operating system runs across several separate computers, and makes them appear to the user as a single computer. The work of a task is split between the machines, which share processing and storage over a network. This gives more power than one machine could provide, and the system can survive one machine failing, but it depends on the network and is complex to program.
| Type | Defining feature | Example |
|---|---|---|
| Multi-tasking | several processes appear to run at once | Windows, Android |
| Multi-user | several users share one computer, each protected from the others | a Linux server, a mainframe |
| Real-time | guaranteed response within a deadline | an airbag controller, BugBot's motor loop |
| Embedded | inside a dedicated device, with limited resources | a washing machine, FreeRTOS on BugBot |
| Distributed | many computers act as one | a cluster rendering a film |
Virtual machines
A virtual machine is any case where software takes on the function of a machine. There are two kinds you should be able to explain.
Running one operating system inside another. A program called a hypervisor (such as VirtualBox or VMware) emulates a complete computer: processor, memory, disk and network card. A whole guest operating system is installed on this imaginary computer. Uses: testing software on several operating systems from one machine, running old programs that need an old operating system, keeping untrusted software sealed off, and, in data centres, running many virtual servers on one physical server so hardware is shared efficiently. The cost is performance: the guest runs slower than it would on real hardware, and all the guests share one machine's resources.
Running intermediate code. Some translators do not produce machine code for any real processor. They produce intermediate code, often called bytecode: simple instructions for an imaginary processor. A process virtual machine then runs the bytecode, either by interpreting it or by compiling it to machine code as it runs. Java compiles to bytecode that runs on the Java Virtual Machine. Python compiles your programs to bytecode that runs on its own virtual machine (you saw it with dis in F6.5).
The big benefit is portability: the same bytecode runs on any computer that has the virtual machine, so a program is compiled once and runs on Windows, a phone, or a robot. Only the virtual machine has to be written for each kind of hardware. The cost is again speed: bytecode running on a virtual machine is slower than native machine code.
A bytecode machine, twice
Here is a tiny stack-based bytecode. PUSH n puts a number on the stack; ADD pops two numbers and pushes their sum; FWD pops a distance and drives it; BEEP pops a frequency and plays it. The same bytecode is run by two different virtual machines: one drives the robot, and one only describes what it would do.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
bytecode = [("PUSH", 10), ("PUSH", 5), ("ADD",), ("FWD",), ("PUSH", 880), ("BEEP",), ("HALT",)]
def run(bytecode, fwd, beep):
stack = []
pc = 0
while bytecode[pc][0] != "HALT":
instruction = bytecode[pc]
if instruction[0] == "PUSH":
stack.append(instruction[1])
elif instruction[0] == "ADD":
b, a = stack.pop(), stack.pop()
stack.append(a + b)
elif instruction[0] == "FWD":
fwd(stack.pop())
elif instruction[0] == "BEEP":
beep(stack.pop())
pc = pc + 1
# machine 1: the robot
run(bytecode, lambda cm: forward(50, distance=cm), lambda hz: tone(hz, 0.3))
# machine 2: a text-only machine
run(bytecode, lambda cm: print("drive", cm, "cm"), lambda hz: print("beep at", hz, "Hz"))
The bytecode did not change. Only the machine that ran it did. That is exactly why Java programs run on so many devices.
Task: a bytecode virtual machine
Finish the virtual machine so it runs bytecode, a list of tuples whose first item is the instruction and whose second item, when there is one, is a whole number. stack is a Python list whose end is the top, and pc is the index of the next instruction. The instructions are:
| Instruction | Effect |
|---|---|
PUSH n |
push n |
DUP |
push a copy of the top value (without popping it) |
ADD, SUB, MUL |
pop b, then pop a, then push a + b, a - b or a × b |
FWD |
pop a distance in cm and drive forward that far at speed 60 |
TURN |
pop an angle in degrees and turn right that far at speed 30 |
BEEP |
pop a frequency in Hz and play it for 0.2 seconds |
JZ a |
pop a value; if it is 0, jump to instruction a |
JMP a |
jump to instruction a |
HALT |
stop |
When HALT is reached, print stack at halt: <stack>, printing the list as Python prints it. The program drives a 20 cm square with a beep at each corner, and leaves one value on the stack. Every distance must come off the stack.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
bytecode = [
("PUSH", 4), ("DUP",), ("JZ", 14), ("PUSH", 4), ("PUSH", 5), ("MUL",), ("FWD",),
("PUSH", 90), ("TURN",), ("PUSH", 660), ("BEEP",), ("PUSH", 1), ("SUB",), ("JMP", 1), ("HALT",),
]
stack = []
pc = 0
while True:
instruction = bytecode[pc]
op = instruction[0]
if op == "PUSH":
stack.append(instruction[1])
elif op == "FWD":
forward(60, distance=stack.pop())
elif op == "TURN":
turn_right(30, angle=stack.pop())
elif op == "HALT":
break
else:
raise ValueError("unknown instruction " + op)
pc = pc + 1
Challenges
- Trace the stack for the first time round the loop, instruction by instruction. What is on the stack just before
JZeach time? - Change the bytecode so the robot draws a triangle instead. Did you need to change the virtual machine?
- Write a second virtual machine for the same bytecode that only prints what it would do, like machine 2 above. Why is this useful for testing?