introduce rwlock for socketbuf instead of the old flag and tsleep dance.
authortedu <tedu@openbsd.org>
Tue, 28 Jun 2016 14:47:00 +0000 (14:47 +0000)
committertedu <tedu@openbsd.org>
Tue, 28 Jun 2016 14:47:00 +0000 (14:47 +0000)
ok mikeb bluhm

sys/kern/uipc_socket2.c
sys/sys/socketvar.h

index dc8f23c..f86e354 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_socket2.c,v 1.63 2015/10/06 14:38:32 claudio Exp $       */
+/*     $OpenBSD: uipc_socket2.c,v 1.64 2016/06/28 14:47:00 tedu Exp $  */
 /*     $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $       */
 
 /*
@@ -185,6 +185,9 @@ sonewconn(struct socket *head, int connstatus)
        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_lock, "sbsndl");
+       rw_init(&so->so_snd.sb_lock, "sbrcvl");
+
        soqinsque(head, so, soqueue);
        if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, NULL, NULL, NULL,
            curproc)) {
@@ -286,22 +289,26 @@ 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_lock, RW_WRITE |
+           (sb->sb_flags & SB_NOINTR ? 0 : RW_INTR) |
+           (wf == M_WAITOK ? 0 : RW_NOSLEEP));
+
+       if (error == EBUSY)
+               error = EWOULDBLOCK;
+       return (error);
 }
 
+void
+sbunlock(struct sockbuf *sb)
+{
+       rw_exit(&sb->sb_lock);
+}
+
+
 /*
  * Wakeup processes waiting on a socket buffer.
  * Do asynchronous notification via SIGIO
@@ -827,7 +834,7 @@ void
 sbflush(struct sockbuf *sb)
 {
 
-       KASSERT((sb->sb_flags & SB_LOCK) == 0);
+       rw_assert_unlocked(&sb->sb_lock);
 
        while (sb->sb_mbcnt)
                sbdrop(sb, (int)sb->sb_cc);
index bfded71..d0708f3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: socketvar.h,v 1.60 2016/02/25 07:39:09 semarie Exp $  */
+/*     $OpenBSD: socketvar.h,v 1.61 2016/06/28 14:47:00 tedu Exp $     */
 /*     $NetBSD: socketvar.h,v 1.18 1996/02/09 18:25:38 christos Exp $  */
 
 /*-
@@ -35,6 +35,7 @@
 #include <sys/selinfo.h>                       /* for struct selinfo */
 #include <sys/queue.h>
 #include <sys/timeout.h>
+#include <sys/rwlock.h>
 
 #ifndef        _SOCKLEN_T_DEFINED_
 #define        _SOCKLEN_T_DEFINED_
@@ -108,13 +109,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_lock; /* exclusive access from process */
                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 +218,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) {                                      \