aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorEliezer Tamir <eliezer.tamir@linux.intel.com>2013-06-24 03:28:03 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-25 19:35:52 -0400
commit2d48d67fa8cd129ea85ea02d91b4a793286866f8 (patch)
treebe47e2406605760d949b08d29d988d46c4a20799 /include
parente4f2379db6c6823c5d4a4c2c912df00c65de51d7 (diff)
net: poll/select low latency socket support
select/poll busy-poll support. Split sysctl value into two separate ones, one for read and one for poll. updated Documentation/sysctl/net.txt Add a new poll flag POLL_LL. When this flag is set, sock_poll will call sk_poll_ll if possible. sock_poll sets this flag in its return value to indicate to select/poll when a socket that can busy poll is found. When poll/select have nothing to report, call the low-level sock_poll again until we are out of time or we find something. Once the system call finds something, it stops setting POLL_LL, so it can return the result to the user ASAP. Signed-off-by: Eliezer Tamir <eliezer.tamir@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r--include/net/ll_poll.h35
-rw-r--r--include/uapi/asm-generic/poll.h2
2 files changed, 24 insertions, 13 deletions
diff --git a/include/net/ll_poll.h b/include/net/ll_poll.h
index fcc7c365cee5..5bf2b3a6129e 100644
--- a/include/net/ll_poll.h
+++ b/include/net/ll_poll.h
@@ -30,6 +30,7 @@
30#ifdef CONFIG_NET_LL_RX_POLL 30#ifdef CONFIG_NET_LL_RX_POLL
31 31
32struct napi_struct; 32struct napi_struct;
33extern unsigned int sysctl_net_ll_read __read_mostly;
33extern unsigned int sysctl_net_ll_poll __read_mostly; 34extern unsigned int sysctl_net_ll_poll __read_mostly;
34 35
35/* return values from ndo_ll_poll */ 36/* return values from ndo_ll_poll */
@@ -38,17 +39,18 @@ extern unsigned int sysctl_net_ll_poll __read_mostly;
38 39
39/* we can use sched_clock() because we don't care much about precision 40/* we can use sched_clock() because we don't care much about precision
40 * we only care that the average is bounded 41 * we only care that the average is bounded
42 * we don't mind a ~2.5% imprecision so <<10 instead of *1000
43 * sk->sk_ll_usec is a u_int so this can't overflow
41 */ 44 */
42static inline u64 ll_end_time(struct sock *sk) 45static inline u64 ll_sk_end_time(struct sock *sk)
43{ 46{
44 u64 end_time = ACCESS_ONCE(sk->sk_ll_usec); 47 return ((u64)ACCESS_ONCE(sk->sk_ll_usec) << 10) + sched_clock();
45 48}
46 /* we don't mind a ~2.5% imprecision
47 * sk->sk_ll_usec is a u_int so this can't overflow
48 */
49 end_time = (end_time << 10) + sched_clock();
50 49
51 return end_time; 50/* in poll/select we use the global sysctl_net_ll_poll value */
51static inline u64 ll_end_time(void)
52{
53 return ((u64)ACCESS_ONCE(sysctl_net_ll_poll) << 10) + sched_clock();
52} 54}
53 55
54static inline bool sk_valid_ll(struct sock *sk) 56static inline bool sk_valid_ll(struct sock *sk)
@@ -62,10 +64,13 @@ static inline bool can_poll_ll(u64 end_time)
62 return !time_after64(sched_clock(), end_time); 64 return !time_after64(sched_clock(), end_time);
63} 65}
64 66
67/* when used in sock_poll() nonblock is known at compile time to be true
68 * so the loop and end_time will be optimized out
69 */
65static inline bool sk_poll_ll(struct sock *sk, int nonblock) 70static inline bool sk_poll_ll(struct sock *sk, int nonblock)
66{ 71{
72 u64 end_time = nonblock ? 0 : ll_sk_end_time(sk);
67 const struct net_device_ops *ops; 73 const struct net_device_ops *ops;
68 u64 end_time = ll_end_time(sk);
69 struct napi_struct *napi; 74 struct napi_struct *napi;
70 int rc = false; 75 int rc = false;
71 76
@@ -84,7 +89,6 @@ static inline bool sk_poll_ll(struct sock *sk, int nonblock)
84 goto out; 89 goto out;
85 90
86 do { 91 do {
87
88 rc = ops->ndo_ll_poll(napi); 92 rc = ops->ndo_ll_poll(napi);
89 93
90 if (rc == LL_FLUSH_FAILED) 94 if (rc == LL_FLUSH_FAILED)
@@ -95,8 +99,8 @@ static inline bool sk_poll_ll(struct sock *sk, int nonblock)
95 NET_ADD_STATS_BH(sock_net(sk), 99 NET_ADD_STATS_BH(sock_net(sk),
96 LINUX_MIB_LOWLATENCYRXPACKETS, rc); 100 LINUX_MIB_LOWLATENCYRXPACKETS, rc);
97 101
98 } while (skb_queue_empty(&sk->sk_receive_queue) 102 } while (!nonblock && skb_queue_empty(&sk->sk_receive_queue) &&
99 && can_poll_ll(end_time) && !nonblock); 103 can_poll_ll(end_time));
100 104
101 rc = !skb_queue_empty(&sk->sk_receive_queue); 105 rc = !skb_queue_empty(&sk->sk_receive_queue);
102out: 106out:
@@ -118,7 +122,12 @@ static inline void sk_mark_ll(struct sock *sk, struct sk_buff *skb)
118 122
119#else /* CONFIG_NET_LL_RX_POLL */ 123#else /* CONFIG_NET_LL_RX_POLL */
120 124
121static inline u64 ll_end_time(struct sock *sk) 125static inline u64 sk_ll_end_time(struct sock *sk)
126{
127 return 0;
128}
129
130static inline u64 ll_end_time(void)
122{ 131{
123 return 0; 132 return 0;
124} 133}
diff --git a/include/uapi/asm-generic/poll.h b/include/uapi/asm-generic/poll.h
index 9ce7f44aebd2..4aee586979ca 100644
--- a/include/uapi/asm-generic/poll.h
+++ b/include/uapi/asm-generic/poll.h
@@ -30,6 +30,8 @@
30 30
31#define POLLFREE 0x4000 /* currently only for epoll */ 31#define POLLFREE 0x4000 /* currently only for epoll */
32 32
33#define POLL_LL 0x8000
34
33struct pollfd { 35struct pollfd {
34 int fd; 36 int fd;
35 short events; 37 short events;