diff options
-rw-r--r-- | share/man/man9/Makefile | 2 | ||||
-rw-r--r-- | share/man/man9/sx.9 | 17 | ||||
-rw-r--r-- | sys/kern/kern_sx.c | 46 | ||||
-rw-r--r-- | sys/sys/sx.h | 4 |
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 /* |