I'd like to use a write lock to serialize accesses to ip_output().  This
will be used to guarantee that atomic code sections in the socket layer
stay atomic when the input/forwarding path won't run under KERNEL_LOCK().

For such purpose I'll have to convert some tsleep(9) to an msleep(9)-like
function operating on a write lock.  That's why I'd like to introduce
rwsleep(9).  I did not bother exporting a read variant of this function
since I don't need it for the moment.

ok?

Index: sys/kern/kern_synch.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_synch.c,v
retrieving revision 1.134
diff -u -p -r1.134 kern_synch.c
--- sys/kern/kern_synch.c       3 Sep 2016 15:06:06 -0000       1.134
+++ sys/kern/kern_synch.c       12 Sep 2016 08:41:23 -0000
@@ -226,6 +226,40 @@ msleep(const volatile void *ident, struc
        return (error);
 }
 
+/*
+ * Same as tsleep, but if we have a rwlock provided, then once we've
+ * entered the sleep queue we drop the it. After sleeping we re-lock.
+ */
+int
+rwsleep(const volatile void *ident, struct rwlock *wl, int priority,
+    const char *wmesg, int timo)
+{
+       struct sleep_state sls;
+       int error, error1;
+
+       KASSERT((priority & ~(PRIMASK | PCATCH | PNORELOCK)) == 0);
+       rw_assert_wrlock(wl);
+
+       sleep_setup(&sls, ident, priority, wmesg);
+       sleep_setup_timeout(&sls, timo);
+       sleep_setup_signal(&sls, priority);
+
+       rw_exit_write(wl);
+
+       sleep_finish(&sls, 1);
+       error1 = sleep_finish_timeout(&sls);
+       error = sleep_finish_signal(&sls);
+
+       if ((priority & PNORELOCK) == 0)
+               rw_enter_write(wl);
+
+       /* Signal errors are higher priority than timeouts. */
+       if (error == 0 && error1 != 0)
+               error = error1;
+
+       return (error);
+}
+
 void
 sleep_setup(struct sleep_state *sls, const volatile void *ident, int prio,
     const char *wmesg)
Index: sys/sys/systm.h
===================================================================
RCS file: /cvs/src/sys/sys/systm.h,v
retrieving revision 1.116
diff -u -p -r1.116 systm.h
--- sys/sys/systm.h     4 Sep 2016 09:22:29 -0000       1.116
+++ sys/sys/systm.h     12 Sep 2016 08:35:26 -0000
@@ -246,11 +246,13 @@ int       sleep_finish_signal(struct sleep_sta
 void   sleep_queue_init(void);
 
 struct mutex;
+struct rwlock;
 void    wakeup_n(const volatile void *, int);
 void    wakeup(const volatile void *);
 #define wakeup_one(c) wakeup_n((c), 1)
 int    tsleep(const volatile void *, int, const char *, int);
 int    msleep(const volatile void *, struct mutex *, int,  const char*, int);
+int    rwsleep(const volatile void *, struct rwlock *, int, const char *, int);
 void   yield(void);
 
 void   wdog_register(int (*)(void *, int), void *);
Index: share/man/man9/tsleep.9
===================================================================
RCS file: /cvs/src/share/man/man9/tsleep.9,v
retrieving revision 1.10
diff -u -p -r1.10 tsleep.9
--- share/man/man9/tsleep.9     14 Sep 2015 15:14:55 -0000      1.10
+++ share/man/man9/tsleep.9     12 Sep 2016 08:42:55 -0000
@@ -34,6 +34,7 @@
 .Sh NAME
 .Nm tsleep ,
 .Nm msleep ,
+.Nm rwsleep ,
 .Nm wakeup ,
 .Nm wakeup_n ,
 .Nm wakeup_one
@@ -45,6 +46,8 @@
 .Fn tsleep "void *ident" "int priority" "const char *wmesg" "int timo"
 .Ft int
 .Fn msleep "void *ident" "struct mutex *mtx" "int priority" "const char 
*wmesg" "int timo"
+.Ft int
+.Fn rwsleep "void *ident" "struct rwlock *wl" "int priority" "const char 
*wmesg" "int timo"
 .Ft void
 .Fn wakeup "void *ident"
 .Ft void
@@ -53,9 +56,10 @@
 .Fn wakeup_one "void *ident"
 .Sh DESCRIPTION
 These functions implement voluntary context switching.
-.Fn tsleep
-and
+.Fn tsleep ,
 .Fn msleep
+and
+.Fn rwsleep
 are used throughout the kernel whenever processing in the current context
 cannot continue for any of the following reasons:
 .Bl -bullet -offset indent
@@ -146,6 +150,22 @@ argument.
 .El
 .Pp
 The
+.Fn rwsleep
+function behaves just like
+.Fn tsleep ,
+but takes an additional argument:
+.Bl -tag -width priority
+.It Fa wl
+A write lock that will be unlocked when the process is safely
+on the sleep queue.
+The write lock will be relocked at the end of rwsleep unless the
+.Dv PNORELOCK
+flag is set in the
+.Fa priority
+argument.
+.El
+.Pp
+The
 .Fn wakeup
 function will mark all processes which are currently sleeping on the identifier
 .Fa ident
@@ -173,9 +193,10 @@ except that only
 .Fa count
 or one process, respectively, is marked runnable.
 .Sh RETURN VALUES
-.Fn tsleep
-and
+.Fn tsleep ,
 .Fn msleep
+and
+.Fn rwsleep
 return 0 if they return as a result of a
 .Fn wakeup .
 If they return as a result of a signal, the return value is

Reply via email to