Linked by Hadrien Grasland on Sun 29th May 2011 09:42 UTC
OSNews, Generic OSes It's funny how trying to have a consistent system design makes you constantly jump from one area of the designed OS to another. I initially just tried to implement interrupt handling, and now I'm cleaning up the design of an RPC-based daemon model, which will be used to implement interrupt handlers, along with most other system services. Anyway, now that I get to something I'm personally satisfied with, I wanted to ask everyone who's interested to check that design and tell me if anything in it sounds like a bad idea to them in the short or long run. That's because this is a core part of this OS' design, and I'm really not interested in core design mistakes emerging in a few years if I can fix them now. Many thanks in advance.
Thread beginning with comment 475036
To view parent comment, click here.
To read all comments associated with this story, please click here.
RE[2]: RPC considered harmful
by Neolander on Mon 30th May 2011 05:48 UTC in reply to "RE: RPC considered harmful"
Neolander
Member since:
2010-03-08

I probably shouldn't use the "RPC" term, you too got confused into thinking that I was talking about blocking calls, while I am in fact doing nonblocking calls.

Once you have a nonblocking call interface, you can trivially implement a blocking call interface on top of it. I simply choose not to do it because I don't want to favor this kind of dirty practices if I can avoid to.

As for RPC being too high level, well... I'm tempted to say that pipes are too low level.

Don't get me wrong, pipes are great for programs of the "streaming" kind, which have an input data stream, process it, and return results in an output data stream. That's why I have them. But most tasks of a system API do not belong to the data stream processing family, and are more about executing a stream of instructions.

In that case, pipes are too low-level, because they are fundamentally a transportation medium for integer data, not instructions. If you want to send instructions across a pipe, you have to use a communication protocol on top of the pipe layer in order to get an instruction representation, so what you have is user-mode RPC implemented on top of the pipe IPC primitive.

I personally think that if an IPC primitive is to be very frequently used, it's better to implement it directly in the kernel (or at least parts of it), due to the extra control it gives over the communication process. The kernel executes trusted code, but library code can be compromised.

Reply Parent Score: 1

RE[3]: RPC considered harmful
by Brendan on Mon 30th May 2011 10:08 in reply to "RE[2]: RPC considered harmful"
Brendan Member since:
2005-11-16

Hi,

I probably shouldn't use the "RPC" term, you too got confused into thinking that I was talking about blocking calls, while I am in fact doing nonblocking calls.


A call is something that doesn't return until it completes. A "non-blocking call" is something that defies logic.. ;)

I got the impression that your "non-blocking call" is a pair of normal/blocking calls, where (for e.g.) the address of the second call is passed as an argument to the first call (a callback). I also got the impression you're intending to optimise the implementation, so that blocking calls that return no data don't actually block (but that's an implementation detail rather than something that effects the conceptual model).

As for RPC being too high level, well... I'm tempted to say that pipes are too low level.


I'm not sure where pipes were mentioned by anyone, but I don't really like them much because they force the receiver to do extra work to determine where each "piece of data" ends.

Pipes can also make scheduling less efficient. For e.g. if a task unblocks when it receives IPC (like it should), then a task can unblock, look at what it received, realise it hasn't received enough data to do anything useful, and block again; which is mostly a waste of time (and task switches).

For an analogy (to summarise), think of email. Asynchronous messaging is like people writing emails and sending them to each other whenever they want while they do other things. Synchronous messaging and RPC is like people sending emails and then sitting there doing nothing for hours while they wait for a reply. Pipes are like people sending pieces of a conversation - "I just sent this email to say hell", "o and wish you a happy birth", "day.\n -Fred\000Dear sir, we are"...

I personally think that if an IPC primitive is to be very frequently used, it's better to implement it directly in the kernel (or at least parts of it), due to the extra control it gives over the communication process. The kernel executes trusted code, but library code can be compromised.


I assumed IPC primitives would be implemented directly in the kernel because you can't implement IPC anywhere else. For example, if you have an "IPC service" implemented as a process/daemon, how would processes communicate with the "IPC service"?

The other thing to consider is that usually IPC has a certain amount of control over the scheduler - tasks block when waiting for IPC, and tasks unblock (and then potentially preempt) when they receive IPC, so it makes sense to implement it near the scheduler.

- Brendan

Reply Parent Score: 2

RE[4]: RPC considered harmful
by Neolander on Mon 30th May 2011 11:41 in reply to "RE[3]: RPC considered harmful"
Neolander Member since:
2010-03-08

A call is something that doesn't return until it completes. A "non-blocking call" is something that defies logic.. ;)

I got the impression that your "non-blocking call" is a pair of normal/blocking calls, where (for e.g.) the address of the second call is passed as an argument to the first call (a callback). I also got the impression you're intending to optimise the implementation, so that blocking calls that return no data don't actually block (but that's an implementation detail rather than something that effects the conceptual model).

What I want to do is...

1/Process A gives work to do to process B through a "fast" system call, that in turn calls a function of B in a new thread using a stack of parameters given by A.
2/Process A forgets about it and goes doing something else.
3/When process B is done, it sends a callback to process A through the same mechanism using which A has given B work to do (running a function of A). Callbacks may have parameters, the "results" of the operation.

Does it remind you of something ?

I'm not sure where pipes were mentioned by anyone, but I don't really like them much because they force the receiver to do extra work to determine where each "piece of data" ends.

For me send_message() and get_message() was like pipe operation (you send messages to or receive messages from the pipe). Sorry if I didn't get it.

For an analogy (to summarise), think of email. Asynchronous messaging is like people writing emails and sending them to each other whenever they want while they do other things. Synchronous messaging and RPC is like people sending emails and then sitting there doing nothing for hours while they wait for a reply. Pipes are like people sending pieces of a conversation - "I just sent this email to say hell", "o and wish you a happy birth", "day.\n -Fred\000Dear sir, we are"...

Then what I do is definitely not RPC in the usual sense, as it is an asynchronous mechanism too. If the above description reminds you of some better name, please let me now.

I assumed IPC primitives would be implemented directly in the kernel because you can't implement IPC anywhere else. For example, if you have an "IPC service" implemented as a process/daemon, how would processes communicate with the "IPC service"?

If you have something like a pipe or message queue, you can implement higher-level IPC protocols on top of it, and use user-space libraries to implement a new IPC mechanism that uses these protocols. That's what I was talking about. But except when trying to make the kernel unusually tiny, I'm not sure it's a good idea either.

The other thing to consider is that usually IPC has a certain amount of control over the scheduler - tasks block when waiting for IPC, and tasks unblock (and then potentially preempt) when they receive IPC, so it makes sense to implement it near the scheduler.

Totally agree.

Edited 2011-05-30 11:57 UTC

Reply Parent Score: 1