> 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
> 
> 

Reply via email to