Link [ NetBSD | NetBSD OpenGrok source search | PR fulltext-search | Summary of daily snapshot builds | history of daily build result | pkgsrc commit viewer ]


   
        usage: [branch:branch] [user:user] [path@revision] keyword [... [-excludekeyword [...]]] (e.g. branch:MAIN sys/arch/arm, if_wm.c@1.234 )




switch to index mode

recent branches: MAIN (4h)  netbsd-10 (18d)  netbsd-9 (18d)  netbsd-8 (23d) 

2024-06-04 10:41:01 UTC Now

2022-02-11 17:53:28 UTC MAIN commitmail json YAML

ucas(9): Membar audit.

- Omit needless membar_enter before ipi_trigger_broadcast.  This was
  presumably intended to imply a happens-before relation for the
  following two CPUs:

/* CPU doing ucas */
ucas_critical_enter()
ucas_critical_pausing_cpus = ncpu - 1 (A)
ipi_trigger_broadcast()

/* other CPU walking by whistling innocently */
IPI handler
ucas_critical_cpu_gate()
load ucas_critical_pausing_cpus (B)

  That is, this was presumably meant to ensure (A) happens-before (B).
  This relation is already guaranteed by ipi(9), so there is no need
  for any explicit memory barrier.

- Issue a store-release in ucas_critical_cpu_gate so we have the
  following happens-before relation which was otherwise not guaranteed
  except if __HAVE_ATOMIC_AS_MEMBAR:

/* other CPU walking by whistling innocently */
...other logic touching the target ucas word... (A)
IPI handler
ucas_critical_cpu_gate()
...
atomic_dec_uint(&ucas_critical_pausing_cpus)

  happens-before

/* CPU doing ucas */
ucas_critical_enter() -> ucas_critical_wait();
...touching the word with ufetch/ustore... (B)

  We need to ensure the logic (A) on another CPU touching the target
  ucas word happens-before we actually do the ucas at (B).

  (a) This requires the other CPU to do a store-release on
      ucas_critical_pausing_cpus in ucas_critical_cpu_gate, and

  (b) this requires the ucas CPU to do a load-acquire on
      ucas_critical_pausing_cpus in ucas_critical_wait.

  Without _both_ sides -- store-release and then load-acquire -- there
  is no such happens-before guarantee; another CPU may have a buffered
  store, for instance, that clobbers the ucas.

  For now, do the store-release with membar_exit conditional on
  __HAVE_ATOMIC_AS_MEMBAR and then atomic_dec_uint -- later with the
  C11 API we can dispense with the #ifdef and just use
  atomic_fetch_add_explicit(..., memory_order_release).  The
  load-acquire we can do with atomic_load_acquire.

- Issue a load-acquire in ucas_critical_cpu_gate so we have the
  following happens-before relation which was otherwise not guaranteed:

/* CPU doing ucas */
...ufetch/ustore... (A)
ucas_critical_exit()
ucas_critical_pausing_cpus = -1;

/* other CPU walking by whistling innocently */
IPI handler
ucas_critical_cpu_gate()
...
while (ucas_critical_pausing_cpus != -1)
spin;
...other logic touching the target ucas word... (B)

  We need to ensure the logic (A) to do the ucas happens-before logic
  that might use it on another CPU at (B).

  (a) This requires that the ucas CPU do a store-release on
      ucas_critical_pausing_cpus in ucas_critical_exit, and

  (b) this requires that the other CPU do a load-acquire on
      ucas_critical_pausing_cpus in ucas_critical_cpu_gate.

  Without _both_ sides -- store-release and then load-acquire -- there
  is no such happens-before guarantee; the other CPU might witness a
  cached stale value of the target location but a new value of some
  other location in the wrong order.

- Use atomic_load/store_* to avoid the appearance of races, e.g. for
  sanitizers.

- Document which barriers pair up with which barriers and what they're
  doing.

(riastradh)