> Date: Sun, 13 Mar 2022 12:47:13 +0000
> From: Visa Hankala <[email protected]>
>
> 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
>
>