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 474924
To read all comments associated with this story, please click here.
RPC considered harmful
by Kaj-de-Vos on Sun 29th May 2011 12:09 UTC
Kaj-de-Vos
Member since:
2010-06-09

You asked for criticism, so I'll be negative: RPC is a bad concept to base an entire OS on. It's inherently tied to the implementation language and to the implementation details of the services. That makes it difficult to port, hard to keep compatible with itself over time, and thus hard to keep compatible with different versions of the services.

The abstraction level of RPC interfaces is too low. To solve these problems, you need a messaging specification at a higher abstraction level, through declarative data specification.

Reply Score: 1

RE: RPC considered harmful
by Neolander on Sun 29th May 2011 12:52 in reply to "RPC considered harmful"
Neolander Member since:
2010-03-08

You asked for criticism, so I'll be negative: RPC is a bad concept to base an entire OS on. It's inherently tied to the implementation language

Why couldn't wrappers be used? Most Unices have a system API that's linked to C concepts at the core, that doesn't prevent C++ or Python wrappers from being used by people who prefer those languages, at the cost of a small performance hit.

and to the implementation details of the services.

Again, why has it to be the case? A good interface can be standard without revealing implementation details. If I say that my memory allocator is called using the malloc(uint parameter) function, how does it prevent me from changing the memory allocator later ?

That makes it difficult to port,

Define port. What do you want to port where?

hard to keep compatible with itself over time,

Unless I miss something, it's not harder than having a library keep a consistent interface over time. Which is, again, a matter of having the library interface not depend on the implementation details. Why should it be so hard?

and thus hard to keep compatible with different versions of the services.

Not if people don't break the interface every morning.

The abstraction level of RPC interfaces is too low.

Why? If the interface of C-style dynamic libraries is enough, how can the RPC interface, which is just a nonblocking and cross-process variant of it in the end, be different?

To solve these problems, you need a messaging specification at a higher abstraction level, through declarative data specification.

Well, I wait for answers to the questions above before asking for more details about your suggested answer.

Reply Parent Score: 1

RE: RPC considered harmful
by Brendan on Mon 30th May 2011 03:27 in reply to "RPC considered harmful"
Brendan Member since:
2005-11-16

Hi,

The abstraction level of RPC interfaces is too low.


In my opinion, it's the opposite problem - the RPC interface is too high level.

A "call" can be broken into 4 phases - the callee waiting to be called, the caller sending data to the callee, the callee executing, and the callee sending data back to the caller.

This could be described as 3 operations - "wait for data", "send data and wait to receive data back" and "send data and don't wait to receive data back".

Now, stop calling it "data" and call it "a message" (it's the same thing anyway, mostly), and you end up with "get_message()", "send_message_and_wait_for_reply()" and "send__message()".

For synchronous software (e.g. emulating RPC); the callee does "get_message()" and blocks/waits until a message arrives, the caller does "send_message_and_wait_for_reply()" and blocks/waits until it receives the reply; and then the callee does "send_message()" to return the reply. It's exactly like RPC.

The interesting thing is that for asynchronous software, you'd use "send_message()" and "get_message()" and don't need anything else. Basically, by breaking it down into these primitives you get synchronous and asynchronous communication (rather than just synchronous); and people can mix and match without limitations. For example, you could have a fully asynchronous service, where one client process uses synchronous messaging to use the service and another client process uses asynchronous messaging to use the service, and the service itself doesn't need to care what each client is doing.

However, you would probably want to offer a few extra primitives to make things easier. For example, you might consider adding "send_message_and_wait_for_reply_with_timeout()", and "check_for_message()" (which would be like "get_message()" but returns a "NO_MESSAGES" error instead of blocking/waiting for a message when there are no messages to get).

-Brendan

Reply Parent Score: 2

RE[2]: RPC considered harmful
by Alfman on Mon 30th May 2011 05:43 in reply to "RE: RPC considered harmful"
Alfman Member since:
2011-01-28

Brendan,

"A 'call' can be broken into 4 phases - the callee waiting to be called, the caller sending data to the callee, the callee executing, and the callee sending data back to the caller."

I've done this before, usually passing XML data structures around and manipulating them with DOM & SAX Parsers. While the approach is flexible, I'd personally be terrified to work on a system where this model is used exclusively to glue hundreds or thousands of components together (as in an operating system).

Can you illustrate why breaking down messaging to such a low level is superior to what .net does with marshalling and web service proxy objects?

If you are not familiar with it, the .net compiler takes a SOAP web service and builds a proxy class which exposes all the functions in the SOAP interface. The proxy class exposes both synchronous functions and asynchronous ones.

MyWebService x = new MyWebService();
result = x.MyFunction(...); // synchronous
AsyncRequest r = x.Begin_MyFunction(...); // Async
... // other code
result = x.End_MyFunction(r); // Async return


Is there a good reason typical devs might want to access the messaging stack at a lower level than this?

Keep in mind, that a programmer could always pass a single hash table to any function, which would technically be as expressive and extensible as any other conceivable messaging protocol (so long as the inner objects are either serializable or marshalled).

Edited 2011-05-30 05:46 UTC

Reply Parent Score: 2

RE[2]: RPC considered harmful
by Neolander on Mon 30th May 2011 05:48 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[2]: RPC considered harmful
by Kaj-de-Vos on Mon 30th May 2011 12:29 in reply to "RE: RPC considered harmful"
Kaj-de-Vos Member since:
2010-06-09

You're talking about the transport method. That is indeed the other side of the coin. I have been talking about the problem that RPC implies an inflexible semantic data exchange (the payload). You're right that RPC also implies an inflexible transport method.

Reply Parent Score: 1