Boost logo

Boost :

From: Giovanni P. Deretta (gpderetta_at_[hidden])
Date: 2006-02-07 09:38:44


Christopher Kohlhoff wrote:
> Hi Giovanni,
>
> --- "Giovanni P. Deretta" <gpderetta_at_[hidden]> wrote:
> <snip>
>
>>A nice solution would be to make socket movable...
>
>
> Yes, this would be nice, but unfortunately I see problems
> reconciling this with some other changes arising from the review
> that I want to make :(
>
> Basically, I want the public interface to allow an
> implementation that stores state directly in the socket object.
> Some of the advantages of doing this include:
>
> - The ability to eliminate per-socket memory allocations.
> Coupled with the custom handler allocation support, you could
> write programs with no ongoing memory allocations occurring
> inside asio.
>

I think this is very important and I'm all in favor of it. But I do not
see how making the socket movable excludes this point. A movable socket
would have an extra bit saying if the state is valid or not. When it is
"moved" the receving socket gets a copy of the state. The valid bit on
the source is turned off while the same bit is turned on in the
receiving socket (*). I expect that the internal state of the socket is
not big enough that copying is a bottle-neck. Moving is thus not a
performance optimization, but a correctess operation. The source object
is no longer valid (can only be destoryed) and the destination socket
becomes the true handle for the device

> - Improved performance, e.g. by eliminating many of the hash
> table lookups to find the list of operations associated with a
> descriptor.
>
> Some of this "state" might be that the socket object is part of
> an intrusive linked list or hash map. This would make
> implementing movability, at best, difficult and inefficient.
>

I do not see how this would be inefficient. Suppose that a socket is :

struct socket {
        socket* prev;
        socket* next;
        bool valid;
        /* more state here */

        void swap(socket& from) {
         prev = to.prev;
         next = to.next;
         prev->next = this;
         next->prev = this;
         /* swap state */
         }
} ;

void move(socket& from, socket& to) {
        socket().swap(to);
        from.swap(to)
}

This requires the socket to be default constructible (or else do a
socket(to.demuxer()).swap(to)) and a swap function in socket (i thought
that asio::socket already had it, but looking at the docs i see i was
wrong).
Yes this is thread unsafe. To make it thread safe, you need to lock the
list (or at least the objects involved) to protect the swap. But you
need a mutex anyway because the object in the intrusive list could be
destroyed at any time.

Ah, btw, at least on posix systems, file descriptors are guaranteed to
be allocated contiguously. So you could create a vector as big as the
hightest fd, store the list of operations in it and use the socket_impl
as a key for an O(1) lookup in the vector.

(*) Btw, you do not really need an extra bit of course. A socket_impl
equal to null_socket would identify an invalid socket (as is the case
right now).

-- 
Giovanni P. Deretta

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