Microkernels were an immensely popular idea in academia (Mach, Minix, …) when Hurd was begun; I don't think the fundamental problem with them — performance is horrible — had been made obvious yet. Microkernel design is probably a good idea, but the message passing overhead kills actual microkernel implementations.
I've heard the Windows NT kernel described as being designed like a microkernel architecture (separate modules with clear APIs), but with direct function calls instead of message passing. I don't know if the Linux/BSD kernels are much different — I've poked at all three, and at a high level they look very similar.
> I don't think the fundamental problem with them — performance is horrible — had been made obvious yet.
On the contrary, the idea that performance of microkernels is "horrible" is the current received wisdom, believed by the majority of programmers without critical examination, and based on very performance-poor early microkernel designs like Mach.
The truth is that modern microkernel designs like L4 can perform IPC over 20 times faster than Mach. Another important advance for microkernels are tagged TLBs which can alleviate the TLB misses that are usually incurred on every context switch.
Someday, hopefully not too far in the future, someone is going to write a modern, practical, and free microkernel-based OS that implements all of POSIX with performance the rivals Linux, but that offers a level of isolation and modularity that Linux could never offer. When that happens, a lot of people are going to scratch their heads and wonder why they believed the people who told them that microkernels are "fundamentally" slow.
I had hoped that HelenOS would become this (http://www.helenos.org/), but its lowest-layer ipc abstraction is async-based, which I think is a mistake. One of L4's innovations was to use sync IPC, which offers the highest possible performance and gets the kernel out of the business of queueing. You can always build async ipc on top of sync without loss of performance; this puts the queues in user-space which is where they belong (they're easier to account for this way).
I asked the HelenOS people why they decided to go this way, and this is their response (one of their points was "the L4's focus on performance is not that important these days", which I disagree with). http://www.mail-archive.com/helenos-devel@lists.modry.cz/msg...
What about minix 3? It implements all of POSIX, and it's a true microkernel. The kernel process is apparently only 4-5K LOC which I have been meaning to take a look through.
Their papers have pretty detailed performance measurements. I recall that they pass fixed-length messages between processes for efficiency (to avoid buffering). And they said it takes approximately 500ns to send a message on a 2.2GHz Athlon, which is in the neighborhood of a malloc().
I don't know how the overall performance is. Minix 3 appears to be targeted at lower end devices, e.g. they mentioned OLPC. I don't think they have things that you would want for servers, like multicore support. I don't think anyone uses it for those types of applications. But it does implement POSIX and it is a microkernel. And from what I gather the codebase is relatively modern -- they said it is related to Minix 2 in name only.
Microkernels could use some hardware optimizations... And most of those optimizations are good for virtual machines too, so they'll get done.
In due time, message passing kernels will get so much faster than interruption based ones that we'll ask ourselves why we used monolitical kernels all this time. (And somebody will have to explain that microkernels used to be slow, and this person will be met with skepticism.)
That said, the computers we had at the 80's and 90's were completely unfit for microkernels. Mach was about the best you could have by then.
(But all that discussion about microkernels is an irrelevant sideline. Linux got adopted because it was there, if it weren't we'd probably use some version of BSD instead.)
Because it gets you an immense amount of existing tools that you won't have to reimplement. You can get shells, compilers, and numerous utilities (eg cp, cat, tail, tar, zip, awk). Look at the list of what BusyBox includes to get an idea of the kind of functionality any system would need to get started. http://www.busybox.net/downloads/BusyBox.html
If you provide terminal emulation then you also get editors. If you implement ptrace then you get a debugger. If you provide networking then apps can display remotely (X).
Even if you are developing something unique for your operating system, using POSIX in that lets you perform some of the development and testing on other systems that already have working toolchains.
In short having POSIX saves a huge amount of time and effort. That doesn't preclude you from having other APIs around too. Don't underestimate the importance of having a functioning system while you replace or augment it with parts that are your unique value add.
Sure, but keep in mind that my ideal would also involve discarding most what a POSIX compatibility layer would get you. Why cleanroom a nifty kernel and then turn it into something that's almost exactly like what already exists? If you want Unix, you know where to find it, as the wag said.
The kernel doesn't have to support POSIX. You can do the emulation in user space. The only tricky part of POSIX is fork, but chances are you won't need that for compilers etc, just exec.
In any event don't confuse the journey (some POSIX compatibility in order to advantage of existing toolchains while building your new OS) for the destination (clean, elegant, new API, world changing, nifty) OS.
And if you are going to have command line tools in your OS, they will need an API and you may as well pick a useful subset of POSIX.
So at some point, you can just put the whole FOSS environment (Firefox, Gnome, Gimp, LibreOffice, etc) on top of your kernel. Porting all those programs is much more work than writing a POSIX compatibility layer.
> Someday, hopefully not too far in the future, someone is going to write a modern, practical, and free microkernel-based OS that implements all of POSIX with performance the rivals Linux, but that offers a level of isolation and modularity that Linux could never offer.
Why, when we already have VMs like Xen which are modern, practical, free, host guest OSes that run at full speed to provide whatever API the applications want, and provide a level of isolation and modularity microkernels never could?
I think that's a fair question, though I disagree that microkernels are somehow inherently less modular and isolated than hypervisors.
I should say, first of all, that when I said "that implements all of POSIX" I didn't mean that POSIX should be its native or only API, but just one API that is offered for compatibility with the incredible amount of existing code that targets it. I agree with your implied argument that POSIX is by no means the be-all, end-all user-space API.
But that said, I don't think that multiple OS's running under a hypervisor is the ideal way of promoting choice and diversity of APIs. First of all, there's a lot more software involved: a hypervisor, a dom0 OS, and a guest OS, just to run anything at all. Sure it works, but there's a lot to be said for a smaller and simpler base system.
When you take the hypervisor approach, every guest OS has to implement very tedious and hardware-dependent basic functionality like booting, context-switching, paging, interrupt handling, etc. instead of being able to use an API that provides these things. This is all not to mention drivers, which is one of Linux's biggest advantages over all competitors.
I see that Xen has a paravirtualization interface that can solve some of these problems, and indeed the more that the Xen<->GuestOS interface becomes like an API/ABI and less like hardware emulation, the more Xen starts to look like a microkernel. I don't know the details of how Xen's paravirtualization interface works (and couldn't find good docs on in in a quick search) so can't comment on the specifics of it.
Maybe Xen's paravirtualization will morph into what I have in mind. One litmus test would be: do I have to statically configure the amount of RAM that each guest OS is allocated? There's no need to do this for multiple processes under a single OS, but any approach that is based on hardware emulation has to decide up front how much RAM the "hardware" has available.
One thing that's interesting is that, while microkernels haven't really won, Xen-style paravirtualization, which in a way is an even more radical version of the de-monolithization idea [1], has taken over in a lot of niches, despite performance being an even bigger problem, especially without hardware assistance.
The problem it tries to bring up is that there is a subset of processes running in the Linux Kernel as either baked in functionality or KOs that can avoid context switches and IPC calls by being baked into the same executable.
In practice, you can share memory. In practice, a code base as large as Linux actually ends up having a lot of TLB flushing whenever it alternates between the very different sections of binary that dictate behaviors of the core kernel and devices.
It doesn't help that the self fulfilling prophecy is that by fine tuning a baked in service into Linux means that a lot less effort is made trying to make it an efficient interface.
I am obviously biased, I think microkernels are a good idea. I don't know if its unix or not, but I don't like having one binary that will inject itself with extra linkables when needed that manages every device, the network stack, the sound API, manages the filesystem, manages memory, and manages processor scheduling. Most of this stuff doesn't need the kernel mode special processor registers, in practice a well designed system shouldn't require anything more than a fixed memory page reference to the device that the kernel will handle mapping (I can't think of a way to build a kernel without virtual memory, virtual files, and virtual processing baked in at the ground level, and 2/3 of those really do require special processor permissions).
You might not be biased. It's hard to ignore Wombat demonstrating context-switching costs that are up to 30 times lower than native Linux.
The status quo of kernels is reminiscent of the status quo of programming languages in the 90s. Where people programmed in faster, static languages and looked down on dynamic ones. I wonder what we will think of monolithic kernels in 50 years from now.
EDIT: A binary injecting itself with multiple code (linkables) might not be bad. It's much like what a macro does to a program. You turn one flag on and the source gets populated with the appropriate code.
It is lack of a dynamic way of injecting it that can bite you. The inability to easily change what was injected.
I've read the same issues about performances and have always wondered how the QNX micro-kernel could power embedded devices (and the next BlackBerry). http://en.wikipedia.org/wiki/QNX
QnX is extremely low overhead, and gets a much more responsive system out of the same hardware than a linux based system. Linux simply doesn't do soft-realtime well, forget about hard realtime, even with the patches applied the granularity is terrible, and prioritization is worse.
Those are the things where a microkernel shines. Because realtime systems value responsiveness (and minimal latency) over raw throughput they look worse on paper, but in use they feel a lot more responsive.
In a nutshell, having 300 MB/s throughput for some system function with latency ranging from 2 ms to 100 ms vs having 200 MB/s with latency ranging from 2 ms to 5 ms will give a very strong edge to the slower system if there is some cut-off beyond which the latency becomes unacceptable (for instance, machine or process control).
Lower performance on paper does not always mean worse performance, it depends very much on which criteria are considered to be more important. And latency can be much more important than throughput.
Mac OS X' kernel is Xnu, http://en.wikipedia.org/wiki/Xnu , which is based on the Mach microkernel but with pieces and bits from FreeBSD bolted on, for a hybrid approach.
I've heard the Windows NT kernel described as being designed like a microkernel architecture (separate modules with clear APIs), but with direct function calls instead of message passing. I don't know if the Linux/BSD kernels are much different — I've poked at all three, and at a high level they look very similar.