Instead of using the old flags and tsleep style lock, switch to rwlock in
sblock. That's what it's for. More legible, and as a bonus, MP safer.
Index: kern/uipc_socket2.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket2.c,v
retrieving revision 1.63
diff -u -p -r1.63 uipc_socket2.c
--- kern/uipc_socket2.c 6 Oct 2015 14:38:32 -0000 1.63
+++ kern/uipc_socket2.c 23 Jun 2016 16:38:41 -0000
@@ -185,6 +185,9 @@ sonewconn(struct socket *head, int conns
so->so_rcv.sb_lowat = head->so_rcv.sb_lowat;
so->so_rcv.sb_timeo = head->so_rcv.sb_timeo;
+ rw_init(&so->so_rcv.sb_rwl, "sbsndl");
+ rw_init(&so->so_snd.sb_rwl, "sbrcvl");
+
soqinsque(head, so, soqueue);
if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, NULL, NULL, NULL,
curproc)) {
@@ -286,22 +289,24 @@ sbwait(struct sockbuf *sb)
* return any error returned from sleep (EINTR).
*/
int
-sb_lock(struct sockbuf *sb)
+sblock(struct sockbuf *sb, int wf)
{
int error;
- while (sb->sb_flags & SB_LOCK) {
- sb->sb_flags |= SB_WANT;
- error = tsleep(&sb->sb_flags,
- (sb->sb_flags & SB_NOINTR) ?
- PSOCK : PSOCK|PCATCH, "netlck", 0);
- if (error)
- return (error);
- }
- sb->sb_flags |= SB_LOCK;
- return (0);
+ error = rw_enter(&sb->sb_rwl, RW_WRITE |
+ (sb->sb_flags & SB_NOINTR ? 0 : RW_INTR) |
+ (wf == M_WAITOK ? 0 : RW_NOSLEEP));
+
+ return (error);
}
+void
+sbunlock(struct sockbuf *sb)
+{
+ rw_exit(&sb->sb_rwl);
+}
+
+
/*
* Wakeup processes waiting on a socket buffer.
* Do asynchronous notification via SIGIO
@@ -827,7 +832,7 @@ void
sbflush(struct sockbuf *sb)
{
- KASSERT((sb->sb_flags & SB_LOCK) == 0);
+ rw_assert_unlocked(&sb->sb_rwl);
while (sb->sb_mbcnt)
sbdrop(sb, (int)sb->sb_cc);
Index: sys/socketvar.h
===================================================================
RCS file: /cvs/src/sys/sys/socketvar.h,v
retrieving revision 1.60
diff -u -p -r1.60 socketvar.h
--- sys/socketvar.h 25 Feb 2016 07:39:09 -0000 1.60
+++ sys/socketvar.h 23 Jun 2016 16:40:56 -0000
@@ -108,13 +108,12 @@ struct socket {
struct mbuf *sb_lastrecord;/* first mbuf of last record in
socket buffer */
struct selinfo sb_sel; /* process selecting read/write */
+ struct rwlock sb_rwl; /* lock */
int sb_flagsintr; /* flags, changed during interrupt */
short sb_flags; /* flags, see below */
u_short sb_timeo; /* timeout for read/write */
} so_rcv, so_snd;
#define SB_MAX (256*1024) /* default for max chars in
sockbuf */
-#define SB_LOCK 0x01 /* lock on data queue */
-#define SB_WANT 0x02 /* someone is waiting to lock */
#define SB_WAIT 0x04 /* someone is waiting for
data/space */
#define SB_SEL 0x08 /* someone is selecting */
#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */
@@ -218,18 +217,10 @@ struct socket {
* Unless SB_NOINTR is set on sockbuf, sleep is interruptible.
* Returns error without lock if sleep is interrupted.
*/
-#define sblock(sb, wf) ((sb)->sb_flags & SB_LOCK ? \
- (((wf) == M_WAITOK) ? sb_lock(sb) : EWOULDBLOCK) : \
- ((sb)->sb_flags |= SB_LOCK, 0))
+int sblock(struct sockbuf *sb, int wf);
/* release lock on sockbuf sb */
-#define sbunlock(sb) do {
\
- (sb)->sb_flags &= ~SB_LOCK; \
- if ((sb)->sb_flags & SB_WANT) { \
- (sb)->sb_flags &= ~SB_WANT; \
- wakeup((caddr_t)&(sb)->sb_flags); \
- } \
-} while (/* CONSTCOND */ 0)
+void sbunlock(struct sockbuf *sb);
#define SB_EMPTY_FIXUP(sb) do {
\
if ((sb)->sb_mb == NULL) { \