Boost logo

Boost :

From: Darryl Green (darryl.green_at_[hidden])
Date: 2005-12-26 00:31:57


Christopher Kohlhoff wrote:
>>One item that I have difficulty in discerning a clear
>>design/rationale for is the demuxer. The demuxer as
>>implemented is a repository of services (another wooly concept
>>afaiks) and something that provides the run, interrupt and
>>related functions to control the scheduling/dispatching of
>>handlers in reaction to changes in Async_Object state. Is
>>there anything preventing a more policy-based approach to
>>assembling services?
>
> The demuxer is composed of services in a similar way to how
> std::locale is composed of facets.

That tells me that there services are objects identified by type that
can be obtained from the thing that holds them (locale in iostreams,
demuxer in asio) by type. Which is - um - about what I knew already....

> The demuxer is not
> necessarily aware of, or coupled to, the service types that it
> contains. For example, the SSL implementation uses a service
> that is only added in to the demuxer if SSL is used.

I gathered that much. But tell me why/what for! Alternatively I'll try
to figure it out and write the docs - you can tell me if I get them right...

[pause to read code in more detail]

Ok - there are a number of service categories and some services depend
on other services. The stream_socket_service impl may, for example, be a
reactive_socket_service. The reactive_socket_service ultimately needs a
demuxer and a reactor, so it gets the reactor (itself a service) from
the demuxer via get_service.

It is documented that (unlike facets of a locale) the services are
constructed on use. This means that there is no way (?) that a custom
replacement service can be provided via the demuxer, as the actual
construction of the service is done by the service_factory based on the
type of service requested from the demuxer. Hence, to customize the
service, it has to have a different type from any existing service, and
the user of the service has to be modified to use the new type. There is
a possibility that some services are used by multiple components (eg the
demuxer and the socket) so care is needed in doing this customization.
Basically about as unlike a local and facets as you can get? I think
this is what threw me to start with.

Did I get that right?

Having been completely mislead by the docs, I think the real model is
something like this:

Having obtained the "locale" in the form of the demultiplexer the
"socket" can look up services that it needs by type.
Thats fine, I supposed initially that this meant a socket would look up
something that actually was a concrete implementation of a documented
concept, but I found that it looked up a blob-o-stuff documented as a
service. As it happens that blob-o-stuff may depend on detail impl that
uses detail services, some of which look suspiciously like they do
implement the concepts.

I'm left feeling that aside from impl detail this is all of no
significance except that service instances are 1:1 with demuxer
instances so it is a demuxer extension mechanism that is handy if a
socket policy needs to associate state with a demuxer not a socket
instance. As a special case the demuxing itself is accessed as a
service. In the case of policies that are associated with (or include a
component associated/implementing) the socket, variations on an idiom of
using a service::null function to get a null impl (ptr) and some form of
create/open etc to c'truct the actual impl is used.

What I was asking for (vaguely) was that the services be more facet-like
so that when customizing a socket-like class it can be assembled from
appropriate facets/concepts. This might mean pulling some of the detail
out of detail (leaving the platform dependent parts there).
Alternatively composite services could be assembled (as appears to be
the case in detail already) from their basic concepts.

In any case, I think a better description of what the service concept is
all about (possibly more than 1 concept here - the core service access,
services that use the demuxer and demuxer services) are needed if this
is to be usable as an accessible customization point of the library.

> The service used by a particular public interface (e.g.
> basic_stream_socket) is already a policy template parameter. One
> example program shows how basic_stream_socket can be
> instantiated with a custom service to perform logging, where
> this service is in turn implemented using the standard
> stream_socket_service.

I've had a look at that now. Is there some particularly profound reason
why logging implemented to fit in with the service idiom is a good
thing/example? It seems to achieve nothing special, though it goes
through some hoops to create a demuxer (private to the logging service)
to perform work in a background thread? Is that supposed to illustrate
something? I think this relates back to the need for better
docs/concepts in this area.

The replacement stream_socket_service is a copy of the original's
interface with logging calls added. It wraps (has a reference to) an
implementation that is the original asio::stream_socket_service. I agree
this illustrates some of the techniques I was asking about should be
practical within the design, which addresses some of my concerns.

I'm happy (unless you can tell me where I've got it completely wrong!) I
understand this area well enough for now. I would want see a much better
level of docs and examples of this area in a post-review version of the lib.

Regards
Darryl Green.

-- 
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.1.371 / Virus Database: 267.14.7/214 - Release Date: 23/12/2005

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk