Microkernel: Difference between revisions

Content deleted Content added
m Fix KeyKOS
Line 18:
==Tradeoffs in microkernel design==
 
Microkernels need a highly efficient way for one process to call another, in a way similar to a subroutine call or a kernel call. The traditional performance problems with microkernels revolve around the costs of such calls. Microkernels must do extra work to copy data between servers and application programs, and the necessary interprocess communication between processes results in extra [[context switch]] operations. The components of that cost are thus copying cost and context switch cost.
Originally the kernel was fairly small, but as the capability of computers grew the number of devices the kernel had to control also grew. Many of these no longer fit into a model based on files; for instance, networking can't be effectively treated as a file. More and more code was included into the kernel to handle these sorts of tasks, and the kernels grew. Modern Unix systems are extremely large: the [[Linux]] kernel, for example, consists of six million lines of code.
 
Attempts have been made to reduce or eliminate copying costs by using the memory management unit, or [[MMU]], to transfer the ownership of memory pages between processes. [[Mach]] uses this approach. This approach adds complexity but reduces the overhead for large
Microkernels were an attempt to break out of the ever-growing kernels and return to a system in which most tasks would be completed by stringing together a series of smaller operations. The key problem under Unix had been trying to model the entire world as files, which no longer seemed to apply. Instead the microkernels took a step back and considered [[Pipeline (Unix)|pipes]] as a specific example of a much more general concept: [[inter-process communication]]s, or IPC. IPC could be used to emulate Unix-style pipes, but it could also be used for practically any other task, passing data at high speed between programs.
data transfers. It is unclear whether the additional complexity is worth the trouble. [[QNX]] manages without it, incurring some extra copying costs.
 
Systems which [[page]] programs out to disk create additional problems for interprocess communication. Unless both the source and destination areas are currently in memory, copying must be delayed, or staged through kernel-managed memory. Copying through kernel memory adds an extra copy cost and requires extra memory. Delaying copying for paging delays complicates the interprocess communication system. [[QNX]] ducks this problem entirely by not supporting paging, which is an appropriate solution for a [[real-time]] system like QNX.
 
Reducing [[context switch]] cost requires careful design of the interaction between interprocess communication and [[CPU scheduling]]. Historically, UNIX interprocess communication has been based on the UNIX [[pipe]] mechanism and the Berkeley [[socket]] mechanism used for networking. Neither of these mechanisms has the performance needed for a usable microkernel. Both are unidirectional I/O-type operations, rather than the subroutine-like call-and-return operations needed for efficient user to server interaction.
[[QNX]] has high-performance call-and-return primitives. [[Mach]] has very general primitives which tend to be used in a unidirectional manner, resulting in scheduling delays.
 
The question of where to put device drivers owes more to history than design intent. In the mainframe world, where I/O [[channels]] have memory management hardware to control device access to [[memory]], drivers need not be entirely trusted. The [[Michigan Terminal System]] (MTS), in 1967, had user-space drivers, the first operating system to be architected in that way.
 
Minicomputers and microcomputers have not, with a few exceptions, interposed a [[memory management unit]] between devices and memory. (Exceptions include the [[Apollo DOMAIN]] [[workstations]] of the early 1980s.) Since [[device drivers]] thus had the ability to overwrite any area of memory, they were clearly trusted programs, and logically part of the kernel. This led to the traditional driver-in-the-kernel style of UNIX, Linux, and Windows.
 
As peripheral manufacturers introduced new models, driver proliferation became a headache, with thousands of drivers, each able to crash the kernel, available from hundreds of sources. This unsatisfactory situation is today's mainstream technology.
 
With the advent of multiple-device network-like buses such as [[USB]] and [[FireWire]], more operating systems are separating the driver for the bus interface device and the drivers for the peripheral devices. The latter are good candidates for moving outside the kernel. So a basic feature of microkernels is becoming part of monolithic kernels.
 
==Microkernel servers==
 
With IPC the operating system could once again be built up of a number of small programs. Networking could be removed from the kernel and placed in a separate user-space program, which would be called by other programs on the system. All hardware support would be handled in this fashion, with programs for networking, file systems, graphics, etc.
Line 33 ⟶ 49:
 
The "collection of servers" model offered many advantages over traditional operating systems. By placing the majority of code in well-separated programs, development on such a system was considerably easier. Developing new networking stacks on a traditional monolithic kernel required the entire kernel to be recompiled and rebooted, hard-crashing the machine if there was a bug. With a microkernel there was little chance that an updated networking system would do anything other than inconvenience the user and require that one program to be relaunched. It also offered considerably more security and stability for the same reasons. Additionally the kernel itself was much smaller — later versions of Mach were only 44,000 lines of code.
 
==Kernel bloat==
 
Early operating system kernels were rather small, partly because computer memories were small. As the capability of computers grew, the number of devices the kernel had to control also grew. Early versions of [[UNIX]] had kernels of quite modest size, even though those kernels contained device drivers and file system managers. [[Berkeley UNIX]] begin the era of the "big kernel". When address spaces increased from 16 to 32 bits, kernel design was no longer cramped by the hardware architecture, and kernels began to grow. This growth trend continued for several decades, resulting in Unix, [[Linux]], and [[Windows]] kernels with millions of lines of privileged code.
 
To date, attempts to reverse this trend have not been highly successful. This is not a technical problem.
 
==Microkernels vs. monolithic kernels==