summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2016-09-13 08:32:44 +0000
committermpi <mpi@openbsd.org>2016-09-13 08:32:44 +0000
commitc4a692e11cc0acf8537c55240cc1a62ec965211e (patch)
tree3a1b8be8f4581a80626d3dd98169b351eb940038
parentSplit if_linkstate_task() in two to avoid SPL recursion when the (diff)
downloadwireguard-openbsd-c4a692e11cc0acf8537c55240cc1a62ec965211e.tar.xz
wireguard-openbsd-c4a692e11cc0acf8537c55240cc1a62ec965211e.zip
Introduce rwsleep(9), an equivalent to msleep(9) but for code protected
by a write lock. ok guenther@, vgross@
-rw-r--r--share/man/man9/tsleep.933
-rw-r--r--sys/kern/kern_synch.c36
-rw-r--r--sys/sys/systm.h4
3 files changed, 65 insertions, 8 deletions
diff --git a/share/man/man9/tsleep.9 b/share/man/man9/tsleep.9
index 391421e86a2..be5cf84d18d 100644
--- a/share/man/man9/tsleep.9
+++ b/share/man/man9/tsleep.9
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tsleep.9,v 1.10 2015/09/14 15:14:55 schwarze Exp $
+.\" $OpenBSD: tsleep.9,v 1.11 2016/09/13 08:32:44 mpi Exp $
.\" $NetBSD: sleep.9,v 1.11 1999/03/24 06:15:12 mycroft Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -28,12 +28,13 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: September 14 2015 $
+.Dd $Mdocdate: September 13 2016 $
.Dt TSLEEP 9
.Os
.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
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index 4e87d06b64b..beeefe06458 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_synch.c,v 1.134 2016/09/03 15:06:06 akfaew Exp $ */
+/* $OpenBSD: kern_synch.c,v 1.135 2016/09/13 08:32:44 mpi Exp $ */
/* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
/*
@@ -226,6 +226,40 @@ msleep(const volatile void *ident, struct mutex *mtx, int priority,
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)
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 374805b91b8..36a2e83fd22 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: systm.h,v 1.116 2016/09/04 09:22:29 mpi Exp $ */
+/* $OpenBSD: systm.h,v 1.117 2016/09/13 08:32:44 mpi Exp $ */
/* $NetBSD: systm.h,v 1.50 1996/06/09 04:55:09 briggs Exp $ */
/*-
@@ -246,11 +246,13 @@ int sleep_finish_signal(struct sleep_state *);
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 *);