diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2011-07-04 00:33:37 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2011-07-04 00:33:37 +0000 |
commit | 8b015e49e180729ea6153e828699ceaccb172ed1 (patch) | |
tree | 91775ba142a936df32ea4e1043a8542b6b19ee1d /sys/kern | |
parent | 4085f3d381be5467257661f2475af515a6da00aa (diff) |
Implement an idle timeout for the socket splicing. A new `sp_idle'
field of the `splice' structure can be used to specify a period of
inactivity after which splicing will be dissolved. ETIMEDOUT error
retrieved with a SO_ERROR indicates the idle timeout expiration.
With comments from and OK bluhm.
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/uipc_socket.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index fc8811726de..1532dcb9107 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket.c,v 1.93 2011/07/02 22:20:08 nicm Exp $ */ +/* $OpenBSD: uipc_socket.c,v 1.94 2011/07/04 00:33:36 mikeb Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* @@ -51,9 +51,10 @@ #include <net/route.h> #include <sys/pool.h> -int sosplice(struct socket *, int, off_t); +int sosplice(struct socket *, int, off_t, struct timeval *); void sounsplice(struct socket *, struct socket *, int); int somove(struct socket *, int); +void soidle(void *); void filt_sordetach(struct knote *kn); int filt_soread(struct knote *kn, long hint); @@ -992,7 +993,7 @@ sorflush(struct socket *so) #ifdef SOCKET_SPLICE int -sosplice(struct socket *so, int fd, off_t max) +sosplice(struct socket *so, int fd, off_t max, struct timeval *tv) { struct file *fp; struct socket *sosp; @@ -1017,6 +1018,9 @@ sosplice(struct socket *so, int fd, off_t max) if (max && max < 0) return (EINVAL); + if (tv && (tv->tv_sec < 0 || tv->tv_usec < 0)) + return (EINVAL); + /* Find sosp, the drain socket where data will be spliced into. */ if ((error = getsock(curproc->p_fd, fd, &fp)) != 0) return (error); @@ -1057,6 +1061,11 @@ sosplice(struct socket *so, int fd, off_t max) sosp->so_spliceback = so; so->so_splicelen = 0; so->so_splicemax = max; + if (tv) + so->so_idletv = *tv; + else + timerclear(&so->so_idletv); + timeout_set(&so->so_idleto, soidle, so); /* * To prevent softnet interrupt from calling somove() while @@ -1080,6 +1089,7 @@ sounsplice(struct socket *so, struct socket *sosp, int wakeup) { splsoftassert(IPL_SOFTNET); + timeout_del(&so->so_idleto); sosp->so_snd.sb_flags &= ~SB_SPLICE; so->so_rcv.sb_flags &= ~SB_SPLICE; so->so_splice = sosp->so_spliceback = NULL; @@ -1275,6 +1285,8 @@ somove(struct socket *so, int wait) sounsplice(so, sosp, 1); return (0); } + if (timerisset(&so->so_idletv)) + timeout_add_tv(&so->so_idleto, &so->so_idletv); return (1); } @@ -1295,6 +1307,18 @@ sowwakeup(struct socket *so) (void) somove(so->so_spliceback, M_DONTWAIT); _sowwakeup(so); } + +void +soidle(void *arg) +{ + struct socket *so = arg; + int s; + + s = splsoftnet(); + so->so_error = ETIMEDOUT; + sounsplice(so, so->so_splice, 1); + splx(s); +} #endif /* SOCKET_SPLICE */ int @@ -1452,16 +1476,17 @@ sosetopt(struct socket *so, int level, int optname, struct mbuf *m0) #ifdef SOCKET_SPLICE case SO_SPLICE: if (m == NULL) { - error = sosplice(so, -1, 0); + error = sosplice(so, -1, 0, NULL); } else if (m->m_len < sizeof(int)) { error = EINVAL; goto bad; } else if (m->m_len < sizeof(struct splice)) { - error = sosplice(so, *mtod(m, int *), 0); + error = sosplice(so, *mtod(m, int *), 0, NULL); } else { error = sosplice(so, mtod(m, struct splice *)->sp_fd, - mtod(m, struct splice *)->sp_max); + mtod(m, struct splice *)->sp_max, + &mtod(m, struct splice *)->sp_idle); } break; #endif /* SOCKET_SPLICE */ |