--=_courier-2562-1054769670-0001-2
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 7bit
Alan Cox <alan@lxorguk.ukuu.org.uk> writes:
> Sort of. The wakeup may occur for several reasons and you need to check
> the return (for signals). Also the wakeup can occur when there is room
> but another thread fills it, or return room but not enough for a large
> datagram. Those don't seem to be the case on your example
I've traced the problem to datagram_poll(). This function doesn't
check if the receiver queue has at least one slot empty, it only
checks sock_writeable() i.e. if:
atomic_read(&sk->wmem_alloc) < (sk->sndbuf / 2);
unix_dgram_sendmsg() can then block on:
if (unix_peer(other) != sk &&
skb_queue_len(&other->receive_queue) > other->max_ack_backlog) {
if (!timeo) {
err = -EAGAIN;
goto out_unlock;
Now the question is how should the problem be fixed?
I've tried using modified datagram_poll():
+ unix_socket *other = NULL;
- if (sock_writeable(sk))
+ other = unix_peer_get(sk);
+ if (sock_writeable(sk) && other &&
+ skb_queue_len(&other->receive_queue) <= other->max_ack_backlog)
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
but unix_peer_get(sk) returns NULL.
How can I examine the receiver queue length?
Should I worry about "restarts" as in unix_dgram_sendmsg()?
Maybe someone has a fix ready?
I've attached the userspace tests, a modified version of someone's real
program - recv should be run first, send should be straced.
The problem is present in both 2.5.70 and 2.4.20rc7.
-- Krzysztof Halasa Network Administrator--=_courier-2562-1054769670-0001-2 Content-Type: application/octet-stream Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=recv.c
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <fcntl.h>
int socketUn; struct sockaddr_un addrUn; int lenUn; int size = 1; char datagram[2000];
void sockInit();
int main() { sockInit();
while(1) { sleep(30);
while(size != -1){ size = recvfrom(socketUn, &datagram, sizeof(datagram), 0, (struct sockaddr*)NULL, (socklen_t *)NULL); /* if (size == -1) perror("recvfrom failed: "); else printf("DATAGRAM: size: %d\n", size);*/ } size = 0; } }
void sockInit() { if ( unlink("/tmp/tempUn") == -1) perror("unlink failed\n");
socketUn = socket(AF_UNIX, SOCK_DGRAM, 0); if (socketUn == -1) perror("socket failed");
addrUn.sun_family = AF_UNIX;
strcpy(addrUn.sun_path, "/tmp/tempUn");
lenUn = strlen(addrUn.sun_path) + sizeof(addrUn.sun_family);
if ( bind(socketUn, (struct sockaddr *)&addrUn, lenUn) == -1) perror("bind failed");
fcntl(socketUn, F_SETFL, O_APPEND|O_NONBLOCK); }
--=_courier-2562-1054769670-0001-2 Content-Type: application/octet-stream Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=send.c
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <fcntl.h>
int socketUn; struct sockaddr_un addrUn; int lenUn; int size; char datagram[1]; int dgramCounter = 0; int maxFdToWatch; fd_set writeFdToWatch;
void sockInit();
int main() {
sockInit();
maxFdToWatch = socketUn + 1;
while(1) { FD_ZERO(&writeFdToWatch); FD_SET(socketUn, &writeFdToWatch);
select(FD_SETSIZE, NULL, &writeFdToWatch, NULL, NULL); sleep(1);
if (FD_ISSET(socketUn, &writeFdToWatch)) { size = sendto(socketUn, &datagram, sizeof(datagram), 0, (struct sockaddr *)&addrUn, lenUn); if (size == -1) perror("sendto failed"); sleep(1); }
dgramCounter++;
FD_ZERO(&writeFdToWatch); } }
void sockInit() { socketUn = socket(AF_UNIX, SOCK_DGRAM, 0); if (socketUn == -1) perror("socket failed"); addrUn.sun_family = AF_UNIX; strcpy(addrUn.sun_path, "/tmp/tempUn"); lenUn = strlen(addrUn.sun_path) + sizeof(addrUn.sun_family); }
--=_courier-2562-1054769670-0001-2--