[Top][All Lists]

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

Re: Channel sessions

From: olafBuddenhagen
Subject: Re: Channel sessions
Date: Sun, 12 Aug 2007 16:03:28 +0200
User-agent: Mutt/1.5.16 (2007-06-11)


On Thu, Aug 02, 2007 at 04:57:36PM +0200, Carl Fredrik Hammar wrote:

> I was writing a reply to your message, trying to sort out this
> confusing subject, when it suddenly realized what the source of this
> confusion.
> I have considered channels to be a entity corresponding to a
> translator, a special translator that cleanly handles character device
> semantics.  This worked as long I only considered exclusive access
> cases, but when I got to ``multiplexing''. Then I realized that
> per-open session data was needed to differentiate clients.
> So I started to add session parameters to most channel operations, so
> that different clients can get different data (or the same data.)  And
> now it seems obvious that each session is a channel in its own right.
> And what I called a channel is in-fact the mutable data of the
> channel's class.
> So in conclusion, a channel is a per-open entity, while a channel
> class is a per-server entity.  When you layer channels you actually
> layer channel classes, how the actual channels get layered is
> class-specific.  The class might open a new channel or it may re-use a
> single shared channel.  Actually, ``channel factory'' might be a
> better word than class, but I think I'll stick with class.
> Hopefully this will clear things up.

Well, I think we generally failed to define a clear terminology. Or
maybe you actually did, and I only fail to stick to it. In any case, to
make things clear, I'll explain what terms seem most logical to me. Let
me know what you think of that. I have so far (mostly) been using all
terms in the way I'm defining them here, and will also do so for the
rest of this mail.

Channel is the general term for the whole concept, and thus can be used
in various ways. The most strict meaning proably would be an entity that
can be accessed through the channel interface, i.e. a filesystem node
served by a channel translator. (To avoid ambiguity, one could also call
that a channel endpoint or so.) However, depending on context, channel
might also refer to other things.

A channel module is a single unit implementing the channel interface,
running within libchannel or in a channel translator. It has a client
side, which can be access through a filesystem node or through
libchannel; and a device side, which can access either a Mach device, or
the client side of another channel module. A channel stack is a layering
of several channel translators/modules.

An output channel is a channel that passed data from the client side to
the device side; an input channel is the opposite.

A channel instance is an individual client connection to a channel. Most
modules will pass through every instance individually, but some will
take several instances on the client side and open only one instance on
the device side.

A stream is similar to an instance, except that a bidirectional channel
usually has one input stream and one output stream per instance. This
term is somewhat blurry, as I'm not sure how this should actually be
handled in practice. As I pointed out, one possible variant could be
creating modules that will pass on the output streams of all instances
individually, but only a joined input stream, or the other way round...
Which would make the relation of streams and channel instances pretty
confusing. (Other variants are more clear.)

A channel class for me sounds like a specific kind of channel with
certain properties, e.g. an audio channel or a network channel. However,
as you are using this term in a totally different meaning, I try to
avoid using it this way. Channel type also describes it quite well I

Henceforth, I will use "junction" for any module that merges or splits
channels or channel instances.

> <olafBuddenhagen@gmx.net> writes:
> > On Thu, Jul 26, 2007 at 09:24:32PM +0200, Carl Fredrik Hammar wrote:

> >> My solution is simple enough; they should all be implemented in
> >> channels (as opposed to being implemented in channelio.)  This will
> >> be more general and give the user more control.  The downside is
> >> that it will be a bit more unwieldy, almost every translator will
> >> introduce a chain of channels at a time, instead of just one.
> >
> > What is the reason for this decision? My feeling is that I should be
> > able to individually express every single element of a channel stack
> > with a distinct translator...
> >
> > Well, maybe I just didn't get your meaning right.
> Of course you could still express the stack elements in distinct
> translators, but we're dealing with functionality normally provided by
> the translator, like buffering.  Introducing a translator that only
> differs from its back-end in that it provides buffering doesn't seem
> useful, most likely you want it bundled with the lower-most
> translator.

I see.

> The unwieldy part is that instead of giving a --buffer or --no-buffer
> flag you now have to use channel layering syntax, e.g.
> ``buffer:dev:dsp'' (or something like that, I haven't given much
> thought to the syntax.)

I don't understand the reason for that. Why can't --buffer or
--no-buffer be used? In storeio, you also have a number of optional
flags, and if you give several of them, you get implicit layering,
although you only set a single translator -- without using the
"unwieldy" layering syntax...

> >> Multiplexors are primarily used to gain multiple sessions to
> >> exclusive access devices and also balances io over sub-channels.
> >> E.g. they multiplex in both directions.
> >
> > Why do you want to merge these functionalities? They seem totally
> > independant -- I can't think of any situation where one would want
> > to use both together.
> >
> > Maybe there *are* cases where you need multiple inputs and multiple
> > outputs in a single component, so it's probably reasonable to leave
> > this option open; but I don't think it should be used in any of the
> > standard modules.
> I agree that they are functionally independent and that performing
> both is uncommon.  But they are conceptually similar, they do the same
> thing only in different directions.  This way we don't need an
> `in-tee' and an `out-tee'.
> The good news is that since they are functionally independent, they
> don't get in the way of each-other.  Normally you would only layer it
> over a single channel, in which case input would simply be forwarded
> to the back-end in a fifo manner.

Well, I don't see the point in a translator/module that -- depending on
context -- will either do one thing, or another totally unrelated thing.
(And in very seldom cases both.) Even moreso as I can see multiple
variants for both functionalities -- any combination would be totally

Also, I thing there still might be some confusion here. It seems very
important that we get a common understanding of the topology.

There are basically two kinds of junctions regarding the topology:
Multi-client junctions and multi-device junctions. Those are two totally
different things, serving very different purposes, and usually not used

For each of these base kinds, there are two diretions (input our
output); for bi-directional channels, usually a pair is necessary.
However, the pairing is not always obvious. In your example, we had two
clients that read from the same audio device. What we need here in the
tee I desribed, which is a muliti-client input junction. What is the
complementary multi-client output junction? In the audio case, probably
an arithmetic mixing makes most sense -- the tee allows multiple clients
to simultaneously read from the same device, and the mixer allows
multiple clients to simultaneously output to the same device. In other
cases however, like networking for example, we would obviouly need
something else to provide complementary functionality...

Now what about the out-tee? This is somewhat confusing: While the in-tee
is a multi-client input junction, the out-tee is a multi-device output
junction -- something totally unrelated with very different use cases.
Also, althouh the basic idea of duplicating streams is the same,
forwarding from one client to multiple devices is totally different
implementation-wise than forwarding from one device to multiple

The situation is even more confusing for fifo. There are two distinct
kinds: A split-fifo (with a topology like the tee), and a merge-fifo;
each having in- and out-variants. (Maybe better leave out the "fifo"
alltogether and give them totally distinct names instead, to reduce

Furthermore, for every variant, multiple policies are possible: If there
are outstanding requests from several connections, how to shedule them?
Always prefer the first one and fallback to others only if the first is
busy? Use round-robin? Or yet something else?

All this only convinces me more and more, that there are very few -- if
any -- generic modules useful for various types of channels; it's more
like every channel type will have a distinct set of modules useful for
this particular type. This is what I felt from when I first learned
about the channel concept, and in fact this made me very sceptical about
the whole concept for a long time. Only recently I realized that even if
every channel type uses totally different modules, it still makes sense
to use a common framework...

> > Also, "multiplexer" is a bad choice of name, as this term is already
> > used for a specific kind of translators.
> I can't think of anything else to call them collectively.

See above: I suggest "junction".

> > This brings up another problem: The fact that for some kinds of
> > channels, input and output are rather independant, and may be
> > handled differently.
> >
> > [...]
> >
> > I can think of several approaches for that. One possibility is, if
> > you have a module that merges outputs for example, i.e. from all the
> > client outputs generates only a single output stream to the device,
> > to simply pass through all client inputs as distinct streams
> > (channel instances). You could then put another translator below
> > that, which for example duplicates all the inputs from a single
> > device stream, and directly passes through the output stream.
> >
> > Another possibility would be making the input/output split explicit,
> > using a dedicated pair of modules for that: First you have a module
> > that splits each client session into an output stream and an input
> > stream, forwarded to different backends. The output and input
> > backend then could be implemented by totally distinct translator
> > paths (sitting on different FS nodes). Finally, the other dedicated
> > module would merge output and input stream again and forward them to
> > a common device backend.
> >
> > The above may be the most elegant and transparent solution, but
> > could be a bit cumbersome due to the many translators one needs to
> > set explicitely. Yet another variant could be using a single special
> > translator that internally splits output and input, and passes them
> > to two extra modules specified as command line parameters.
> Yes this would be the right way to go.  I have already thought about
> the whole in/out splitting and reached the same conclusions.
> A third would be to have two simplex channels instead of a duplex one,
> all the way through.  While it's probably the most generall solution,
> it seems to much to cumbersome.

This is in fact my second suggestion (as opposed to the third which you
commented on above): You could split the directions immediately before
the direction-dependant modules, and join them again directly
afterwards; but you could also do the split at the very bottom of the
stack, and join only at the very top... The mechanism is the same.

Every of the variants I suggested has a specific appeal: The first
variant is elegant in the sense that you never explicitely split the
directions -- instead, just stack various modules, some handling the
input case and some the output case. The third variant is elegant in the
sense that every translator handles both directions, the split happening
only internally. The second variant is elegant in that it doesn't really
require any special handling: It just uses generic direction
splitting/merging modules, which are implemented just the same as other
modules (i.e. the framework doesn't need any extra facilities to handle
bidirectionality), and can be useful also in other scenarios anyways.

Indeed the fact that it doesn't require special handling, strongly
suggests that this variant is probably the most reasonable to use for
the beginning -- if it turns out too cumbersome in practice, something
more involved still can be devised...


reply via email to

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