On Sun, 2004-12-05 at 20:56 +0000, Icarus Sparry wrote:
> I posted this to USENET (comp.lang.lisp) and it was suggested to me that I
> should email this list instead. It is a little long. Summary
> I have something which works, but I would like it improved. It adds missing
> funcuntionality to sb-bsd-sockets, but it is not very general.
I attempted the same thing a few months ago. I had something that worked
with 0.8.10 or so, but then something changed in the depths of sb-bsd-
sockets relating to the FFI interface and the way sb-grovel was working,
and my patches weren't good after 0.8.10.56 or thereabouts. I got busy
with some other stuff and haven't been able to get back to it.
Let me see if I can dig up the code.
A few comments on your code:
1. You should not use sb-grovel::define-foreign-routine directly, but
rather hack a definition for sendto into constants.lisp.
2. As you say, you shouldn't declare things as strings that are really
buffers of unsigned octets. You can make your socket-sendto interface
smart and "do the right thing," depending on the type of buffer passed
to it. This obviously requires more code to special case a few
interesting data types (strings, arrays, lists, etc.).
3. Your current solution has some subtle bugs, I believe. In particular,
you haven't accounted for blocking in the socket layer, multiple
threads, and garbage collection. Depending on how the OS implements its
networking and threading, there *may* exist a case where the first
thread gets blocked while in the sockets layer, but before the network
stack copies the data out of the heap. If another SBCL thread runs and
triggers a GC which causes the buffer to move on the heap, the network
stack may end up with a bogus pointer. This may only happen on some
ports where the GC moves things around (do all versions of the SBCL GC
copy/compact?) and where a UDP sendto would block (not very likely, but
potentially still possible, depending on the OS/stack implementation).
To get around this, you can do one of a couple of things. In the 0.8.10
timeframe, the code used to lock the buffer on the heap so that it
couldn't be moved. I'm guessing this interfered with GC at some level
and the new code (0.8.10.56+) seems to use an alien copy buffer (see
socket-receive in sockets.lisp, for instance, where the probability of
blocking in the call is very high). This is not a very efficient
solution, obviously, because you're copying data around within the Lisp
process, and then the stack will likely copy it to kernel buffers, too.
That said, I'm not a good enough SBCL hacker to know what the Right
Thing(TM) is to do here.
Dave Roberts <ldave@...>