Well I'm always happy to take a public pasting in return for the chance to 
learn something :) It's fair to say I didn't fully understand the implications 
of TCPs flow-control mechanisms re buffering capacity, and I've been grateful 
to be guided here.

> On 4 Sep 2013, at 16:52, Bryan O'Sullivan <b...@serpentine.com> wrote:
> Your question is actually not related to Haskell at all,

Well.. I'll try to protest my inquiry was specifically targeted at Haskell and 
that it's reasonable to ask:  "what is the behaviour of send when there is no 
buffering capacity?";  and "as a newcomer to Haskell, broadly what are the 
mechanisms used to implement send on top of the C API?".  Thanks to everyone 
who provided pointers.

Network.Socket has this to say:

> Essentially the entire C socket API is exposed through this module; in 
> general the operations follow the behaviour of the C functions of the same 
> name (consult your favourite Unix networking book).

I'm pretty sure you can't understand the behaviour of Network.Socket from 
consulting a Unix networking book, otherwise you'd be looking for -1 return 
values and error-codes, and pondering how you might go about efficiently 
managing read/write to a whole bunch non-blocking sockets.

I don't know how one would go about providing a little background in the 
Network.Socket docs but it seems it would be very helpful;  there's no clue 
provided as to the magic that it's taking care of.

Anyway, that's enough hot air from me. I've put my findings below in case 
anyone else is ever interested.

S







For anyone interested, here's what I learned from asking questions here and 
digging around:

- The underlying C sockets are in non-blocking mode;

- send uses a threadWaitWrite to block the current thread until the socket is 
writeable;

- threadWaitWrite relies on either epoll or kqueue to efficiently identify 
writeable file-descriptors, therefore select is not required and not 
implemented by Network.Socket, and there is no need to provide API access to 
setting O_NONBLOCK;

- threadWaitWrite is run inside a throwSocketErrorWaitWrite 
(Network.Socket.Internal), which uses a throwErrnoIfRetry (Foreign.C.Error);  
the overall effect is that if the threadWaitWrite/send operation ever errors 
with EINTR then the whole threadWaitWrite/send is retried;  otherwise 
subsequent sends are managed and called by threadWaitWrite when the send is 
likely to succeed (which is more efficient than polling using a retry loop 
alone);  all other errors are converted to IOError.

The end result on the behaviour of the Network.Socket.send is:

- send can result in all sorts of socket-related IOErrors being thrown, except 
for EINT interrupts because the send is efficiently managed and retried;

- send never has a return value of -1, because an exception is raised or the 
send is retried;

- send blocks the current thread if a socket is not currently writeable.

- It strikes me that a return value of 0 for Network.Socket.send is unlikely, 
because otherwise the socket file-descriptor would not have reported that it 
was writeable and the send would not have been called.  But I'm unsure if a 0 
value could never be returned.


Simon Yarde
simonya...@me.com

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to