diff options
author | rwatson <rwatson@FreeBSD.org> | 2007-05-03 14:42:42 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2007-05-03 14:42:42 +0000 |
commit | 20848234d96d64f1050c92166ebffc88afcc2fae (patch) | |
tree | 1bcae9ed15171271aa6fc97f1e539335630da9e9 /sys/kern/uipc_sockbuf.c | |
parent | 9bb125a79a492945d63a1509b80173d7740b1411 (diff) | |
download | FreeBSD-src-20848234d96d64f1050c92166ebffc88afcc2fae.zip FreeBSD-src-20848234d96d64f1050c92166ebffc88afcc2fae.tar.gz |
sblock() implements a sleep lock by interlocking SB_WANT and SB_LOCK flags
on each socket buffer with the socket buffer's mutex. This sleep lock is
used to serialize I/O on sockets in order to prevent I/O interlacing.
This change replaces the custom sleep lock with an sx(9) lock, which
results in marginally better performance, better handling of contention
during simultaneous socket I/O across multiple threads, and a cleaner
separation between the different layers of locking in socket buffers.
Specifically, the socket buffer mutex is now solely responsible for
serializing simultaneous operation on the socket buffer data structure,
and not for I/O serialization.
While here, fix two historic bugs:
(1) a bug allowing I/O to be occasionally interlaced during long I/O
operations (discovere by Isilon).
(2) a bug in which failed non-blocking acquisition of the socket buffer
I/O serialization lock might be ignored (discovered by sam).
SCTP portion of this patch submitted by rrs.
Diffstat (limited to 'sys/kern/uipc_sockbuf.c')
-rw-r--r-- | sys/kern/uipc_sockbuf.c | 35 |
1 files changed, 16 insertions, 19 deletions
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 381632c..a35a2c6 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/signalvar.h> #include <sys/socket.h> #include <sys/socketvar.h> +#include <sys/sx.h> #include <sys/sysctl.h> /* @@ -132,27 +133,25 @@ sbwait(struct sockbuf *sb) sb->sb_timeo)); } -/* - * Lock a sockbuf already known to be locked; return any error returned from - * sleep (EINTR). - */ int -sb_lock(struct sockbuf *sb) +sblock(struct sockbuf *sb, int flags) { - int error; - SOCKBUF_LOCK_ASSERT(sb); - - while (sb->sb_flags & SB_LOCK) { - sb->sb_flags |= SB_WANT; - error = msleep(&sb->sb_flags, &sb->sb_mtx, - (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH, - "sblock", 0); - if (error) - return (error); + if (flags == M_WAITOK) { + sx_xlock(&sb->sb_sx); + return (0); + } else { + if (sx_try_xlock(&sb->sb_sx) == 0) + return (EWOULDBLOCK); + return (0); } - sb->sb_flags |= SB_LOCK; - return (0); +} + +void +sbunlock(struct sockbuf *sb) +{ + + sx_xunlock(&sb->sb_sx); } /* @@ -797,8 +796,6 @@ static void sbflush_internal(struct sockbuf *sb) { - if (sb->sb_flags & SB_LOCK) - panic("sbflush_internal: locked"); while (sb->sb_mbcnt) { /* * Don't call sbdrop(sb, 0) if the leading mbuf is non-empty: |