diff options
| author | Eliezer Tamir <eliezer.tamir@linux.intel.com> | 2013-06-24 03:28:03 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-06-25 19:35:52 -0400 |
| commit | 2d48d67fa8cd129ea85ea02d91b4a793286866f8 (patch) | |
| tree | be47e2406605760d949b08d29d988d46c4a20799 /include | |
| parent | e4f2379db6c6823c5d4a4c2c912df00c65de51d7 (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.h | 35 | ||||
| -rw-r--r-- | include/uapi/asm-generic/poll.h | 2 |
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 | ||
| 32 | struct napi_struct; | 32 | struct napi_struct; |
| 33 | extern unsigned int sysctl_net_ll_read __read_mostly; | ||
| 33 | extern unsigned int sysctl_net_ll_poll __read_mostly; | 34 | extern 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 | */ |
| 42 | static inline u64 ll_end_time(struct sock *sk) | 45 | static 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 */ |
| 51 | static inline u64 ll_end_time(void) | ||
| 52 | { | ||
| 53 | return ((u64)ACCESS_ONCE(sysctl_net_ll_poll) << 10) + sched_clock(); | ||
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | static inline bool sk_valid_ll(struct sock *sk) | 56 | static 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 | */ | ||
| 65 | static inline bool sk_poll_ll(struct sock *sk, int nonblock) | 70 | static 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); |
| 102 | out: | 106 | out: |
| @@ -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 | ||
| 121 | static inline u64 ll_end_time(struct sock *sk) | 125 | static inline u64 sk_ll_end_time(struct sock *sk) |
| 126 | { | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | static 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 | |||
| 33 | struct pollfd { | 35 | struct pollfd { |
| 34 | int fd; | 36 | int fd; |
| 35 | short events; | 37 | short events; |
