The OS-periment's IPC design is looking for "testers"
The OS-periment's IPC design is looking for "testers"
TOSP : the context
I'm the main and only developer in a project called the OS-periment. This project aims at producing a modern OS that's specifically designed with the needs of personal computing in mind. By personal computers, I designate desktops, laptops, tablets (if they ever happen to get standard and open hardware one day), and as a whole everything with a relatively large screen, which is to be operated by one single user at a time, and which does not require this user to have received an in-depth formation and read kilometric manuals in order to do the most basic things. Implementation is done in C and C++, save for few assembly snippets here and there.
It has appeared to me that such a concept, when pushed sufficiently far, screams for optimization down to the lowest layers of the OS stack. Take, as an example, security models. The user-based security infrastructure which is at the core of most of today's server-centric operating systems is poorly suited to the job, because it is designed to protect a sysadmin from malicious users on large-scale multi-user machines and not to protect an average user from malicious software. Users have to use root privileges all the time for tasks like setting up the system clock or installing software which are trivial for them, so in the end those privileges become meaningless. A security model that's fine-tuned for personal computing should, to the contrary, be application-based, and give each *software* only limited security permissions to play with, while keeping the user as an almighty overlord which can do whatever he wants. Code to do this exists for a lot of modern kernels, but it has appeared too late and does not take a significant part in the associated OS' culture. As an example, try to do anything unusual or fancy on a SElinux-based distribution, and it'll end up getting in your way. Linux and its huge existing software library have simply not be designed for that.
Taking sides also helps with some traditional OS development compromises. Take, as an example, microkernels vs monolithic kernels. Reliability vs raw kernel performance. On most modern single-user machines, I believe that raw performance is not the most vital concern, provided that it remains sufficient, as long as reactivity to user input, which is the most important performance criteria there, can be ensured through other means, like careful prioritizing of interactive tasks above background ones. Therefore, I take the extra reliability and cleanness of microkernels over the throughput of monolithic kernels without hesitating a second.
Help needed !
One important area of a microkernel design is inter-process communication. We have isolated processes from each other, yet they still have to give themselves work to do from time to time. How do they do that ? That's the core question behind IPC. My personal answer to this problem would be a non-blocking variant of RPC, either using asynchronous task queues or pop-up threads depending on the problem that is being solved by the server process which receives the remote calls. But since design mistakes bite very hard if they are found late in the OS design process, I'm asking all theory enthusiasts around here if they would be interested in having a look at my current design, and report any potential problem which they see with it.
Many thanks in advance, here's the link : http://theosperiment.wordpress.com/2011 ... model-rc3/
I'm the main and only developer in a project called the OS-periment. This project aims at producing a modern OS that's specifically designed with the needs of personal computing in mind. By personal computers, I designate desktops, laptops, tablets (if they ever happen to get standard and open hardware one day), and as a whole everything with a relatively large screen, which is to be operated by one single user at a time, and which does not require this user to have received an in-depth formation and read kilometric manuals in order to do the most basic things. Implementation is done in C and C++, save for few assembly snippets here and there.
It has appeared to me that such a concept, when pushed sufficiently far, screams for optimization down to the lowest layers of the OS stack. Take, as an example, security models. The user-based security infrastructure which is at the core of most of today's server-centric operating systems is poorly suited to the job, because it is designed to protect a sysadmin from malicious users on large-scale multi-user machines and not to protect an average user from malicious software. Users have to use root privileges all the time for tasks like setting up the system clock or installing software which are trivial for them, so in the end those privileges become meaningless. A security model that's fine-tuned for personal computing should, to the contrary, be application-based, and give each *software* only limited security permissions to play with, while keeping the user as an almighty overlord which can do whatever he wants. Code to do this exists for a lot of modern kernels, but it has appeared too late and does not take a significant part in the associated OS' culture. As an example, try to do anything unusual or fancy on a SElinux-based distribution, and it'll end up getting in your way. Linux and its huge existing software library have simply not be designed for that.
Taking sides also helps with some traditional OS development compromises. Take, as an example, microkernels vs monolithic kernels. Reliability vs raw kernel performance. On most modern single-user machines, I believe that raw performance is not the most vital concern, provided that it remains sufficient, as long as reactivity to user input, which is the most important performance criteria there, can be ensured through other means, like careful prioritizing of interactive tasks above background ones. Therefore, I take the extra reliability and cleanness of microkernels over the throughput of monolithic kernels without hesitating a second.
Help needed !
One important area of a microkernel design is inter-process communication. We have isolated processes from each other, yet they still have to give themselves work to do from time to time. How do they do that ? That's the core question behind IPC. My personal answer to this problem would be a non-blocking variant of RPC, either using asynchronous task queues or pop-up threads depending on the problem that is being solved by the server process which receives the remote calls. But since design mistakes bite very hard if they are found late in the OS design process, I'm asking all theory enthusiasts around here if they would be interested in having a look at my current design, and report any potential problem which they see with it.
Many thanks in advance, here's the link : http://theosperiment.wordpress.com/2011 ... model-rc3/
- NickJohnson
- Member
- Posts: 1249
- Joined: Tue Mar 24, 2009 8:11 pm
- Location: Sunnyvale, California
Re: The OS-periment's IPC design is looking for "testers"
First, it doesn't make any sense to have the user as superuser but no applications, because the user interacts with the system through applications, and therefore either makes everything run as superuser or get minimal privileges (depending on how you interpret that sentence.) Second, giving the user superuser access all the time is dangerous: they should have to jump through hoops to get it, since they should also think before using it.Neolander wrote:... while keeping the user as an almighty overlord which can do whatever he wants.
Edit: I should probably actually answer your question too...
It seems like a pretty reasonable plan for an RPC-based microkernel. However, RPC naturally tends to cause sort of over-binding between different parts of the system, because different components can have a lot of knowledge about the interfaces of other components. I would simply be careful about that. Basically, make APIs for types of drivers, not individual drivers, and you should be fine. Also, I would make sure that the absence of a function call in a driver is handled gracefully.
Re: The OS-periment's IPC design is looking for "testers"
Yeah, that part was badly written. Let me try it again.NickJohnson wrote:First, it doesn't make any sense to have the user as superuser but no applications, because the user interacts with the system through applications, and therefore either makes everything run as superuser or get minimal privileges (depending on how you interpret that sentence.) Second, giving the user superuser access all the time is dangerous: they should have to jump through hoops to get it, since they should also think before using it.Neolander wrote:... while keeping the user as an almighty overlord which can do whatever he wants.
The user trusts the core OS services. So none of them should require special privilege escalation for him. On a blank OS install, he should be able to do everything without ever seeing an UAC-like security warning, since OS components are trusted from the start anyway.
As an example, if the user wants to edit system files or delete the kernel, so be it, he'll get what he deserves if he screws up. What I'd do about such dangerous situations would be to put a regular (not security) warning when the user opens system folders or starts editing things, that politely tells him that what he's doing is dangerous. Kind of like Windows XP did, but with an obvious and easy way to disable it so that power users do not get annoyed. If the user then chooses to ignore or disable the warning, knowing that what he's doing is dangerous, then what happens next is his problem, not the OS' one anymore, in my opinion. I think that desktop OSs shouldn't be overprotective nannies, they should just give subtle advices and help the user know what he's doing.
This does not prevent system apps from having limited privileges at the core. But the defaults should be sufficiently permissive that the user does not have to know about them. As an example, "do not alter any files but yours and the ones explicitly designated by the user through a standard system "open file" GUI or a command line parameter" is a reasonable security restriction for a text editor.
It's only when the user runs a new program which wants to do things beyond the basics and without asking the user in a controlled way first (like, say, directly access hardware without going through the system API and drivers, or alter system settings without going through a standard system dialog for this) that security alerts should start to appear, with clear and concise descriptions of what privileges the application requests, and why they are dangerous. And they should remain an exception. Average word processors, image editors, games, etc. shouldn't need them, without getting full implicit access rights to system folders or the user's home either.
This security part is far from being done yet, though, and you're right that they are still lots of questions to be answered when I start to seriously work on it. But I think it's an interesting path to study.
You mean that drivers should have standard RPC interfaces, and not all make their owns ? Indeed, that sounded pretty obvious to me, but "obvious" is a word that is never to be used in the design world, because the "to me" part is the key . Adding it.It seems like a pretty reasonable plan for an RPC-based microkernel. However, RPC naturally tends to cause sort of over-binding between different parts of the system, because different components can have a lot of knowledge about the interfaces of other components. I would simply be careful about that. Basically, make APIs for types of drivers, not individual drivers, and you should be fine.
Do you mean at connection time or after connection time ? (cf last paragraph of II.1.b)Also, I would make sure that the absence of a function call in a driver is handled gracefully.
At connection time, it is possible to reserve the "0" connection identifier as an invalid identifier which indicates that the connection has failed. The client stub may handle this situation gracefully, but if it goes on and tries to send RPC calls using connexion 0, the kernel mumble that enough is enough, and sends its holy wrath on the client (in short : client segfaults, unless it has set up an exception handler for this).
After a connection has been established, it can reasonably be assumed that the server will keep the remote call all the time, so only thing which must be handled is server death and rebirth. This could be done by having the kernel internally queue client calls while the server is being resurrected, and block the client if that queue gets full (though it should be sufficiently big not to get full in normal circumstances).
If the server's function calls DID change (because of, say, a compatibility-breaking API change due to a server update), I think that kernel holy wrath on the client is the only reasonable option, even though the client isn't exactly guilty.
What would you think about this ?
Last edited by Neolander on Sun Jun 12, 2011 3:04 am, edited 6 times in total.
Re: The OS-periment's IPC design is looking for "testers"
Well, on OSX and Haiku, I think I remember that it's the other extreme : you never, ever, receive a single warning. So you may well screw up your system without knowing what you're doing. Not sure about OSX though, it's been a while since I've had to tamper with system files on it.berkus wrote:If you only've seen how Windows does it, doesn't mean that all OSes do it equally bad.
Whereas on all linux distros I've used to date, you have to keep logging as root or giving your password all the time, without knowing why, like on Windows. And like one Windows, it quickly becomes relatively meaningless. Especially when you consider than standard user apps can blank your home or send all personal data within it on the internet anyway, which is far worse than a screwed up system config IMO.
Last edited by Neolander on Sun Jun 12, 2011 2:41 am, edited 2 times in total.
Re: The OS-periment's IPC design is looking for "testers"
Like this ?berkus wrote:ADD: OS should protect at least its own files from tampering with, I knew unsuspecting users who moved WINDOWS95 folder into the My Documents folder and then wondered why it doesn't boot. Assume the worst, most stupidest users that have to be protected from themselves and nannied, but don't do it as silly as Windows does. The implementation in windows stems from some other architectural misdesigns which they couldn't patch due to backwards compatibility.
"As an example, if the user wants to edit system files or delete the kernel, so be it, he'll get what he deserves if he screws up. What I'd do about such dangerous situations would be to put a regular (not security) warning when the user opens system folders or starts editing things, that politely tells him that what he's doing is dangerous. Kind of like Windows XP did, but with an obvious and easy way to disable it so that power users do not get annoyed. If the user then chooses to ignore or disable the warning, knowing that what he's doing is dangerous, then what happens next is his problem, not the OS' one anymore, in my opinion."
Re: The OS-periment's IPC design is looking for "testers"
Do you remember what kind of sentence it says, or can take a screenshot ? I don't have a mac at hand where I currently live.berkus wrote:OSX explains you why you need to give your administrator password.
Re: The OS-periment's IPC design is looking for "testers"
This I cannot agree with. Hiding things would hurt power users to no end, and only bring limited benefits to regular users if the VFS is well-organized. For treating users like mindless dummies and removing any control on the low-level OS from them, products like iOS already existberkus wrote:No. User shall never see the system folders at all. User is sandboxed just like any other app is.
Last edited by Neolander on Sun Jun 12, 2011 3:31 am, edited 2 times in total.
Re: The OS-periment's IPC design is looking for "testers"
Please do, and many thanks in advance !berkus wrote:The text is always different, depending on what you're about to do.
I can take a screenshot for saving to a system file perhaps.
Re: The OS-periment's IPC design is looking for "testers"
No, just no. I don't want to create another iOS where any tinkering requires arcane operations to be performed first. This OS disgusts me too much, noticeably for this reason. There has to be another way, or at least I want to believe it now, though I may change my mind later. (I'm currently designing low-level IPC mechanisms, what we're currently talking about is more drafts for the future)berkus wrote:Regular users disagree. Power users will always jailbreak anyway. Just give them the possibility.
Re: The OS-periment's IPC design is looking for "testers"
Great idea !berkus wrote:Ok, we can disagree here, so let's disagree on the RPC too?
Well, just about everywhere where there's a process boundary, save for system calls.Too much data copying, I believe. Can you elaborate on how much this mechanism is to be used (I noticed you say "at the lowest level in the system" or somesuch).
As for where I'd put a process boundary, I'd say between core kernel services (essentially MM and process/thread management) and drivers, between different drivers, between those and higher-level system services (VFS, GUI rendering), between unrelated higher-level services, and obviously between regular software and any system services.
Rule of thumb would be that all processes should answer relatively specific needs, but that the tasks which they do should be complex enough that the IPC overhead remains sufficiently low. As an example, I don't believe in putting schedulers outside of the kernel : that would cause a lot of context switches without resulting in a significant security/reliability benefit. Let's face it, switching processes and manipulating the clock requires ring 0. On the other hand, modern drivers are so complex that they win by being taken out of the kernel.
To reduce large-scale data copying, shared memory may be used, to some extent (client has to explicitly allocate memory as shareable, sole pointers being analyzed for automatic sharing in the event of an RPC call are those which are directly used as function parameters). See II.2.a about automatic sharing and appendix A about how sharing is implemented.
Re: The OS-periment's IPC design is looking for "testers"
Yep, that pretty much describes the part which happens once, except that there's a step 0 where client and server broadcast which remote calls they offer (API functions for the server, callbacks for the client). The server also has to follow a similar (albeit slightly simpler) procedure for callback setup in remote calls which use them.berkus wrote:Step 1:
a client wishing to utilise a service broadcasts query for a function signature
Step 2:
some trader service looks up the signature and finds appropriate server
Step 3:
client and server set up marshalling stubs which keep track of extra/removed parameters, api versioning and current client/server session
on client side this returns a kind of function pointer that client can then directly use
on server side it probably sets up a thread pool (or adds handler structure to an existing one)
The idea is to put all gory stuff in a "heavy" initialization procedure, so that the overhead only occurs once, and subsequent remote calls can be made as fast as possible.
Yep. Note that on SMP systems, server may run directly after the call, in parallel with the still running client.Step 4:
client invokes provided closure with parameters
this code will marshal all data, post it into the server and immediately return
Step 5:
server process gets cpu time and processes request
upon completion is has to call some asynchronous callback
(this callback was probably set up in Step 3 but in other direction, e.g. server get a closure of marshalling stub, and client started a thread pool to serve it)
Client is not randomly interrupted, and does not block when making calls. A separate function will handle the callback, exactly like server would handle incoming calls, except that the callback parameters include some identifier that specifies which operation this callback is associated with. Like server-side remote call, the callback function can either be handled asynchronously (e.g. parameters are unmarshaled and put in thread pool by the kernel, handler is run when current client thread is done) or in a multi-threaded fashion (new thread is spawned within the client to handle the incoming callback), depending on what's most convenient and fastest.Step 6:
client is interrupted in some random place to receive the callback?
or client's thread in thread pool is unblocked to serve the callback call, unmarshal some data and call some internal (synchronized) function to process the results.
Re: The OS-periment's IPC design is looking for "testers"
Well, by putting an emphasis on asynchronous behaviour at such a fundamental level, I hope that people would try to use asynchronous callbacks more often instead of making inefficient synchronous versions, but mayber I'm being naive there.berkus wrote:It looks a bit too heavy (especially the asynchronous callbacks - I bet first thing designed there would be a synchronous wrapper that sits in a loop until callback fires or timeout happens), but it should work.
As for heaviness... Do you speak as compared to other µKernel IPC primitives ? And also, do you speak in terms of design complexity or in terms of communication overhead ? I actually believe that the communication overhead could be less than that of message passing for a large number of remote calls, given a well-optimized implementation, due to the abstraction being closer to the tasks it's used for.
Interesting, I didn't know that it worked like that... Should have a look at their design docs or their communication code, then, if it's human readable.(For an example of such system in user space see PulseAudio - it has a fairly convoluted setup process, but then if you get the locking right it even works, sometimes.)
They should certainly be sent together, but as for unifying them I believe that they are separate concepts. Some API changes do not alter the parameter structures but do break compatibility, for a silly example imagine that someone would modify malloc() so that it takes block size in KB instead of bytes.Also you have separated API versioning and function signatures, while they look like the same abstraction level to me.
Re: The OS-periment's IPC design is looking for "testers"
Just noticed that you had uploaded the OSX screenshot in the previous post
Maybe the "details" section is human readable now, though. I remember it being a bit arcane on my relatives' Leopard laptops. Can't check from here, the popup won't open no matter how many times I click on the triangle
At first look, it seems to have the same problem which I have with UAC, which is that it has a very coarse-grained view of what apps can and can't do : you know which program is doing something wrong (TextMate), but you don't know what it wants to do, and why it is wrong. TextMate "makes changes". Which changes to what ? It is unknown. For well-trusted programs acting on the behalf of the user, it's not a problem, but it is my guess that if a fancy "desktop tweaking" app pretended to change windows decorations and in fact did that PLUS erasing half of the System folder, you'd get exactly the same message. You don't know what the application is doing, only that it needs full root privileges for that.berkus wrote:E.g. saving a system file looks like this:
Maybe the "details" section is human readable now, though. I remember it being a bit arcane on my relatives' Leopard laptops. Can't check from here, the popup won't open no matter how many times I click on the triangle
- NickJohnson
- Member
- Posts: 1249
- Joined: Tue Mar 24, 2009 8:11 pm
- Location: Sunnyvale, California
Re: The OS-periment's IPC design is looking for "testers"
I suppose I was assuming a bit of a simpler protocol based on the description. I would also agree that that is overkill.berkus wrote:Let me describe how I understood the architecture:
...
Did I get it right complexity-wise?
I also use a lot of RPC in my OS, so maybe it would be useful to describe mine in comparison. It's not very optimized, but it's much simpler conceptually. My only real IPC primitive is a message, which is asynchronous and is handled by a pop-up thread, and has its contents sent by remapping pages. The RPC, which is implemented on top of it, is synchronous and sends one string as an argument and receives one as a return value. Here are the steps:
Step 1:
The client sends a message containing the RPC call string to the server, and waits on a queue for a reply.
Step 2:
The server spawns a pop-up thread to receive the RPC call, which is then routed based on its first space-separated part (like a command line) to the appropriate registered handler.
Step 3:
The server's handler returns a string, which is sent by another message to the client.
Step 4:
The client spawns a pop-up thread to receive the RPC reply and queues it, then transfers control to the waiting thread, which pulls it from the queue and returns.
I/O uses messages directly, because they have low overhead, and events are done in almost the same way as RPC, but with no reply. RPC is mostly used for VFS stuff and stuff that might otherwise use ioctl().
Re: The OS-periment's IPC design is looking for "testers"
I could well explain awfully badly, but I think that I get similar complexity after the initialization steps, and that you forget your own initialization steps.
Like...
Like...
- How does the client learn about the server's PID ?
- How do different versions of the client and the server communicate with each other ?