Messages in this thread | | | Subject | Re: select for UNIX sockets? | From | Krzysztof Halasa <> | Date | 08 Jun 2003 02:04:10 +0200 |
| |
"David Schwartz" <davids@webmaster.com> writes:
> You are doing something wrong. You are using 'select' along with > blocking > I/O operations. You can't make bricks without clay. If you don't want to > block, you must use non-blocking socket operations. End of story.
There is a little problem here. Do you see any place for select() here? There isn't any.
If you have a working select(), you can use (blocking or non-blocking) I/O functions a get a) low latency b) small CPU overhead. If you want to use non-blocking I/O, either with broken select() or without it at all, you get either a) high latency, or b) high CPU overhead.
> Just because 'select' indicates a write hit, you are not assured > that some > particular write at a later time will not block. Past performance does not > guarantee future results.
The problem is select() on UNIX datagram sockets returns immediately, and thus it could be well substituted by a NOP. There isn't any "performance".
> Suppose, for example, a machine has two network interfaces. One is very > busy, queue full, and one is totally idle, queue empty. What do you think > 'select' for write on an unconnected UDP socket should do? If you say it > should block, then it can block forever even if there's plenty of buffer > space on the network card you were going to send to. So, it can't block, it > must indicate writability.
That's a little different problem, and a datagram will be transmitted by this busy interface at last (while you will never send a datagram if nobody is reading the socket).
Hoverer, select() doesn't work on connected sockets either (I missed the fact the example program doesn't connect at first, but it's unimportant here).
> You have any number of sane choices. My suggestion is that you make the > socket non-blocking and treat an EWOULDBLOCK return as equivalent to > success. You can additionally take it as a hint that the packet will be as > if it was dropped.
You essentially transform a code such as: while () { select(); blocking_send(); }
into:
while() { non_blocking_send(); }
Not very CPU-friendly :-(
Having working select() on at least connected sockets is a must.
intrepid:/tmp$ strace -f ./test 2>&1 |egrep 'socket|bind|connect|send|recv'
[pid 1051] socket(PF_UNIX, SOCK_DGRAM, 0) = 3 [pid 1051] bind(3, {sa_family=AF_UNIX, path="/tmp/test"}, 11) = 0 [pid 1050] socket(PF_UNIX, SOCK_DGRAM, 0) = 3 [pid 1050] connect(3, {sa_family=AF_UNIX, path="/tmp/test"}, 11) = 0 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 <<<<< the last packet queued [pid 1050] send(3, "\1", 1, 0 <unfinished ...> <<<<<< doesn't fit in queue [pid 1051] recvfrom(3, "\1", 2000, 0, NULL, NULL) = 1 [pid 1051] recvfrom(3, "\1", 2000, 0, NULL, NULL) = 1 [pid 1051] recvfrom(3, "\1", 2000, 0, NULL, NULL) = 1 [pid 1051] recvfrom(3, "\1", 2000, 0, NULL, NULL) = 1 [pid 1051] recvfrom(3, "\1", 2000, 0, NULL, NULL) = 1 <<<<< makes room [pid 1050] <... send resumed> ) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0) = 1 [pid 1050] send(3, "\1", 1, 0 <unfinished ...> -- Krzysztof Halasa Network Administrator - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |