> Date: Sun, 13 Mar 2022 12:47:13 +0000 > From: Visa Hankala <v...@hankala.org> > > This makes the refcnt implementation issue memory barriers when > releasing references, splitting memory activity cleanly into preceding > and succeeding stages around refcnt 1->0 transition. > > I think the while loop could be optimized a little by re-reading > r->r_refs just after sleep_finish(). That should avoid re-entering > the SCHED_LOCK()'ed section. However, that is not part of this patch. > > OK?
Under what circumstances does memory ordering matter for these interfaces? > Index: share/man/man9/refcnt_init.9 > =================================================================== > RCS file: src/share/man/man9/refcnt_init.9,v > retrieving revision 1.1 > diff -u -p -r1.1 refcnt_init.9 > --- share/man/man9/refcnt_init.9 11 Sep 2015 19:13:22 -0000 1.1 > +++ share/man/man9/refcnt_init.9 13 Mar 2022 11:40:12 -0000 > @@ -68,6 +68,18 @@ There may only be one caller to > per refcnt > .Fa r . > .Pp > +.Fn refcnt_rele , > +.Fn refcnt_rele_wake > +and > +.Fn refcnt_finalize > +provide release memory ordering. > +The caller's prior memory loads and stores are completed > +before the reference is released. > +The functions provide acquire memory ordering after all the references > +have been released. > +This ensures the object's destructor sees all updates > +done during the lifetime of the object. > +.Pp > .Fn REFCNT_INITIALIZER > initialises a declaration of a refcnt to 1. > .Sh CONTEXT > Index: sys/kern/kern_synch.c > =================================================================== > RCS file: src/sys/kern/kern_synch.c,v > retrieving revision 1.183 > diff -u -p -r1.183 kern_synch.c > --- sys/kern/kern_synch.c 10 Mar 2022 15:21:08 -0000 1.183 > +++ sys/kern/kern_synch.c 13 Mar 2022 11:40:13 -0000 > @@ -825,10 +825,16 @@ refcnt_rele(struct refcnt *r) > { > u_int refcnt; > > + membar_exit_before_atomic(); > refcnt = atomic_dec_int_nv(&r->r_refs); > KASSERT(refcnt != ~0); > > - return (refcnt == 0); > + if (refcnt == 0) { > + membar_enter_after_atomic(); > + return (1); > + } > + > + return (0); > } > > void > @@ -844,12 +850,20 @@ refcnt_finalize(struct refcnt *r, const > struct sleep_state sls; > u_int refcnt; > > + membar_exit_before_atomic(); > refcnt = atomic_dec_int_nv(&r->r_refs); > + if (refcnt == 0) { > + membar_enter_after_atomic(); > + return; > + } > + > while (refcnt) { > sleep_setup(&sls, r, PWAIT, wmesg, 0); > refcnt = atomic_load_int(&r->r_refs); > sleep_finish(&sls, refcnt); > } > + /* Provide acquire ordering after seeing refcnt == 0. */ > + membar_sync(); > } > > void > >