aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man9/Makefile2
-rw-r--r--share/man/man9/sx.917
-rw-r--r--sys/kern/kern_sx.c46
-rw-r--r--sys/sys/sx.h4
4 files changed, 69 insertions, 0 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 8a5a7a6cbaef..977ff583a2c8 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -169,6 +169,8 @@ MLINKS+=sx.9 sx_try_slock.9
MLINKS+=sx.9 sx_try_xlock.9
MLINKS+=sx.9 sx_sunlock.9
MLINKS+=sx.9 sx_xunlock.9
+MLINKS+=sx.9 sx_try_upgrade.9
+MLINKS+=sx.9 sx_downgrade.9
MLINKS+=time.9 boottime.9 time.9 mono_time.9 time.9 runtime.9
MLINKS+=timeout.9 untimeout.9
MLINKS+=timeout.9 callout_handle_init.9 timeout.9 callout_init.9
diff --git a/share/man/man9/sx.9 b/share/man/man9/sx.9
index 2fa030224838..945098946271 100644
--- a/share/man/man9/sx.9
+++ b/share/man/man9/sx.9
@@ -39,6 +39,8 @@
.Nm sx_try_xlock ,
.Nm sx_sunlock ,
.Nm sx_xunlock
+.Nm sx_try_upgrade
+.Nm sx_downgrade
.Nd kernel shared/exclusive lock
.Sh SYNOPSIS
.Fd #include <sys/types.h>
@@ -61,6 +63,10 @@
.Fn sx_sunlock "struct sx *sx"
.Ft void
.Fn sx_xunlock "struct sx *sx"
+.Ft int
+.Fn sx_try_upgrade "struct sx *sx"
+.Ft void
+.Fn sx_downgrade "struct sx *sx"
.Sh DESCRIPTION
Shared/exclusive locks are used to protect data that are read far more often
than they are written.
@@ -91,6 +97,12 @@ or
.Fn sx_try_xlock
and
.Fn sx_xunlock .
+A thread can attempt to upgrade a currently owned shared lock to an exclusive
+lock by calling
+.Fn sx_try_upgrade .
+A thread that owns an exclusive lock can downgrade it to a shared lock by
+calling
+.Fn sx_downgrade .
.Pp
.Fn sx_try_slock
and
@@ -99,6 +111,11 @@ will return 0 if the shared/exclusive lock cannot be acquired immediately;
otherwise the shared/exclusive lock will be acquired and a non-zero value will
be returned.
.Pp
+.Fn sx_try_upgrade
+will return 0 if the shared lock cannot be upgraded to an exclusive lock
+immediately; otherwise the exclusive lock will be acquired and a non-zero value
+will be returned.
+.Pp
A thread may not own a shared lock and an exclusive lock simultaneously;
attempting to do so will result in deadlock.
.Sh SEE ALSO
diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c
index 124ebff295ab..e36dda24eda5 100644
--- a/sys/kern/kern_sx.c
+++ b/sys/kern/kern_sx.c
@@ -245,3 +245,49 @@ _sx_xunlock(struct sx *sx, const char *file, int line)
mtx_unlock(&sx->sx_lock);
}
+
+int
+_sx_try_upgrade(struct sx *sx, const char *file, int line)
+{
+
+ mtx_lock(&sx->sx_lock);
+ _SX_ASSERT_SLOCKED(sx, file, line);
+
+ if (sx->sx_cnt == 1) {
+ WITNESS_UNLOCK(&sx->sx_object, 0, file, line);
+
+ sx->sx_cnt = -1;
+ sx->sx_xholder = curproc;
+
+ LOCK_LOG_TRY("XUPGRADE", &sx->sx_object, 0, 1, file, line);
+ WITNESS_LOCK(&sx->sx_object, LOP_EXCLUSIVE | LOP_TRYLOCK, file,
+ line);
+
+ mtx_unlock(&sx->sx_lock);
+ return (1);
+ } else {
+ LOCK_LOG_TRY("XUPGRADE", &sx->sx_object, 0, 0, file, line);
+ mtx_unlock(&sx->sx_lock);
+ return (0);
+ }
+}
+
+void
+_sx_downgrade(struct sx *sx, const char *file, int line)
+{
+
+ mtx_lock(&sx->sx_lock);
+ _SX_ASSERT_XLOCKED(sx, file, line);
+ MPASS(sx->sx_cnt == -1);
+
+ WITNESS_UNLOCK(&sx->sx_object, LOP_EXCLUSIVE, file, line);
+
+ sx->sx_cnt = 1;
+ if (sx->sx_shrd_wcnt > 0)
+ cv_broadcast(&sx->sx_shrd_cv);
+
+ LOCK_LOG_LOCK("XDOWNGRADE", &sx->sx_object, 0, 0, file, line);
+ WITNESS_LOCK(&sx->sx_object, 0, file, line);
+
+ mtx_unlock(&sx->sx_lock);
+}
diff --git a/sys/sys/sx.h b/sys/sys/sx.h
index f123a3f88402..ee6ac736d653 100644
--- a/sys/sys/sx.h
+++ b/sys/sys/sx.h
@@ -54,6 +54,8 @@ int _sx_try_slock(struct sx *sx, const char *file, int line);
int _sx_try_xlock(struct sx *sx, const char *file, int line);
void _sx_sunlock(struct sx *sx, const char *file, int line);
void _sx_xunlock(struct sx *sx, const char *file, int line);
+int _sx_try_upgrade(struct sx *sx, const char *file, int line);
+void _sx_downgrade(struct sx *sx, const char *file, int line);
#define sx_slock(sx) _sx_slock((sx), __FILE__, __LINE__)
#define sx_xlock(sx) _sx_xlock((sx), __FILE__, __LINE__)
@@ -61,6 +63,8 @@ void _sx_xunlock(struct sx *sx, const char *file, int line);
#define sx_try_xlock(sx) _sx_try_xlock((sx), __FILE__, __LINE__)
#define sx_sunlock(sx) _sx_sunlock((sx), __FILE__, __LINE__)
#define sx_xunlock(sx) _sx_xunlock((sx), __FILE__, __LINE__)
+#define sx_try_upgrade(sx) _sx_try_upgrade((sx), __FILE__, __LINE__)
+#define sx_downgrade(sx) _sx_downgrade((sx), __FILE__, __LINE__)
#ifdef INVARIANTS
/*