Index: sys/refcnt.h =================================================================== RCS file: sys/refcnt.h diff -N sys/refcnt.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/refcnt.h 11 Sep 2015 14:12:15 -0000 @@ -0,0 +1,41 @@ +/* $OpenBSD: srp.h,v 1.3 2015/09/09 11:21:51 dlg Exp $ */ + +/* + * Copyright (c) 2015 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SYS_REFCNT_H_ +#define _SYS_REFCNT_H_ + +#include + +struct refcnt { + u_int refs; +}; + +#ifdef _KERNEL + +#define REFCNT_INITIALIZER() { 1 } + +#define refcnt_init(_r) do { (_r)->refs = 1; } while (0) +#define refcnt_take(_r) atomic_inc_int(&(_r)->refs) +#define refcnt_last(_r) (atomic_dec_int_nv(&(_r)->refs) == 0) + +void refcnt_rele(struct refcnt *); +void refcnt_finalize(struct refcnt *); + +#endif /* _KERNEL */ + +#endif /* _SYS_REFCNT_H_ */ Index: sys/srp.h =================================================================== RCS file: /cvs/src/sys/sys/srp.h,v retrieving revision 1.3 diff -u -p -r1.3 srp.h --- sys/srp.h 9 Sep 2015 11:21:51 -0000 1.3 +++ sys/srp.h 11 Sep 2015 14:12:15 -0000 @@ -19,6 +19,8 @@ #ifndef _SYS_SRP_H_ #define _SYS_SRP_H_ +#include + struct srp { void *ref; }; @@ -33,13 +35,13 @@ struct srp_hazard { struct srp_gc { void (*srp_gc_dtor)(void *, void *); void *srp_gc_cookie; - u_int srp_gc_refcount; + struct refcnt srp_gc_refcnt; }; #ifdef _KERNEL #define SRP_INITIALIZER() { NULL } -#define SRP_GC_INITIALIZER(_d, _c) { (_d), (_c), 1 } +#define SRP_GC_INITIALIZER(_d, _c) { (_d), (_c), REFCNT_INITIALIZER() } void srp_startup(void); void srp_gc_init(struct srp_gc *, void (*)(void *, void *), void *); Index: sys/device.h =================================================================== RCS file: /cvs/src/sys/sys/device.h,v retrieving revision 1.51 diff -u -p -r1.51 device.h --- sys/device.h 11 Sep 2015 07:13:58 -0000 1.51 +++ sys/device.h 11 Sep 2015 14:12:15 -0000 @@ -45,6 +45,7 @@ #define _SYS_DEVICE_H_ #include +#include /* * Minimal device structures. @@ -77,7 +78,7 @@ struct device { char dv_xname[16]; /* external name (name + unit) */ struct device *dv_parent; /* pointer to parent device */ int dv_flags; /* misc. flags; see below */ - int dv_ref; /* ref count */ + struct refcnt dv_ref; /* ref count */ }; /* dv_flags */ Index: kern/kern_synch.c =================================================================== RCS file: /cvs/src/sys/kern/kern_synch.c,v retrieving revision 1.122 diff -u -p -r1.122 kern_synch.c --- kern/kern_synch.c 7 Sep 2015 15:38:45 -0000 1.122 +++ kern/kern_synch.c 11 Sep 2015 14:12:15 -0000 @@ -48,6 +48,7 @@ #include #include #include +#include #include @@ -589,4 +590,25 @@ sys___thrwakeup(struct proc *p, void *v, } return (0); +} + +void +refcnt_rele(struct refcnt *r) +{ + if (refcnt_last(r)) + wakeup_one(r); +} + +void +refcnt_finalize(struct refcnt *r) +{ + struct sleep_state sls; + u_int refcnt; + + refcnt = atomic_dec_int_nv(&r->refs); + while (refcnt) { + sleep_setup(&sls, r, PWAIT, "lastref"); + refcnt = r->refs; + sleep_finish(&sls, refcnt); + } } Index: kern/kern_srp.c =================================================================== RCS file: /cvs/src/sys/kern/kern_srp.c,v retrieving revision 1.4 diff -u -p -r1.4 kern_srp.c --- kern/kern_srp.c 11 Sep 2015 14:08:03 -0000 1.4 +++ kern/kern_srp.c 11 Sep 2015 14:12:16 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_srp.c,v 1.4 2015/09/11 14:08:03 dlg Exp $ */ +/* $OpenBSD: kern_srp.c,v 1.3 2015/09/09 11:21:51 dlg Exp $ */ /* * Copyright (c) 2014 Jonathan Matthew @@ -39,7 +39,7 @@ srp_gc_init(struct srp_gc *srp_gc, void { srp_gc->srp_gc_dtor = dtor; srp_gc->srp_gc_cookie = cookie; - srp_gc->srp_gc_refcount = 1; + refcnt_init(&srp_gc->srp_gc_refcnt); } void @@ -48,13 +48,19 @@ srp_init(struct srp *srp) srp->ref = NULL; } +void srpl_refs_init(struct srpl_rc *, void (*)(void *, void *), + void (*)(void *, void *), void *); + +#define SRPL_RC_INITIALIZER(_r, _u, _c) { _r, SRP_GC_INITIALIZER(_u, _c) } + + void srp_update_locked(struct srp_gc *srp_gc, struct srp *srp, void *nv) { void *ov; if (nv != NULL) - atomic_inc_int(&srp_gc->srp_gc_refcount); + refcnt_take(&srp_gc->srp_gc_refcnt); /* * this doesn't have to be as careful as the caller has already @@ -129,8 +135,7 @@ srp_v_dtor(struct srp_gc *srp_gc, void * { (*srp_gc->srp_gc_dtor)(srp_gc->srp_gc_cookie, v); - if (atomic_dec_int_nv(&srp_gc->srp_gc_refcount) == 0) - wakeup_one(&srp_gc->srp_gc_refcount); + refcnt_rele(&srp_gc->srp_gc_refcnt); } void @@ -174,7 +179,7 @@ void srp_update(struct srp_gc *srp_gc, struct srp *srp, void *v) { if (v != NULL) - atomic_inc_int(&srp_gc->srp_gc_refcount); + refcnt_take(&srp_gc->srp_gc_refcnt); v = atomic_swap_ptr(&srp->ref, v); if (v != NULL) @@ -184,15 +189,7 @@ srp_update(struct srp_gc *srp_gc, struct void srp_finalize(struct srp_gc *srp_gc) { - struct sleep_state sls; - u_int r; - - r = atomic_dec_int_nv(&srp_gc->srp_gc_refcount); - while (r > 0) { - sleep_setup(&sls, &srp_gc->srp_gc_refcount, PWAIT, "srpfini"); - r = srp_gc->srp_gc_refcount; - sleep_finish(&sls, r); - } + refcnt_finalize(&srp_gc->srp_gc_refcnt); } static inline void * Index: kern/subr_autoconf.c =================================================================== RCS file: /cvs/src/sys/kern/subr_autoconf.c,v retrieving revision 1.87 diff -u -p -r1.87 subr_autoconf.c --- kern/subr_autoconf.c 14 Mar 2015 03:38:50 -0000 1.87 +++ kern/subr_autoconf.c 11 Sep 2015 14:12:16 -0000 @@ -475,7 +475,7 @@ config_make_softc(struct device *parent, if (cd->cd_devs[dev->dv_unit]) panic("config_make_softc: duplicate %s", dev->dv_xname); - dev->dv_ref = 1; + refcnt_init(&dev->dv_ref); return (dev); } @@ -922,7 +922,7 @@ device_mpath(void) void device_ref(struct device *dv) { - atomic_inc_int(&dv->dv_ref); + refcnt_take(&dv->dv_ref); } /* @@ -937,7 +937,7 @@ device_unref(struct device *dv) { struct cfattach *ca; - if (atomic_dec_int_nv(&dv->dv_ref) == 0) { + if (refcnt_last(&dv->dv_ref)) { ca = dv->dv_cfdata->cf_attach; free(dv, M_DEVBUF, ca->ca_devsize); }