From owner-freebsd-arch@FreeBSD.ORG Fri Mar 13 23:16:14 2015 Return-Path: Delivered-To: freebsd-arch@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id A3582D74; Fri, 13 Mar 2015 23:16:14 +0000 (UTC) Received: from mail-wi0-x236.google.com (mail-wi0-x236.google.com [IPv6:2a00:1450:400c:c05::236]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority G2" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 2D7C375E; Fri, 13 Mar 2015 23:16:14 +0000 (UTC) Received: by wiwl15 with SMTP id l15so827685wiw.1; Fri, 13 Mar 2015 16:16:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:to:cc:subject:message-id:references:mime-version :content-type:content-disposition:in-reply-to:user-agent; bh=X6U98Pj1Ppstv0C7R4uECUDYz3qORZkSUSCfmRwLXRQ=; b=oVekECIV9z3rx/l94eFV2I1995nRH4ZseDOkEedi8+HzY3cVnc9SIjW2zvioYrlfZu YJGDIc7l/kvGxWWkP5DIYQD4CTA1eAXFwNyjnOXGQmv2TM4Asn4neTOSQG+rcO+/o/vH yHbSop4hTxu3n8cqtEGWEF3GRvgxeNKVjmohLrR1esay25/stJU9bBCFlZRiJeDCXx1h lKowmVBDu3V5KlVfdf7JOBSiuN74YdynEX1urFIDWgG7/0UAqrFM3KVbOgIghILx5axR AqXgTSgoTArXc1Xuz5lPFm9+uBr++lkQlE2QM1bhi/kbw19QzqBIIM3TBIa3eW7Nm6XP sG9Q== X-Received: by 10.180.106.103 with SMTP id gt7mr145089650wib.59.1426288572332; Fri, 13 Mar 2015 16:16:12 -0700 (PDT) Received: from dft-labs.eu (n1x0n-1-pt.tunnel.tserv5.lon1.ipv6.he.net. [2001:470:1f08:1f7::2]) by mx.google.com with ESMTPSA id at4sm4711922wjc.16.2015.03.13.16.16.09 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 13 Mar 2015 16:16:10 -0700 (PDT) Date: Sat, 14 Mar 2015 00:16:07 +0100 From: Mateusz Guzik To: John Baldwin Subject: Re: refcount_release_take_##lock Message-ID: <20150313231607.GB32157@dft-labs.eu> References: <20141025184448.GA19066@dft-labs.eu> <201410281413.58414.jhb@freebsd.org> <20141028193404.GB12014@dft-labs.eu> <201411111427.15407.jhb@freebsd.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <201411111427.15407.jhb@freebsd.org> User-Agent: Mutt/1.5.21 (2010-09-15) Cc: John-Mark Gurney , freebsd-arch@freebsd.org X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 13 Mar 2015 23:16:14 -0000 In the meantime I wrote a new version. Apart from locking-handling primitives this time we get refcount_acquire_if_greater and refcount_release_if_greater helpers. This diff contains an example usage for kern_resource.c which will be committed separately. diff --git a/share/man/man9/refcount.9 b/share/man/man9/refcount.9 index b3c8d7f..1b66a9d 100644 --- a/share/man/man9/refcount.9 +++ b/share/man/man9/refcount.9 @@ -26,14 +26,20 @@ .\" .\" $FreeBSD$ .\" -.Dd January 20, 2009 +.Dd March 13, 2015 .Dt REFCOUNT 9 .Os .Sh NAME .Nm refcount , .Nm refcount_init , .Nm refcount_acquire , -.Nm refcount_release +.Nm refcount_release , +.Nm refcount_acquire_if_greater , +.Nm refcount_release_if_greater , +.Nm refcount_release_lock_mtx , +.Nm refcount_release_lock_rmlock , +.Nm refcount_release_lock_rwlock , +.Nm refcount_release_lock_sx .Nd manage a simple reference counter .Sh SYNOPSIS .In sys/param.h @@ -44,6 +50,22 @@ .Fn refcount_acquire "volatile u_int *count" .Ft int .Fn refcount_release "volatile u_int *count" +.Ft int +.Fn refcount_acquire_if_greater "volatile u_int *count" "u_int value" +.Ft int +.Fn refcount_release_if_greater "volatile u_int *count" "u_int value" +.In sys/lock.h + +.In sys/mutex.h +.Ft int +.Fn refcount_release_lock_mtx "volatile u_int *count, struct mtx *lock" +.In sys/rmlock.h +.Ft int +.Fn refcount_release_lock_rmlock "volatile u_int *count, struct rmlock *lock" +.In sys/rwlock.h +.Fn refcount_release_lock_rwlock "volatile u_int *count, struct rwlock *lock" +.In sys/sx.h +.Fn refcount_release_lock_sx "volatile u_int *count, struct sx *lock" .Sh DESCRIPTION The .Nm @@ -77,6 +99,52 @@ The function returns a non-zero value if the reference being released was the last reference; otherwise, it returns zero. .Pp +The +.Fn refcount_acquire_if_greater +function works like +.Fn refcount_acquire +with the exception that the counter value has to be +greater than the one provided as an argument. +.Pp +The +.Fn refcount_release_if_greater +function works like +.Fn refcount_release +with the exception that the counter value has to be +greater than the one provided as an argument. +.Pp +The +.Fn refcount_release_lock_mtx +function is used to atomically release an existing reference and acquire the +lock. +The function returns with the lock held and a non-zero value if the reference +being released was the last reference; +otherwise, it returns zero and the lock is not held. +.Pp +The +.Fn refcount_release_lock_rmlock +function is used to atomically release an existing reference and acquire the +lock. +The function returns with the lock held and a non-zero value if the reference +being released was the last reference; +otherwise, it returns zero and the lock is not held. +.Pp +The +.Fn refcount_release_lock_rwlock +function is used to atomically release an existing reference and acquire the +lock. +The function returns with the lock held and a non-zero value if the reference +being released was the last reference; +otherwise, it returns zero and the lock is not held. +.Pp +The +.Fn refcount_release_lock_sx +function is used to atomically release an existing reference and acquire the +lock. +The function returns with the lock held and a non-zero value if the reference +being released was the last reference; +otherwise, it returns zero and the lock is not held. +.Pp Note that these routines do not provide any inter-CPU synchronization, data protection, or memory ordering guarantees except for managing the counter. @@ -91,6 +159,42 @@ The .Nm refcount_release function returns non-zero when releasing the last reference and zero when releasing any other reference. +.Pp +The +.Nm refcount_acquire_if_greater +function returns non-zero if the reference was acquired and zero otherwise. +.Pp +The +.Nm refcount_release_if_greater +function returns non-zero if the reference was released and zero otherwise. +.Pp +The +.Nm refcount_release_lock_mtx +function returns non-zero if the reference was released and zero otherwise. +.Pp +The +.Nm refcount_release_lock_rmlock +function returns non-zero if the reference was released and zero otherwise. +.Pp +The +.Nm refcount_release_lock_rwlock +function returns non-zero if the reference was released and zero otherwise. +.Pp +The +.Nm refcount_release_lock_sx +function returns non-zero if the reference was released and zero otherwise. .Sh HISTORY -These functions were introduced in +.Fn refcount_acquire +and +.Fn refcount_release +functions were introduced in .Fx 6.0 . +.Pp +.Fn refcount_acquire_if_greater , +.Fn refcount_release_if_greater , +.Fn refcount_release_lock_mtx , +.Fn refcount_release_lock_rmlock , +.Fn refcount_release_lock_rwlock , +.Fn refcount_release_lock_sx +functions were introduced in +.Fx 11 . diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 56b598f..6489538 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -1303,20 +1303,10 @@ uihold(struct uidinfo *uip) void uifree(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_lock_rwlock(&uip->ui_ref, &uihashtbl_lock)) return; - /* Prepare for suboptimal case. */ - rw_wlock(&uihashtbl_lock); - if (refcount_release(&uip->ui_ref) == 0) { - rw_wunlock(&uihashtbl_lock); - return; - } - racct_destroy(&uip->ui_racct); LIST_REMOVE(uip, ui_hash); rw_wunlock(&uihashtbl_lock); diff --git a/sys/sys/refcount.h b/sys/sys/refcount.h index 4611664..b6ddb90 100644 --- a/sys/sys/refcount.h +++ b/sys/sys/refcount.h @@ -64,4 +64,64 @@ refcount_release(volatile u_int *count) return (old == 1); } +static __inline int +refcount_acquire_if_greater(volatile u_int *count, int val) +{ + int old; + + for (;;) { + old = *count; + if (old <= val) + return (0); + if (atomic_cmpset_int(count, old, old + 1)) + return (1); + } +} + +static __inline int +refcount_release_if_greater(volatile u_int *count, int val) +{ + int old; + + for (;;) { + old = *count; + if (old <= val) + return (0); + if (atomic_cmpset_int(count, old, old - 1)) + return (1); + } +} + +#define _refcount_release_lock(count, lock, TYPE, LOCK_OP, UNLOCK_OP) \ +({ \ + TYPE *__lock; \ + volatile u_int *__cp; \ + int __ret; \ + \ + __lock = (lock); \ + __cp = (count); \ + \ + if (refcount_release_if_greater(__cp, 1)) { \ + __ret = 0; \ + } else { \ + LOCK_OP(__lock); \ + if (refcount_release(__cp)) { \ + __ret = 1; \ + } else { \ + UNLOCK_OP(__lock); \ + __ret = 0; \ + } \ + } \ + __ret; \ +}) + +#define refcount_release_lock_mtx(count, lock) \ + _refcount_release_lock(count, lock, struct mtx, mtx_lock, mtx_unlock) +#define refcount_release_lock_rmlock(count, lock) \ + _refcount_release_lock(count, lock, struct rmlock, rm_wlock, rm_wunlock) +#define refcount_release_lock_rwlock(count, lock) \ + _refcount_release_lock(count, lock, struct rwlock, rw_wlock, rw_wunlock) +#define refcount_release_lock_sx(count, lock) \ + _refcount_release_lock(count, lock, struct sx, sx_xlock, sx_xunlock) + #endif /* ! __SYS_REFCOUNT_H__ */ -- Mateusz Guzik