aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2014-01-16 20:50:04 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-16 22:10:34 -0500
commit6398e23cdb1d807132c1d3d007d6b1ec87b511af (patch)
tree41ce1f1fa70ea6c60475316e080c67e0063693af /net/tipc/socket.c
parent78eb3a5379a52f291556483ea55b8a37e2ed4d5b (diff)
tipc: standardize accept routine
Comparing the behaviour of how to wait for events in TIPC accept() with other stacks, the TIPC implementation might be perceived as different, and sometimes even incorrect. As sk_sleep() and sk->sk_receive_queue variables associated with socket are not protected by socket lock, the process of calling accept() may be woken up improperly or sometimes cannot be woken up at all. After standardizing it with inet_csk_wait_for_connect routine, we can get benefits including: avoiding 'thundering herd' phenomenon, adding a timeout mechanism for accept(), coping with a pending signal, and having sk_sleep() and sk->sk_receive_queue being always protected within socket lock scope and so on. Signed-off-by: Ying Xue <ying.xue@windriver.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index b2ae25ae3038..008f6fdf95c3 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1566,6 +1566,42 @@ static int listen(struct socket *sock, int len)
1566 return res; 1566 return res;
1567} 1567}
1568 1568
1569static int tipc_wait_for_accept(struct socket *sock, long timeo)
1570{
1571 struct sock *sk = sock->sk;
1572 DEFINE_WAIT(wait);
1573 int err;
1574
1575 /* True wake-one mechanism for incoming connections: only
1576 * one process gets woken up, not the 'whole herd'.
1577 * Since we do not 'race & poll' for established sockets
1578 * anymore, the common case will execute the loop only once.
1579 */
1580 for (;;) {
1581 prepare_to_wait_exclusive(sk_sleep(sk), &wait,
1582 TASK_INTERRUPTIBLE);
1583 if (skb_queue_empty(&sk->sk_receive_queue)) {
1584 release_sock(sk);
1585 timeo = schedule_timeout(timeo);
1586 lock_sock(sk);
1587 }
1588 err = 0;
1589 if (!skb_queue_empty(&sk->sk_receive_queue))
1590 break;
1591 err = -EINVAL;
1592 if (sock->state != SS_LISTENING)
1593 break;
1594 err = sock_intr_errno(timeo);
1595 if (signal_pending(current))
1596 break;
1597 err = -EAGAIN;
1598 if (!timeo)
1599 break;
1600 }
1601 finish_wait(sk_sleep(sk), &wait);
1602 return err;
1603}
1604
1569/** 1605/**
1570 * accept - wait for connection request 1606 * accept - wait for connection request
1571 * @sock: listening socket 1607 * @sock: listening socket
@@ -1582,7 +1618,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
1582 struct tipc_port *new_tport; 1618 struct tipc_port *new_tport;
1583 struct tipc_msg *msg; 1619 struct tipc_msg *msg;
1584 u32 new_ref; 1620 u32 new_ref;
1585 1621 long timeo;
1586 int res; 1622 int res;
1587 1623
1588 lock_sock(sk); 1624 lock_sock(sk);
@@ -1592,18 +1628,10 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
1592 goto exit; 1628 goto exit;
1593 } 1629 }
1594 1630
1595 while (skb_queue_empty(&sk->sk_receive_queue)) { 1631 timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
1596 if (flags & O_NONBLOCK) { 1632 res = tipc_wait_for_accept(sock, timeo);
1597 res = -EWOULDBLOCK; 1633 if (res)
1598 goto exit; 1634 goto exit;
1599 }
1600 release_sock(sk);
1601 res = wait_event_interruptible(*sk_sleep(sk),
1602 (!skb_queue_empty(&sk->sk_receive_queue)));
1603 lock_sock(sk);
1604 if (res)
1605 goto exit;
1606 }
1607 1635
1608 buf = skb_peek(&sk->sk_receive_queue); 1636 buf = skb_peek(&sk->sk_receive_queue);
1609 1637