[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: New channel concept

From: olafBuddenhagen
Subject: Re: New channel concept
Date: Fri, 11 Jan 2008 14:20:00 +0100
User-agent: Mutt/1.5.17 (2007-11-01)


This time I have a bit more to say... ;-)

On Mon, Jan 07, 2008 at 09:56:48PM +0100, Carl Fredrik Hammar wrote:

> Old channels are required to implement a subset of the Hurds io
> interface.  But they also have the ability to implement arbitrary
> interfaces to deal with the additional operations that character
> devices might support.  It is obvious that the io interface of
> channels could be handled by the same mechanism, but that would make
> io optional, which didn't make sense in the old channel concept.

OK so far...

> There are also objects which I have called ``channel hubs'' (yuck!),
> that act as trivial filesystem objects, and they implement a subset of
> the Hurds fs interface.

Let me get this right: The hub is the entity that handles any RPC
requests made to a channel translator?

> It's such an object that actually gets transferred over IPC, which
> then produces channel objects.

You mean the process of a channel translator "uploading" the necessary
information so the client using libchannel can handle stuff itself
instead of further using the translator?

> While I have been criticized for terms used for these two object
> types, it is clear that they need to be distinct in order to fully
> implement channels.

Right :-)

> I then started toying with the idea of hubs as a type of channels that
> implement the fs interface, one that can return new channels.

I fear I'm totally lost now.

I thought channels basically offer a standard I/O interface, plus
individual additions, plus the channel management interface that allows
"uploading" the channel information so it can be handled in the client.
(Using libchannel modules.)

What are you suggesting here? Separating the channel management
interface from the actual I/O+extensions, so they are implemented by
different objects? If so, how would you uphold the concept of channels:
That a translator can either handle I/O requests itself, or optionally
upload the functionality to the client?

Well, maybe it's not that important to understand it, as it seems only a
temporary idea?...

> Of course this doesn't fit at all with the old concept of a channel,
> instead I now propose that channels be able to implement *arbitrary*
> Hurd objects.  All a server object has to do is implement a channel
> interface in order for a client to transfer it.

Well, I guess that fits with my proposal to turn channels into a generic
translator stacking framework. Not sure though what exactly you mean by
"Hurd objects" in this context. Did I mention already that the word
"object" is way overloaded? ;-)

> Because channels are designed to deal with stacked translators,
> channels can be considered a *logical communication channel* going
> through the stack.  Therefore I still regard ``channel'' an valid name
> for this abstraction.  (But by all means, do feel free to object!)
> Henceforth, ``channel'' will refer to the new concept unless otherwise
> specified.

Considering the more generic scope, maybe we should drop the whole
"channel" terminology alltogether, and try to find something more
intuitively describing translator stacking... I have no suggestions
offhand, though :-)

> Channels are now simply a mechanism to implement arbitrary objects,
> just like servers already do.  This way we'll really cover all our
> bases and hopefully the design will meet the needs of all possible
> implementations.

Yeah, that was essentially my idea. More precisely: That is what I have
been pondering for quite some time, and only recently it occured to me
that a generalized channel mechanism could provide that :-)

> Arbitrary objects you say?  So now we can just skip IPC altogether and
> reimplement the Hurd using channels, and the Hurd will be lightning
> fast?  Unfortunately not.  ;-)
> Channels can't provide any functionality to a process which it
> couldn't otherwise do.  This because channels can't offer any
> protection whatsoever for their content.  So an effort to only use
> channels would eventually lead to the entire system running inside a
> single process, or worse, inside the kernel.

That's not really what would happen. What libchannel does is moving
functionality into library modules within the clients, i.e. towards
top-level application programs. Taken to the extreme, you still have
exactly one process for each top-level application; but this process
implements almost all functionality it relies upon, including stuff that
traditionally is provided by other components; only at the very lowest
level (access to actual hardware and peripherial interfaces), you still
have central management. In short, you get the exokernel approach. Are
you familiar with that?

(In the original exokernel, the low-level hardware management is all
done by a monolithic kernel; but I guess the concept would also work
with isolated processes managing individual hardware components.)

Note however that this extreme is *not* the ideal we should strive for
IMHO. The idea of Exokernel is/was to devoid the low-level hardware
resource management of any abstractions (instead implementing optional
abstractions in libraries running within the user processes), to avoid
overhead -- promising better performance. But for starters, I'm not
convinced that the tricky filtering mechanisms necessary to specify
complex arbitrary policies without any abstractions do not actually pose
more overhead than a well chosen abstraction.

More importantly, my feeling is that the separation of policies from
abstractions done on too large a scale tends to encourage a bad system
structure. Policies combined with abstractions are much simpler and more
intuitive, leading to a very natural structure.

I guess theoretically it would be possible to logically offer
traditional servers implementing policies with abstractions, and
transparently decompose these into low-level abstraction-free policies
for the hardware management, and library modules implementing the
abstractions. (Though I don't see a way to do it really transparently
when coding in C...)

However, I'm not sure this can be done efficiently. In any case, if you
layer several logical servers, the complexity of the low-level policies
would probably quickly explode; and it might also result in overly
complex communication patterns. Thus I believe it's not really realistic
to do it all transparently. At least part of the policies would have to
be choosen explicitely -- again, leading to a bad system structure I

Last but not least, avoiding process boundaries by doing everything in
library modules means there is no fault isolation -- a very bad thing.
For that reason, I believe it should be done only in very specific,
isolated cases -- only when it is really necessary to achieve good

(For stores for example it's probably not really useful most of the
time... It seems to me that the major motivation behind libstore was
actually to allow the root FS to run without relying on other processes.
Personally, I'm not convinced this was really a good idea. But well,
what do I know :-) )

All in all I believe that the Exokernel model is interesting, and
worthwhile to use for some specific subsystems -- for graphics hardware,
Mesa's/Xorg's DRI/DRM model basically implements this model for example.
(As well as the older, now defunct KGI approach...) But doing it on a
large scale is not a good idea IMHO. For the most part, I think a good
design is about choosing the *right* abstractions in resource
management, not about avoiding them alltogether.

> So, if channels doesn't bring anything new to the table that a plug-in
> couldn't, what are they good for?  They are useful when you want to
> provide or use a service through either IPC or as a plug-in when the
> server provides it and the client can handle it.  The problem is that
> this requires code in the client that deal with both cases.  It is
> also important that the two cases behaves the same, anything else
> would likely confuse users.  It's precisely in these where cases
> channels find there niche, a means with which to deal with the two
> cases uniformly.

Right :-)

> This determines a first requirement of libchannel: there must be a
> special channel type that wraps around a port referencing the object,
> if it could not be fetched.

I wouldn't call it a special channel type. Rather, it's an inherent part
of the framework. Not only logically, but also technically it's probably
more useful to implement it specially, rather than trying to fit it into
the channel module mechanism...

> It also gives us a requirement for objects implemented in a channel:
> it has to have the same semantics as if it was used through a port
> wrapper instead.


> (This excludes channel junctions mentioned in the old discussion, but
> these couldn't be transferred in the old libchannel either, they were
> only coaxed in as channels to ease their implementation.  A decision I
> believe was a mistake in hindsight, as they only need to *use*
> channels.)

Very true. This point totally escaped me in the original discussion: As
junctions always have to run in a separate process from the clients,
i.e. can't be uploaded from their original translator, there is no point
at all to fit them into the channel model! I feel so stupid now :-)

Perhaps it might be still desirable to have some way to handle junctions
as part of a channel, e.g. to allow them to be used with channel
stacking syntax... But I'm not at all sure this is worthwhile, or even
desirable. I guess we should just ignore such a possibility for the base
concept -- that simplifies things a lot :-)

> Now there's a clear goal to strive for: the closer channel objects are
> to the semantics of using the object through a port, the more
> interfaces can be implemented by channels.  More specifically, the
> goal is to emulating full RPC calls (as opposed to the underlying
> message passing).  Ideally channel functions should act exactly like
> those generated by MIG, only differing in that their name are prefixed
> with ``channel_'', that their port parameters are dealt with in a
> uniform manner, and that they might perform better.  Given that MIG is
> well documented, it will be easy to evaluate this property of a
> design.  Any automation would also be welcomed.

I must disagree here. The idea of channels (or more generally,
optimizing translator stacking) is *not* merely to avoid actual RPC
calls. I don't think that would be a worthwhile goal. The actual IPC is
very slow on Mach, but modern microkernels show that it is possible to
do much better. The cost of IPC itself is not exactly neglectible, but
only in few situations really a relevant performance factor.

The main overhead of RPCs is not from the actual calls, but from the
implications of an RPC interface -- from the fact that client and server
can run in different processes (address spaces), possibly even on
different hosts. (Though we don't employ this latter possibilily
presently, and I'm not convinced it is really useful to preserve network
transparency at such a low level.) Meaning the client needs to be
prepared for communication to fail; meaning that the interface is
constrained to passing mostly plain values, no pointers, no global
variables, no function pointers etc.; meaning client and server don't
have access to the same resources; meaning server and client threads run
asynchronously (unless using passive objects, which we don't).

All these properties require a lot of overhead, which won't go away by
simply avoiding the actual RPC call. To really optimize here, it's
necessary to take it up at a much higher level. (In fact, the major
advantage of the channel concept over my earlier ideas on optimizing
translator stacking is the fact that it works at a higher level!)

When client and server are from the same channel family, they can
interact at a level that is in fact totally detached from the standard
I/O-based interface, using something much more abstract instead. (I must
confess that I don't know the actual store interfaces; but my guess is
that libstore uses such a special interface between the modules
internally?) In some cases the actual functionality of the individual
layers perhaps could even be implemented using some kind of abstract
description, rather than C code.

When client and server are from different families, obviously they can't
use such a specific interface; they will be bound by the I/O interface
as common denominator. But it still can happen through a high-level
variant totally detached from RPC mechanisms. Even for "dumb" clients,
not knowing anything about channels at all, it might still be useful to
wrap the I/O system calls at a level above actual RPCs. (In this case,
libc would have to call out to libchannel...)

> If a design achieves the goal stated above, channels can handle
> anything the old libchannel could.  The client obtains the port to a
> channel translators fs object, fetches the underlying channel (which
> correspond to a hub) and then calls ``channel_dir_lookup'' to get io
> channels (which correspond to old channels).

I don't understand the "channel_dir_lookup" step. What does that do?

> It is less obvious that it can handle stores, which implements an
> interface slightly more powerful than the normal Hurd io interface.
> (Among other things it exposes the sparseness of the underlying
> store.)  Cases like this should be handled by adding a new Hurd
> interface, since this additional expressiveness should not be hidden
> to clients that can't or do not wish to use channels.


> If an interface makes little sense in a IPC context, the translator
> can simply not handle such calls over IPC but still provide a
> implementation in the channel itself.  To deal with this the client
> should be able to detect when a transfer fails, so it can apply a
> compatibility channel over the original port.  If such a channel can't
> be implemented then the entire operation must fail if transfer fails.
> (This case is probably uninteresting, it would basically be a
> complicated way to implement plug-ins.)

I really think channels should only be used as an optimization of
translator stacking, i.e. be limited to things that can be expressed
through RPC interfaces.

Is there any use case where you think it would be important to do


reply via email to

[Prev in Thread] Current Thread [Next in Thread]