Concepts
The 1986 USENIX paper that introduced Mach describes four basic abstractions: tasks, threads, ports and messages. Memory management is built around them. This page covers each in a few sentences.
Tasks and threads
A task is a container for resources. It has an address space and a set of port rights, and it does not run anything by itself. A thread is the unit of execution. It runs inside a task, and a task can have many threads. This is different from a UNIX process, which combines both ideas in one object.
Ports and port rights
A port is a message queue that the kernel owns and protects. Programs never touch the queue directly. They hold port rights, which are permissions to use a port. The main rights are:
- receive, which lets the holder take messages off the queue. Only one task holds it at a time.
- send, which lets the holder put messages on the queue. Any number of tasks can hold it.
- send-once, which allows a single send and is used for replies.
A task can reach only the ports it has been given. Because of this, a port right works as a capability: what a program can do depends on what it holds, not on who it is.
Messages
Threads communicate by sending messages to ports. A message can carry plain data, port rights, and large regions of memory. Memory is sent without copying it up front: the receiver gets a copy-on-write mapping, and pages are copied only if one side writes to them.
Writing the code for sending and receiving by hand is tedious, so Mach came with MIG, the Mach Interface Generator. It reads an interface definition and produces the stubs that turn a procedure call into a message and back.
Virtual memory
Each task has its own address space, made of regions backed by memory objects. Mach allows a memory object to be managed by a user-space program called an external pager, which supplies pages when the kernel needs them. Copy-on-write is used throughout, including for the memory that tasks inherit when they are created.
Servers and personalities
In Mach 2.5 the BSD code lived inside the kernel. Mach 3.0 moved it out into user-space servers, which is what makes it a microkernel in the strict sense. A program talks to a server by sending messages, and several operating system interfaces can share one kernel. Early demonstrations ran BSD, DOS and Linux this way. Apple's XNU did not follow this path and keeps BSD inside the kernel.