deadmutex wrote:
The 4 user/kernel switches + 2 context switches is a problem that microkernels have in general. You'd have the same issue if you were to put the page fault handler or IRQ handlers in user-space. A well-designed IPC system (not necessarily message passing) can mitigate the performance penalty.
I didn't even think about handling IRQs in userspace O_O...think I'll pass on that one.
deadmutex wrote:
If using synchronous message passing, then here's one way to do it with RPC calls: in addition to having send() and receive(), you'd also have send_and_wait() which sends a request to a server and immediately waits for a reply. If the recipient isn't ready to receive then the sender blocks and the kernel sends a message to the scheduler. If, on the other hand, the recipient is already waiting to receive a request from the sender, then the kernel sets the sender to receive a reply from the recipient and then switches to the recipient, donating the remaining timeslice. Once the request has been serviced, the server sends a reply back to the sender and the kernel resumes execution of the sending thread. So, a client does a send_and_wait() to the FS driver and the FS driver does a send_and_wait() to the block driver. Then the block driver sends a response to the FS driver and the FS driver sends a response to the client. A lot of switching is involved, which is why IPC design is so important.
For user-mode scheduling in microkernels, you might find
this paper helpful.
Stoess, J.
Towards Effective User-Controlled Scheduling for Microkernel-Based Systems, ACM SIGOPS Operating Systems Review, Volume 41, Issue 4, Jul 2007, pp 59-68.
https://doi.org/10.1145/1278901.1278910Hmmm, that's an interesting idea, I might mess with that. I think part of my problem is I was originally approaching it a bit too conventionally? Not sure if that's the right word. What I mean by that is instead of having EVERYONE send messages I was trying to come up with a way to basically return to the caller instead of just telling the receiver who the caller is and having them simply send a message back. So the flow I've been trying to work around in my head is something like process sends to FS driver, FS driver sends to block driver, and then block driver RETURNS to FS driver and the kernel has to figure out who that return goes to and such...I think I was massively over-complicating this by trying to add a return mechanism.
nullplan wrote:
STOP! Go back to start and remember your first principles: First make it work, then make it work fast. The system you have right now is the worst possible one, because it does not exist yet. Any scheduler at all, even if it takes a full second to complete a process switch, is better than that (on the principle that something is better than nothing). So just go back and implement your design, and then figure out how to make it better.
Software development is essentially a learning process, less engineering and more "throwing stuff at the wall to see what sticks". The important part is that implementing something will teach you about the challenges associated with that thing, which details require more consideration, etc. So just build it and see what questions remain unanswered. And never optimize before measuring. Programmers are notoriously bad at anticipating performance. Just try it, it probably won't be that bad.
...I uhhhh am not exactly over-planning. The system I described is KINDA what my current kernel actually does...just without the working scheduler bit. That is, the kernel currently sets up the APIC for preemption, it currently jumps into a userspace scheduler on preemption, that userspace scheduler then goes back into the kernel. The bit I haven't figured out is the message passing and stuff around actually getting it to schedule in userspace hence the main question. I'm very much a fan of writing without much forethought...maybe a bit too much lol.
vvaltchev wrote:
My advice is to keep the scheduler and basic memory management in the micro-kernel itself. It's way simpler and faster than trying to put even the scheduler in user space. Also, that's exactly what most of the microkernels do. Then, you might consider implementing filesystems and drivers in user space, if you want.
But, if I have to be completely honest, I'd say that it would make sense to me trying first to have something working using the simplest model possible (monolithic kernel) and then, step by step, modify it in a way that parts of it run in userspace. This way you'll have:
- More time to learn hands-on the typical OS problems before getting into microkernels
- A stable system to play with, while you'll be working on increasing the complexity of its architecture.
Probably, you'll have some automated tests as well at this point.
- A sense of reward given by the results so far: starting with the 4th gear in will lead you to so many problems that you might demotivate yourself.
Vlad
I've thought about doing this a bit but I'm a bit worried I'll get into a situation where modifying the monolithic kernel to be more dependent on userspace servers will be incredibly difficult because I fail to design my drivers in a way that allows for easy removal from kernel space.
nexos wrote:
I'm developing a microkernel as well. And have spent many hours thinking about the design. Although its all on paper at the moment (I'm currently redesigning my build system), I can give you a few recommendations.
First, read books about OS theory. No, I'm not talking about ast's books. My personal favorite is Uresh Vahalia's Unix internals. It will make theory make sense.
Second, don't start with clumsy algorithms then use good ones. You'll have a mess.
Third, implement the scheduler and memory manager in the kernel. No microkernel implements scheduling in user space. Implementing memory management in user space will make you very confused when designing it. Note that the process manager should go in user space, and parts of the memory manager as well, but not the whole thing.
Fourth, plan your algorithms. I have been planning my algorithms for nearly 6 months now! Be sure to especially plan your IPC system.
One more thing, look into the "One kernel stack per CPU" approach. If done right, it could improve performance (less context switches).
...that's...an awfully lot of planning in contrary to one of the other posts here lol...I uhhh, jumped into my kernel right away. As noted I've actually already implemented pieces of the userspace scheduler, I just have gotten a bit stuck with how to actually make it schedule and not play ping pong with the kernel as the only process in ring 3 and wasn't sure how to best approach its design.