refcount_release_take_##lock
Mateusz Guzik
mjguzik at gmail.com
Sat Oct 25 18:44:54 UTC 2014
The following idiom is used here and there:
int old;
old = obj->ref;
if (old > 1 && atomic_cmpset_int(&obj->ref, old, old -1))
return;
lock(&something);
if (refcount_release(&obj->ref) == 0) {
unlock(&something);
return;
}
free up
unlock(&something);
==========
I decided to implement it as a common function.
We have only refcount.h and I didn't want to bloat all including code
with additional definitions and as such I came up with a macro that has
to be used in .c file and that will define appropriate inline func.
I'm definitely looking for better names for REFCOUNT_RELEASE_TAKE_USE_
macro, assuming it has to stay.
Comments?
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index f8ae0e6..cf16344 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -81,6 +81,8 @@ __FBSDID("$FreeBSD$");
MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
static MALLOC_DEFINE(M_PRISON_RACCT, "prison_racct", "Prison racct structures");
+REFCOUNT_RELEASE_TAKE_USE_SX;
+
/* Keep struct prison prison0 and some code in kern_jail_set() readable. */
#ifdef INET
#ifdef INET6
@@ -4466,15 +4468,12 @@ prison_racct_free_locked(struct prison_racct *prr)
void
prison_racct_free(struct prison_racct *prr)
{
- int old;
sx_assert(&allprison_lock, SA_UNLOCKED);
- old = prr->prr_refcount;
- if (old > 1 && atomic_cmpset_int(&prr->prr_refcount, old, old - 1))
+ if (refcount_release_take_sx(&prr->prr_refcount, &allprison_lock) == 0)
return;
- sx_xlock(&allprison_lock);
prison_racct_free_locked(prr);
sx_xunlock(&allprison_lock);
}
diff --git a/sys/kern/kern_loginclass.c b/sys/kern/kern_loginclass.c
index b20f60b..8cc4b40 100644
--- a/sys/kern/kern_loginclass.c
+++ b/sys/kern/kern_loginclass.c
@@ -70,6 +70,7 @@ LIST_HEAD(, loginclass) loginclasses;
*/
static struct mtx loginclasses_lock;
MTX_SYSINIT(loginclasses_init, &loginclasses_lock, "loginclasses lock", MTX_DEF);
+REFCOUNT_RELEASE_TAKE_USE_MTX;
void
loginclass_hold(struct loginclass *lc)
@@ -81,22 +82,14 @@ loginclass_hold(struct loginclass *lc)
void
loginclass_free(struct loginclass *lc)
{
- int old;
- old = lc->lc_refcount;
- if (old > 1 && atomic_cmpset_int(&lc->lc_refcount, old, old - 1))
+ if (refcount_release_take_mtx(&lc->lc_refcount, &loginclasses_lock) == 0)
return;
- mtx_lock(&loginclasses_lock);
- if (refcount_release(&lc->lc_refcount)) {
- racct_destroy(&lc->lc_racct);
- LIST_REMOVE(lc, lc_next);
- mtx_unlock(&loginclasses_lock);
- free(lc, M_LOGINCLASS);
-
- return;
- }
+ racct_destroy(&lc->lc_racct);
+ LIST_REMOVE(lc, lc_next);
mtx_unlock(&loginclasses_lock);
+ free(lc, M_LOGINCLASS);
}
/*
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c
index f4914fa..efbaa87 100644
--- a/sys/kern/kern_resource.c
+++ b/sys/kern/kern_resource.c
@@ -71,6 +71,7 @@ static MALLOC_DEFINE(M_PLIMIT, "plimit", "plimit structures");
static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures");
#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
static struct rwlock uihashtbl_lock;
+REFCOUNT_RELEASE_TAKE_USE_RWLOCK;
static LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
static u_long uihash; /* size of hash table - 1 */
@@ -1327,37 +1328,24 @@ void
uifree(uip)
struct uidinfo *uip;
{
- int old;
- /* Prepare for optimal case. */
- old = uip->ui_ref;
- if (old > 1 && atomic_cmpset_int(&uip->ui_ref, old, old - 1))
+ if (refcount_release_take_rwlock(&uip->ui_ref, &uihashtbl_lock) == 0)
return;
- /* Prepare for suboptimal case. */
- rw_wlock(&uihashtbl_lock);
- if (refcount_release(&uip->ui_ref)) {
- racct_destroy(&uip->ui_racct);
- LIST_REMOVE(uip, ui_hash);
- rw_wunlock(&uihashtbl_lock);
- if (uip->ui_sbsize != 0)
- printf("freeing uidinfo: uid = %d, sbsize = %ld\n",
- uip->ui_uid, uip->ui_sbsize);
- if (uip->ui_proccnt != 0)
- printf("freeing uidinfo: uid = %d, proccnt = %ld\n",
- uip->ui_uid, uip->ui_proccnt);
- if (uip->ui_vmsize != 0)
- printf("freeing uidinfo: uid = %d, swapuse = %lld\n",
- uip->ui_uid, (unsigned long long)uip->ui_vmsize);
- mtx_destroy(&uip->ui_vmsize_mtx);
- free(uip, M_UIDINFO);
- return;
- }
- /*
- * Someone added a reference between atomic_cmpset_int() and
- * rw_wlock(&uihashtbl_lock).
- */
+ racct_destroy(&uip->ui_racct);
+ LIST_REMOVE(uip, ui_hash);
rw_wunlock(&uihashtbl_lock);
+ if (uip->ui_sbsize != 0)
+ printf("freeing uidinfo: uid = %d, sbsize = %ld\n",
+ uip->ui_uid, uip->ui_sbsize);
+ if (uip->ui_proccnt != 0)
+ printf("freeing uidinfo: uid = %d, proccnt = %ld\n",
+ uip->ui_uid, uip->ui_proccnt);
+ if (uip->ui_vmsize != 0)
+ printf("freeing uidinfo: uid = %d, swapuse = %lld\n",
+ uip->ui_uid, (unsigned long long)uip->ui_vmsize);
+ mtx_destroy(&uip->ui_vmsize_mtx);
+ free(uip, M_UIDINFO);
}
void
diff --git a/sys/sys/refcount.h b/sys/sys/refcount.h
index 4611664..9dff576 100644
--- a/sys/sys/refcount.h
+++ b/sys/sys/refcount.h
@@ -64,4 +64,29 @@ refcount_release(volatile u_int *count)
return (old == 1);
}
+#define REFCOUNT_RELEASE_DEFINE(NAME, TYPE, LOCK, UNLOCK) \
+static __inline int \
+refcount_release_take_##NAME(volatile u_int *count, TYPE *v) \
+{ \
+ u_int old; \
+ \
+ old = *count; \
+ if (old > 1 && atomic_cmpset_int(count, old, old - 1)) \
+ return (0); \
+ LOCK(v); \
+ if (refcount_release(count)) \
+ return (1); \
+ UNLOCK(v); \
+ return (0); \
+}
+
+#define REFCOUNT_RELEASE_TAKE_USE_MTX \
+ REFCOUNT_RELEASE_DEFINE(mtx, struct mtx, mtx_lock, mtx_unlock);
+#define REFCOUNT_RELEASE_TAKE_USE_RWLOCK \
+ REFCOUNT_RELEASE_DEFINE(rwlock, struct rwlock, rw_wlock, rw_wunlock);
+#define REFCOUNT_RELEASE_TAKE_USE_RMLOCK \
+ REFCOUNT_RELEASE_DEFINE(rmlock, struct rmlock, rm_wlock, rm_wunlock);
+#define REFCOUNT_RELEASE_TAKE_USE_SX \
+ REFCOUNT_RELEASE_DEFINE(sx, struct sx, sx_xlock, sx_xunlock);
+
#endif /* ! __SYS_REFCOUNT_H__ */
More information about the freebsd-arch
mailing list