Linked by jokkel on Wed 4th Jan 2017 22:49 UTC
OSNews, Generic OSes

Redox OS, a microkernel OS written in Rust, hast just released version 0.0.6, which includes bug fixes and and update to Rust.

From the project's 2016 in review post:

Today, we have a pretty mature project. It contains many core, usable components. It is already usable, but it is still not mature yet to be used as a replacement for Linux (like BSD is), but we’re slowly getting there.

The kernel was rewritten, a memory allocator was added, rendering libc out of the dependency chain, several applications were added, a file system were added, a window manager and display server was implemented, and so on.

Order by: Score:
Redox
by drstorm on Wed 4th Jan 2017 22:59 UTC
drstorm
Member since:
2009-04-24

It's called Redox...

Reply Score: 2

Discussion of licenses
by Alfman on Thu 5th Jan 2017 03:00 UTC
Alfman
Member since:
2011-01-28

There's an interesting side discussion in the redox forum about the license that the OS should take on, whether to go with MIT or GPL:

https://www.reddit.com/r/rust/comments/5klu34/funding_redox_os_devel...


I personally work on many commercial projects that reject GPL libraries, for better or worse. However that resistance is usually for userspace libraries. For operating system code, I don't see much resistance since it doesn't impose limits on userspace.

oheoh says:

I don't want to donate money to help make what ends up as proprietary software in a device made by the next apple or samsung.


I kind of agree with him, it seems unfortunate that apple has not given back as much as it took from the BSDs. Of course they're under no obligation to because of the license, but it does seem fair to say the license enriched apple more than the BSD project. There could be more companies that took BSD code and never contributed back because they're not obligated to.

While I understand why many people dislike the viral nature of copyleft, it still seems evident to me that the GPL has benefited linux greatly with all kinds of companies submitting code updates back to linux. The thing I think linux made a mistake with is in failing to be "GPL2+" instead of just "GPL2", since that limitation is having negative repercussions and makes it virtually impossible to upgrade to GPL3 at any point in the future.


Hopefully I'm not stirring the hive too much with a religious licensing debate ;) But I think some people here on osnews might have some informed opinions.

Reply Score: 3

RE: Discussion of licenses
by teco.sb on Thu 5th Jan 2017 04:29 UTC in reply to "Discussion of licenses"
teco.sb Member since:
2014-05-08

But I think some people here on osnews might have some informed opinions.

I, personally, think it's a matter of opinion. I contribute to free software projects and prefer to contribute to GPL licensed software for a very simple reason: I put the work in, and these are my terms. I don't ask for money, or recognition, or any such thing, instead, I want my work to remain available to anyone that wishes to use it. However, I can totally understand why projects like libogg/libvorbis, libopus, etc choose a BSD/MIT style license. They are not writing code as a hobby, these are reference implementations.

As for what Redox should do, I think it's up to the developers. It's definitely one of those choices that will stay with you 'til the end (see your example about Linux).

Reply Score: 4

RE[2]: Discussion of licenses
by Alfman on Thu 5th Jan 2017 05:28 UTC in reply to "RE: Discussion of licenses"
Alfman Member since:
2011-01-28

teco.sb,

As for what Redox should do, I think it's up to the developers. It's definitely one of those choices that will stay with you 'til the end (see your example about Linux).



Of course... I did not make it clear that it is the lead developer himself who is actively soliciting input in the link earlier:
I have a few questions then, open to anybody:
How many people would only donate if the code were GPLv3?
How many people would only donate if the code remains MIT?
And, if willing to specify, how much would your donations be?


The questions imply that donations may play a role in deciding the operating system's license choices going forward.


Aside: I had no idea John Goodman was a fan of robust alternative operating systems!
http://www.redox-os.org/donate/
The following patrons have donated $4 or more to Jackpot51 for use in developing Redox OS:
...
John Goodman


Edited 2017-01-05 05:36 UTC

Reply Score: 2

RE: Discussion of licenses
by FlyingJester on Thu 5th Jan 2017 23:39 UTC in reply to "Discussion of licenses"
FlyingJester Member since:
2016-05-11

I'm interested in what ways Apple hasn't given much back to the BSDs.

On the one hand, they use a totally different driver setup than any BSD, and a lot of their very low-level OS stuff is more Mach than BSD.

On the other hand, they do supply all the code you need to get a working XNU kernel (which can replace the one OS X ships with) including all BSD code needed, and all of the BSD-portions of their userland. Not to mention that the ZFS port in FreeBSD is in part Apple's handiwork.

Reply Score: 2

RE[2]: Discussion of licenses
by Alfman on Fri 6th Jan 2017 02:17 UTC in reply to "RE: Discussion of licenses"
Alfman Member since:
2011-01-28

FlyingJester,

I'm interested in what ways Apple hasn't given much back to the BSDs.


It just seems that apple is always absent from corporate sponsorship that open source projects depend on. I can't find any evidence that apple has ever helped provide financial support to the open source projects they incorporate into apple products, but do let me know if I'm wrong about this.

For example:
https://www.freebsdfoundation.org/donors/#inkind
Netapp, juniper, arm, facebook, netflix, google, vmware, microsoft, sandisk, cisco, (and many more)...I skimmed through the 3 years for which they publish data, but I never see apple. Did I just miss it?


http://www.itworld.com/article/2832144/it-management/citizen-apple-...


You bring up source code contributions, but even then I wouldn't give apple high marks as a team player. They take a lot of code to fulfill their immediate needs and then totally drop the ball. In the words of rleigh:
http://www.osnews.com/thread?638853
The base system, tools and libraries are often quite outdated. Much is years old; some tools are over a decade out of date. There are bugs and missing features which were fixed and added to FreeBSD in 2007 which they still haven't picked up! All the core FreeBSD stuff should be being synched, but it isn't. They could be doing this for every release, but they aren't. The base stuff is stagnating, as is a lot of the stuff layered on top. It's becoming increasingly incompatible with the rest of the world as a result. The wilful neglect here is appalling, particularly since it would not even take a single full-time developer to keep up to date--it's not like they are even writing code, it's simply pulling it from elsewhere and integrating it. Given the company's size and resources, this is quite pathetic.


I don't really know what went down with apple and ZFS, but they allowed it to fall apart, unfortunately.

Anyways, this topic should be about redox instead of apple, so with that in mind I'm going to abruptly segway to TFS, which is a redox file system based on ZFS ;)

https://github.com/redox-os/tfs
TFS (abbrv. Ticki's File System or The File System) is a file system loosly based on ZFS, but with improved features. TFS includes support for O(1) snapshotting, caching, error correction, compression, and more.

It was originally designed for Redox OS, but will work on Linux and BSD too.

In contrary to ZFS, which TFS takes a lot inspiration from, TFS fixes certain flaws ZFS had:

TFS is not monolithic: It is based on a stack of disk drivers, each making up disjoint components. This makes it easy to maintain and implement.
TFS is disk-centric: TFS puts a lot of effort into handling as much of the raw bytes without semantic information as possible. This gives great performance and simple code.
TFS puts greater emphasis on memory caching: This can improve performance significantly.
TFS has much improved file monitoring: inotify and friends are all hacks. TFS provides a integrated solution to file monitoring.
TFS puts even more emphasis on compression: TFS has built in random-access compression.


Edited 2017-01-06 02:19 UTC

Reply Score: 2

RE[2]: Discussion of licenses
by tylerdurden on Sat 7th Jan 2017 03:25 UTC in reply to "RE: Discussion of licenses"
tylerdurden Member since:
2009-03-17


On the one hand, they use a totally different driver setup than any BSD, and a lot of their very low-level OS stuff is more Mach than BSD.


OSX (and NextStep before it) has always been severely misunderstood. It has always been a mach-like system, with BSD-elements borrowed mainly for the Unix personality part of the system, and plenty of GNU stuff laying around thrown in for good measure (although they've moved away from a lot of it in the past few years). Yet many people, especially in the FreeBSD camp from my experience, see it as a mutated FreeBSD.

Edited 2017-01-07 03:27 UTC

Reply Score: 2

RE: Discussion of licenses
by Rugxulo on Fri 6th Jan 2017 16:32 UTC in reply to "Discussion of licenses"
Rugxulo Member since:
2007-10-09

Hopefully I'm not stirring the hive too much with a religious licensing debate ;) But I think some people here on osnews might have some informed opinions.


There are still developers who intentionally close sources or restrict freedoms of permissive software derivatives. Even if it gives them zero noticeable advantage, they can't be swayed. However, a GPL project that is non-portable, hard to build, and unmaintained isn't much better off either.

If someone wants to help a project, they'll find a way, regardless of license. And similarly if someone wants to remove functionality or kill a port to an unpopular platform, nobody can stop them. The ideal that GPL somehow makes us better, more cooperative people isn't justified.

Software licensing should be pragmatic and generous, hands off, trying to solve a concrete problem, not an excuse to annoy others.

So, long story short, I'm disinterested in licensing because it shouldn't matter (although I prefer free). If there's no obvious advantage to doing so, there's no reason to be restrictive. I'm not a lawyer, and I'm not interested in arguing. I want to solve actual problems, help actual people, not have a legal standoff.

Maybe I expressed myself badly, but my point is that licensing is usually the least of our worries. It's an uphill battle no matter what you choose.

Reply Score: 1

RE: Discussion of licenses
by Drumhellar on Fri 6th Jan 2017 18:24 UTC in reply to "Discussion of licenses"
Drumhellar Member since:
2005-07-12

I kind of agree with him, it seems unfortunate that apple has not given back as much as it took from the BSDs.


What do you mean? All the BSD components that Apple used ended up in their open source projects, including the XNU kernel, which is still open. While it has been a while since they used a merged a recent version of the FreeBSD kernel in with XNU, the two have diverged enough that any changes Apple makes wouldn't necessarily be easy to port back to FreeBSD anyways.

There are a number of other pieces of software they created that are opensource under permissive licenses, too. LLVM/Clang is one (Not technically created by Apple, but they've been footing the bill for the creator and a whole team to work on it full time since 2005), mDNS, GCD, and others. A lot of OSX-specific tech is open source, too, such as launchd.

Edited 2017-01-06 18:28 UTC

Reply Score: 2

Microkernels
by teco.sb on Thu 5th Jan 2017 04:38 UTC
teco.sb
Member since:
2014-05-08

Writing kernels is WAY beyond my level of knowledge, however, I think microkernels are a much better choice than the monolithic/modular kernels we have to deal with today. I just don't understand why this design won out over something simpler and more manageable, like a microkernel. I sure hope this project moves forward.

I'm still hoping we will, one day, see a seL4-based general purpose OS.

Reply Score: 2

RE: Microkernels
by Brendan on Thu 5th Jan 2017 09:51 UTC in reply to "Microkernels"
Brendan Member since:
2005-11-16

Hi,

Writing kernels is WAY beyond my level of knowledge, however, I think microkernels are a much better choice than the monolithic/modular kernels we have to deal with today.


A micro-kernel isn't simpler, it's more complex. Roughly, it's similar code doing similar things, but with the additional complexity of isolation between pieces and communication between isolated pieces.

The benefits of micro-kernels all come from that isolation - better security, better debugging, easier to implement fault tolerance, etc.

Note that this tends to also influence the OS developer's stance on proprietary drivers (untrusted proprietary drivers running in user-space is far less concerning than untrusted proprietary drivers running in kernel-space); and the OS developer's stance on proprietary drivers influences (some) hardware manufacturer's and (some) software developer's willingness to support the OS.

I just don't understand why this design won out over something simpler and more manageable, like a microkernel. I sure hope this project moves forward.


The reason for this is that most micro-kernel developers are incredibly stupid and make decisions that guarantee failure before they even write a single line of code.

To understand this; first you have to understand (what I'll call) "The OS Developer's Dilemma".

An OS without applications is useless. If you port applications from some other OS then it's virtually impossible to show that your OS is better in any meaningful way - it ends up being the same applications with all the same (user-visible) features as a more mature OS (that is faster and more stable and has better hardware support because it is more mature). If you don't port applications from some other OS then you have to write a huge number of applications and that's going to take multiple decades. This is the "The OS Developer's Dilemma" - you have to choose between being screwed and being screwed, and it's extremely difficult to avoid the consequences regardless of your choice.

For micro-kernels this becomes worse. The isolation between pieces causes additional communication overhead. If you port software from some other OS, then that software (and the APIs and libraries, etc it uses) will not have been designed to mitigate the communication overhead. What you'll be left with is poor performance, plus a trivial way for people to do "apples vs. apples" benchmarks (e.g. same application on 2 different OSs) that "prove" that the micro-kernel sucks because performance is worse; combined with no sane way to show any advantages, partly because the advantages can't be benchmarked and compared easily (how can you benchmark security?), and partly because ported software won't take advantage of any of the OS's advantages itself.

Essentially; for micro-kernels "The OS Developer's Dilemma" becomes a choice between being extremely screwed and being screwed. That is where most micro-kernels fail - they choose to avoid being screwed (the need to write a lot of applications, etc) and instead choose to be extremely screwed (and port applications and support APIs designed for *nix that are inappropriate for a micro-kernel); and the end result is that they are doomed before they start.

- Brendan

Reply Score: 8

RE[2]: Microkernels
by Kebabbert on Thu 5th Jan 2017 11:23 UTC in reply to "RE: Microkernels"
Kebabbert Member since:
2007-07-27

A micro-kernel isn't simpler, it's more complex. Roughly, it's similar code doing similar things, but with the additional complexity of isolation between pieces and communication between isolated pieces.

This was the weirdest thing Ive read today.

A micro-kernel has much fewer lines of code, so you can reason about it mathematically. You can not do that with a large kernel. That is the point of L4 kernel, you can not prove things unless it is a micro-kernel - because you want to reduce the complexity. So you are wrong. A micro-kernel is simpler, because it has fewer lines of code. The more code, the more complex.

Reply Score: 2

RE[3]: Microkernels
by Brendan on Thu 5th Jan 2017 12:47 UTC in reply to "RE[2]: Microkernels"
Brendan Member since:
2005-11-16

Hi,

"A micro-kernel isn't simpler, it's more complex. Roughly, it's similar code doing similar things, but with the additional complexity of isolation between pieces and communication between isolated pieces.

This was the weirdest thing Ive read today.

A micro-kernel has much fewer lines of code, so you can reason about it mathematically. You can not do that with a large kernel. That is the point of L4 kernel, you can not prove things unless it is a micro-kernel - because you want to reduce the complexity. So you are wrong. A micro-kernel is simpler, because it has fewer lines of code. The more code, the more complex.
"

A micro-kernel on it's own is far less code than a monolithic kernel; but a micro-kernel on it's own it's also completely useless.

A micro-kernel plus all the drivers, file systems, services, etc that are necessary to make it actually useful adds up to more code (and more complexity) than a monolithic kernel with equivalent functionality.

- Brendan

Reply Score: 6

RE[4]: Microkernels
by Alfman on Thu 5th Jan 2017 15:44 UTC in reply to "RE[3]: Microkernels"
Alfman Member since:
2011-01-28

Brendan,

This is a very interesting discussion; I like the way you lay out "The OS Developer's Dilemma". I definitely agree: a new general purpose OS isn't going to be terribly useful if it doesn't support existing software APIs, but once it does those APIs will get used almost exclusively and all the other native features that make the OS unique will go largely unused regardless of merit.


Can I just ask why you assert that a microkernel involves more code/complexity? I'm not claiming it's right/wrong, I'm just having trouble seeing why it would be intrinsically true. Obviously microkernel calls will have to traverse the kernel barrier, but it doesn't seem self-evident to me that this in and of itself increases the programmer's code/complexity compared to macrokernel calls that don't traverse the barrier.

Clearly, for performance reasons, a micro-kernel favors message passing compared to numerous function calls, which has an impact on complexity, but that's not necessarily exclusive to the kernel type and conceivably one could develop kernel module APIs that work under both macro and micro-kernel with nothing more than a recompile, in which case they'd be equal complexity. So in this way complexity isn't dictated so much by macro/micro kernel but rather the design of the API.



What do you consider kernels where the isolation is enforced by managed programming language semantics rather than CPU memory barriers (such as singularity or JX)? Is that a micro-kernel, macro-kernel, or something completely different? It's an interesting question because it has all the isolation properties of a micro-kernel yet runs in a single address space with no CPU transitions.

Edited 2017-01-05 15:53 UTC

Reply Score: 2

RE[5]: Microkernels
by Brendan on Fri 6th Jan 2017 06:46 UTC in reply to "RE[4]: Microkernels"
Brendan Member since:
2005-11-16

Hi,

Can I just ask why you assert that a microkernel involves more code/complexity? I'm not claiming it's right/wrong, I'm just having trouble seeing why it would be intrinsically true. Obviously microkernel calls will have to traverse the kernel barrier, but it doesn't seem self-evident to me that this in and of itself increases the programmer's code/complexity compared to macrokernel calls that don't traverse the barrier.


The first part is the actual mechanics of communication. For this, you can compare it to calling "foo()" where "foo()" is in a dynamically linked library and tools (e.g. the code that does the dynamic linking) ensures that the data types, etc match; and sending "FOO" using (e.g.) sockets where the receiver has to figure out what the request is and if it's well-formed before it can call its internal "foo()" function (and similar in the opposite direction for the reply). Typically you end up with some kind of "switch(message->type) { ...." at every place that receives messages.

The second part is security (e.g. what prevents a malicious user-space program from pretending it's the kernel and sending a message to a driver?). There's multiple different approaches to this, but they all add some complexity.

The third part is tricks to mitigate the overhead. This includes things like bundling multiple requests into the same message (to amortise the "per message" cost), asynchronicity (to decouple task switching from send/receive), etc.

Then there's boot code. When there's no drivers in the kernel (to load drivers from disk or network) you have to figure out an alternative (some sort of "initial RAM disk") and your boot code has to provide that. When there's no video support built into the kernel (to display error messages that occur during kernel initialisation) you need to figure out an alternative (boot code displays error messages before and after kernel is started, and then some sort of "hand off" when a video driver takes over later during boot). For a monolithic kernel you can mostly just slap whatever you need into the kernel as you go and don't need to do much planning. For micro-kernel, you have to plan your boot code carefully because kernel can't/shouldn't do much itself.

What do you consider kernels where the isolation is enforced by managed programming language semantics rather than CPU memory barriers (such as singularity or JX)? Is that a micro-kernel, macro-kernel, or something completely different? It's an interesting question because it has all the isolation properties of a micro-kernel yet runs in a single address space with no CPU transitions.


As far as I'm concerned, for most OSs there's some sort of isolation between "user-space things" and "kernel", and that could be hardware isolation (e.g. CPU's MMU) or software isolation (e.g. managed language) or some mixture of both. The difference between monolithic and micro-kernel is which pieces are isolated (e.g. if drivers are isolated from kernel or not) and has nothing to do with how they're isolated (MMU, managed language, ...).

- Brendan

Reply Score: 2

RE[6]: Microkernels
by teco.sb on Fri 6th Jan 2017 15:44 UTC in reply to "RE[5]: Microkernels"
teco.sb Member since:
2014-05-08

The first part is the actual mechanics of communication. For this, you can compare it to calling "foo()" where "foo()" is in a dynamically linked library and tools (e.g. the code that does the dynamic linking) ensures that the data types, etc match; and sending "FOO" using (e.g.) sockets where the receiver has to figure out what the request is and if it's well-formed before it can call its internal "foo()" function (and similar in the opposite direction for the reply). Typically you end up with some kind of "switch(message->type) { ...." at every place that receives messages.

The second part is security (e.g. what prevents a malicious user-space program from pretending it's the kernel and sending a message to a driver?). There's multiple different approaches to this, but they all add some complexity.

The third part is tricks to mitigate the overhead. This includes things like bundling multiple requests into the same message (to amortise the "per message" cost), asynchronicity (to decouple task switching from send/receive), etc.

Then there's boot code. When there's no drivers in the kernel (to load drivers from disk or network) you have to figure out an alternative (some sort of "initial RAM disk") and your boot code has to provide that. When there's no video support built into the kernel (to display error messages that occur during kernel initialisation) you need to figure out an alternative (boot code displays error messages before and after kernel is started, and then some sort of "hand off" when a video driver takes over later during boot). For a monolithic kernel you can mostly just slap whatever you need into the kernel as you go and don't need to do much planning. For micro-kernel, you have to plan your boot code carefully because kernel can't/shouldn't do much itself.

To follow up on Alfman's question and your responses, how is any of what you described different from the current crop of modular kernels? True monolithic kernels no longer exist, all the large projects have moved onto a modular design, where the kernel loads code at runtime.

The second problem you describe also exists when loading a modular kernel loads a module. Except that now, that code will be running in kernel-space, as opposed to user-space. How is the micro-kernel approach more complex than the modular-kernel approach?

The boot problem you describe also exists on modular-kernels. As a matter of fact, the Linux kernel has shipped with initramfs support for years exactly so they can work around this problem.

As for the other 2 problems you mention, I think you have valid points. However, I would argue these problems you are describe do not add complexity to the individual pieces.

Since micro-kernels are separated into smaller pieces and each one of those pieces are independently simpler. As an example, take a look at the DragonflyBSD kernel and what they've done in order to better support SMP (https://www.dragonflybsd.org/docs/developer/Locking_and_Synchronizat...). How is all that mess less complex? As another example, the Linux kernel, until recently, had that big kernel lock (https://kernelnewbies.org/BigKernelLock).

I just don't think the issues you listed are any better in modular-kernels. Maybe different, but not better.

Reply Score: 2

RE[7]: Microkernels
by acobar on Fri 6th Jan 2017 19:44 UTC in reply to "RE[6]: Microkernels"
acobar Member since:
2005-11-15

What about context switch? From what I heard, it used to be the main thing hurting micro-kernels performance because of the high cost of message passing between kernel mode and things done on user mode. I know that a modern CPU does lots of tricks to mitigate the cost of context switch but most optimizations are done for things not crossing the address space in use, which is, unfortunately, constantly swapped on micro-kernels.

Edited 2017-01-06 19:55 UTC

Reply Score: 2

RE[7]: Microkernels
by Brendan on Fri 6th Jan 2017 21:47 UTC in reply to "RE[6]: Microkernels"
Brendan Member since:
2005-11-16

Hi,

To follow up on Alfman's question and your responses, how is any of what you described different from the current crop of modular kernels? True monolithic kernels no longer exist, all the large projects have moved onto a modular design, where the kernel loads code at runtime.


Modular kernels use dynamic linking, which is essentially a normal function call except that it's been patched when the module was loaded. You can't call a function that doesn't exist (you'd get linking errors). You don't need extra "switch(message->type)" code to determine which function you're calling. I explained this already.

The second problem you describe also exists when loading a modular kernel loads a module. Except that now, that code will be running in kernel-space, as opposed to user-space. How is the micro-kernel approach more complex than the modular-kernel approach?


No. Imagine you've got your bank account details stored in a file on a file system. Somewhere inside the monolithic kernel there's some file system code containing a function that can read that file. User-space can not call this function directly. It can only call kernel's API (which calls the VFS layer, which does permission checks, and then might call the file system code's function after the checks are done). The file system code knows that it can only be called by kernel and can't be called by user-space, so it needs no additional security checking.

Now imagine it's a micro-kernel and the file system code (and the VFS) are just normal processes. The file system code receives a "read file request" message. Did this request come from the VFS (after VFS did file permission checks), or did it come from a malicious application that's trying to bypass the VFS (and bypass the file permission checks)?

There are 2 basic ways to handle this sort of security problem. Either the receiving process is responsible for it and has to do its own additional security checks (e.g. was the message sent by someone I trust?), or you have additional stuff in the kernel to control who can/can't send which messages to what. That is the extra security stuff you need for micro-kernel that doesn't exist in monolithic.

The boot problem you describe also exists on modular-kernels. As a matter of fact, the Linux kernel has shipped with initramfs support for years exactly so they can work around this problem.


No. For monolithic you can literally just slap crap anywhere you like whenever you like without thinking much about it (and that includes adding support for "initramfs" as an afterthought 10 years after you started writing the kernel). You don't have to (e.g.) plan for and support "initramfs" from day 1.

As for the other 2 problems you mention, I think you have valid points. However, I would argue these problems you are describe do not add complexity to the individual pieces.


I think that's where you're going wrong. You're looking at the complexity of one little piece and comparing it to the complexity of a whole system; and you're not comparing the complexity of "all pieces plus the communication necessary to form a whole system" to a whole system.

Since micro-kernels are separated into smaller pieces and each one of those pieces are independently simpler. As an example, take a look at the DragonflyBSD kernel and what they've done in order to better support SMP (https://www.dragonflybsd.org/docs/developer/Locking_and_Synchronizat...). How is all that mess less complex? As another example, the Linux kernel, until recently, had that big kernel lock (https://kernelnewbies.org/BigKernelLock).


How about if I chop your arms and legs off, then isolate them by mailing each one to a different country, then build an international system of pumps and control logic to keep them working while they're separated from your body, and then tell you it's simpler like this (because if I ignore everything except one leg, that leg seems simpler than an entire "monolithic human")?

For Linux SMP and locking, they added it to every piece - the memory management, the scheduler, the VFS, the file systems, the entire network stack, and about 500+ drivers. You're comparing this work to adding SMP and locking to a micro-kernel alone (and not the VFS, and not file systems, and not the entire network stack, and not 500+ drivers); and then saying "only doing tiny fraction of the work is easier".

- Brendan

Edited 2017-01-06 21:52 UTC

Reply Score: 2

RE[6]: Microkernels
by Alfman on Fri 6th Jan 2017 23:28 UTC in reply to "RE[5]: Microkernels"
Alfman Member since:
2011-01-28

Brendan,

I'm trilled we have a technical discussion going, you have no idea ;)

The first part is the actual mechanics of communication. ... Typically you end up with some kind of "switch(message->type) { ...." at every place that receives messages.


It's a good observation, I guess this depends on the exact implementation of the syscalls. Linux obviously uses a case switch for userspace, but if you use a task-gate, you don't need to do that at all. On the other hand, task-gates are not the most efficient mechanisms for a microkernel to use.

I think we need to distinguish between inherent complexity versus complexity deriving from performance optimization. So, for the purposes of this discussion is it fair to narrow your assertion down to "optimized microkernels" being more complex?

I'm currently pondering whether a function lookup table is actually more complex or merely different, however I'll err in your favor and say it is more complex. Never the less, with proper support from macros and the language, I think it should be possible to hide the fact that a switch mechanism is being used at all, and just like most programmers don't really care about assembly language under the hood, they wouldn't need to care that the calls are being 'switched' rather than 'called'.

I'm pretty sure you will respond by saying that this is merely moving the complexity into the language/tooling, which is true. However this is a one time cost and the complexity can be hidden from future kernel developers, much like the macros used in linux kernel modules to hide complexity.


The second part is security (e.g. what prevents a malicious user-space program from pretending it's the kernel and sending a message to a driver?). There's multiple different approaches to this, but they all add some complexity.


Yes, it needs to be solved, but I don't think it has to be more complex than the macrokernel case where insmod needs to be protected. For example "if (uid!=0) die('no soup for you...');" The implementation of this check might have to happen at different points, but IMHO it's not really more complex.


If you want finer grained security controls, obviously you can do that with a microkernel and that will definitely add complexity, however this is above and beyond what a macro kernel can do so it would no longer be an apples to apples comparison. In other words, this additional complexity is only needed to get additional security.



The third part is tricks to mitigate the overhead. This includes things like bundling multiple requests into the same message (to amortise the "per message" cost), asynchronicity (to decouple task switching from send/receive), etc.


Yes absolutely, synchronous calls are definitely the weak point for microkernel performance. Batched asynchronous calls can eliminate all the microkernel overhead (and maybe even perform better than in-kernel synchronous calls), however there's no denying that asynchronous programming is very different. I wouldn't say it's more complex than multi-threaded programming, however as a substitute for synchronous calls it is undeniably more complex.

Vector operations can be done efficiently in a microkernel, but using them tends to makes everything more complex.
https://linux.die.net/man/3/readv

I would like to see research in this area, such that simple code could automatically be converted into vectored code. We have this to an extent with SSE compiler optimization, but I wonder if the same thing might be done with higher level operating system constructs. Obviously we're not there today.

Then there's boot code. When there's no drivers in the kernel (to load drivers from disk or network) you have to figure out an alternative (some sort of "initial RAM disk") and your boot code has to provide that. When there's no video support built into the kernel (to display error messages that occur during kernel initialisation) you need to figure out an alternative (boot code displays error messages before and after kernel is started, and then some sort of "hand off" when a video driver takes over later during boot). For a monolithic kernel you can mostly just slap whatever you need into the kernel as you go and don't need to do much planning. For micro-kernel, you have to plan your boot code carefully because kernel can't/shouldn't do much itself.


I'll defer to teco.sb's response, since I agree with him that it's practically the same as the modular macrokernel case.



The difference between monolithic and micro-kernel is which pieces are isolated (e.g. if drivers are isolated from kernel or not) and has nothing to do with how they're isolated (MMU, managed language, ...).


The interesting thing is that with managed language solution, there's no overhead for the isolation. It's a free bi-product of how managed languages work.

Edited 2017-01-06 23:47 UTC

Reply Score: 2

RE[7]: Microkernels
by Brendan on Sat 7th Jan 2017 11:21 UTC in reply to "RE[6]: Microkernels"
Brendan Member since:
2005-11-16

Hi,

I'm trilled we have a technical discussion going, you have no idea ;)


:)

It's a good observation, I guess this depends on the exact implementation of the syscalls. Linux obviously uses a case switch for userspace, but if you use a task-gate, you don't need to do that at all. On the other hand, task-gates are not the most efficient mechanisms for a microkernel to use.


The communication is in addition to the syscall stuff (and not instead of the syscall stuff). For example, your kernel API might have a "sendMessage()" function and a "switch(function_number) { case API_SENDMESSAGE: " to determine which syscall it is; and then the receiver of the message may have an additional "switch(message->type) { ...." to figure out what the message it received is actually for.

Of course (hopefully) the kernel's "switch(function_number)" ends up being a jump table - e.g. determine if the function number is within a valid range, then "jmp [table+rax*8]".

Note that I think you meant "call gates" rather than "task gates" (although both are technically possible). ;)

I think we need to distinguish between inherent complexity versus complexity deriving from performance optimization. So, for the purposes of this discussion is it fair to narrow your assertion down to "optimized microkernels" being more complex?


No. For equivalent kernels (same amount of optimisation, same features, etc); a monolithic kernel is simpler than "micro-kernel plus all the stuff monolithic kernel has that micro-kernel doesn't". In other words an OS that uses monolithic kernel is simpler than an OS that uses a micro-kernel.

People make the mistake of thinking that an OS that uses a micro-kernel is simpler because the micro-kernel all by itself is simpler; but that is an extremely broken and meaningless comparison. It would be more fair to compare "monolithic without any of the hundreds of device drivers, file system code, VFS, etc" to "micro-kernel".

I'm currently pondering whether a function lookup table is actually more complex or merely different, however I'll err in your favor and say it is more complex. Never the less, with proper support from macros and the language, I think it should be possible to hide the fact that a switch mechanism is being used at all, and just like most programmers don't really care about assembly language under the hood, they wouldn't need to care that the calls are being 'switched' rather than 'called'.


For the "switch(message->type)" in every message receiver (and not for the "switch(function_number)" used for the kernel API that I think you were talking about here); with sufficiently complex tools and/or libraries you can bury it under callbacks; where you register your callback with some kind of "generic dispatcher", and where that "generic dispatcher" gets the message for you and figures out which function to call for you. With even more complex tools/programming languages it's possible to bury that "generic dispatcher" system under syntactical sugar (e.g. "futures").

Yes, it needs to be solved, but I don't think it has to be more complex than the macrokernel case where insmod needs to be protected. For example "if (uid!=0) die('no soup for you...');" The implementation of this check might have to happen at different points, but IMHO it's not really more complex.


Typically the message passing is used for everything (and not just for drivers, etc). For example, maybe you write a game client and a game server and they communicate with messaging. Maybe the game is multiplayer; and one player presses a key causing a message to be sent from keyboard driver to a GUI, causing a message to be sent to game client, causing message to be sent to game server, causing message to be sent to other player's game client, causing message to be sent to other player's GUI, causing message to be sent to video driver.

The "if (uid!=0) die('no soup for you...');" can't work.

For my systems the message receiver is responsible for doing security checks and the kernel guarantees that each message has an unforgeable "message sender ID". The end result is that (e.g.) maybe your game server receives a message requesting that an entity explodes, and the game server has a "switch(message->type) {" to determine what the message is for, and then the game server checks to see if the message came from one of the game clients that are playing the game, and if it came from something else (e.g. a player is trying to cheat) it ignores the message.

Of course other micro-kernels do it differently. Some try to do the checking in the kernel (e.g. using capability systems, etc). This tends to end up being inflexible (e.g. "all or nothing" systems where you can't tell kernel "process 123 can send FOO but can't send BAR") or very complex. It also tends to pushes the complexity into the kernel (which, in my opinion, is supposed to be "micro" and therefore not supposed to deal with complexity that could've been in user-space).

I'll defer to teco.sb's response, since I agree with him that it's practically the same as the modular macrokernel case.


For a practical comparison; typically beginners writing monolithic kernels have some kind of "kprintf()" (that ends up writing directly to a video card's framebuffer) working within their first 2 weeks. For mine, micro-kernel shouldn't have code to touch video. Instead it maintains a "boot log" (which is mostly just a big zero terminated string) where you append to the end of the string, then notify something else (outside the kernel, in boot code) that the boot log changed, and that something else updates the video. This causes concurrency issues later in boot - e.g. one driver adds "Hello " and then adds " world!\n", but in between a different driver on a different CPU adds "BORK\n", so you end up with "Hello BORK\n world!\n". To fix that I have buffering, where a driver adds pieces to its buffer (e.g. "Hello " and then "world!\n") and then asks kernel to do "atomically add contents of buffer to boot log", and then kernel notifies something else (boot code) that the boot log changed, and then something else updates the video. This also causes problems when I start a video driver, because now I've got boot code and video driver both fighting for the frame-buffer. To fix that I end up with a kind of "hand-off sequence" where video driver tells kernel to tell boot code to stop updating the screen itself (and where boot code starts sending video updates to video driver so that video driver can update the frame buffer on its behalf).

The interesting thing is that with managed language solution, there's no overhead for the isolation. It's a free bi-product of how managed languages work.


That's a myth.

What you actually end up with is "overhead of hardware checks" (e.g. TLB misses) vs. "overhead of managed language checks plus the overhead of hardware checks" (e.g. checks that couldn't be omitted by compiler, plus TLB misses caused by long mode requiring paging and the total working set not fitting in caches/TLBs and causing "least recently used TLB eviction").

The other thing you end up with is an extremely complicated optimising compiler (more complicated than a normal compiler that doesn't have the additional responsibility) that must be perfect to guarantee the system is secure but also must be expected to have several thousand bugs (e.g. 1 bug per 1000 lines of code for several million of lines of compiler code).

The other thing you end up with is hardware issues (temporary glitches, CPU errata, things like rowhammer attacks, etc) where even if your compiler is "impossibly perfect" you still have no guarantee of security because there's nothing to shield you from "modified after proven secure".

Mostly (at least in my opinion), "managed" is a researcher's fantasy (that just makes things worse practice). ;)

- Brendan

Reply Score: 2

RE[4]: Microkernels
by Kebabbert on Mon 9th Jan 2017 15:25 UTC in reply to "RE[3]: Microkernels"
Kebabbert Member since:
2007-07-27

A micro-kernel on it's own is far less code than a monolithic kernel; but a micro-kernel on it's own it's also completely useless.

A micro-kernel plus all the drivers, file systems, services, etc that are necessary to make it actually useful adds up to more code (and more complexity) than a monolithic kernel with equivalent functionality.

- Brendan

First you said that a micro-kernel is more complex than a monolithic kernel, which is not really true. But what you actually meant, was the micro-kernel plus all it's subsystems are more complex than the monolithic dito?

Well, that is another discussion that I dont really know too much about. But OTOH, if you have a micro-kernel, you separate cleanly the kernel from the subsystems. That should mean that you can examine each system locally, without having to consider other subsystems. In other words, you reduce complexity. You look at one simple system at a time, instead of one large system where many subsystems interact.

For instance, you could mathematically reason about one subsystem at a time, because they are encapsulated. This is not possible with a monolithic kernel where there might be side effects in other subsystems.

So I really doubt that a micro-kernel with all it's subsystems is more complex than a monolithic dito. To me this is a weird statement. If you have independent encapsulated subsystems, then you reduce complexity because of divide-and-conquer. You need to provide some links or a better explanation why independent separated sub systems are more complex than a monolithic dito.


UPDATE: Now I see what you mean:
"...I think that's where you're going wrong. You're looking at the complexity of one little piece and comparing it to the complexity of a whole system; and you're not comparing the complexity of "all pieces plus the communication necessary to form a whole system" to a whole system...."

And this could be true. I see your point now. Ok.

Edited 2017-01-09 15:37 UTC

Reply Score: 2

RE[5]: Microkernels
by Alfman on Mon 9th Jan 2017 21:31 UTC in reply to "RE[4]: Microkernels"
Alfman Member since:
2011-01-28

Kebabbert,

UPDATE: Now I see what you mean:
"...I think that's where you're going wrong. You're looking at the complexity of one little piece and comparing it to the complexity of a whole system; and you're not comparing the complexity of "all pieces plus the communication necessary to form a whole system" to a whole system...."

And this could be true. I see your point now. Ok.


Yea, it's the amount of aggregate work for all pieces when all work is said and done. The micro-kernel's pieces are clearly separate execution units which enforce a strict API to intercommunicate, and this API might add complexity for developers, but I'm still on the wall about that. The modular kernel will also require it's own API(s) (and in the case of linux an unstable one), so the question is whether the micro-kernel API has to be more complex than the modular kernel API, I haven't seen enough evidence to convince me that it is.

A pure monolithic kernel might theoretically be done without APIs at all, with zero encapsulation and every piece of code modifying shared state as it needs to, but this is the anti-thesis of object oriented programming principals designed to simplify software. This is why it can make sense to use an API with strong encapsulation even in a monolithic kernel in order to reduce complexity. A case could be made that well designed APIs actually reduce complexity even if they add code. And in a micro-kernel, if I add a bit of code to the kernel proper, and it ends up simplifying thousands of drivers outside the kernel, I would consider that a net reduction of complexity.


For me it's hard to come to a 100% solid general conclusion on this topic. Complexity is just one factor that has to be balanced with security, robustness, efficiency, etc. This debate is interesting because the usual criticism for microkernels is the low performance of synchronous calls, but I think it's the first time we discuss complexity on it's own. Good discussion ;)

Edited 2017-01-09 21:35 UTC

Reply Score: 2