Re: [PATCH] membarrier: Update example to take TSO into account

From: Michael Kerrisk (man-pages)
Date: Tue Sep 19 2017 - 11:11:53 EST


On 09/18/2017 08:59 PM, Mathieu Desnoyers wrote:
> The example given specifically states that it focus on x86 (TSO memory
> model), but gives a read-read vs write-write ordering example, even
> though this scenario does not require explicit barriers on TSO.
>
> So either we change the example architecture to a weakly-ordered
> architecture, or we change the example to a scenario requiring barriers
> on x86.
>
> Let's stay on x86, but provide a Dekker as example instead.

Thanks for the patch, Mathieu. Applied. (And thanks for the links below.)

Cheers,

Michael

> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@xxxxxxxxxxxx>
> CC: Michael Kerrisk <mtk.manpages@xxxxxxxxx>
> CC: Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
> Link: https://stackoverflow.com/questions/45970525/is-the-example-in-the-membarrier-man-page-pointless-in-x86
> Link: https://lwn.net/Articles/573436/
> ---
> man2/membarrier.2 | 66 ++++++++++++++++++++++++++++++-------------------------
> 1 file changed, 36 insertions(+), 30 deletions(-)
>
> diff --git a/man2/membarrier.2 b/man2/membarrier.2
> index 658dfa5d1..bbf611e10 100644
> --- a/man2/membarrier.2
> +++ b/man2/membarrier.2
> @@ -192,39 +192,42 @@ following code (x86) can be transformed using
> static volatile int a, b;
>
> static void
> -fast_path(void)
> +fast_path(int *read_b)
> {
> - int read_a, read_b;
> -
> - read_b = b;
> + a = 1;
> asm volatile ("mfence" : : : "memory");
> - read_a = a;
> -
> - /* read_b == 1 implies read_a == 1. */
> -
> - if (read_b == 1 && read_a == 0)
> - abort();
> + *read_b = b;
> }
>
> static void
> -slow_path(void)
> +slow_path(int *read_a)
> {
> - a = 1;
> - asm volatile ("mfence" : : : "memory");
> b = 1;
> + asm volatile ("mfence" : : : "memory");
> + *read_a = a;
> }
>
> int
> main(int argc, char **argv)
> {
> + int read_a, read_b;
> +
> /*
> * Real applications would call fast_path() and slow_path()
> * from different threads. Call those from main() to keep
> * this example short.
> */
>
> - slow_path();
> - fast_path();
> + slow_path(&read_a);
> + fast_path(&read_b);
> +
> + /*
> + * read_b == 0 implies read_a == 1 and
> + * read_a == 0 implies read_b == 1.
> + */
> +
> + if (read_b == 0 && read_a == 0)
> + abort();
>
> exit(EXIT_SUCCESS);
> }
> @@ -275,31 +278,26 @@ init_membarrier(void)
> }
>
> static void
> -fast_path(void)
> +fast_path(int *read_b)
> {
> - int read_a, read_b;
> -
> - read_b = b;
> + a = 1;
> asm volatile ("" : : : "memory");
> - read_a = a;
> -
> - /* read_b == 1 implies read_a == 1. */
> -
> - if (read_b == 1 && read_a == 0)
> - abort();
> + *read_b = b;
> }
>
> static void
> -slow_path(void)
> +slow_path(int *read_a)
> {
> - a = 1;
> - membarrier(MEMBARRIER_CMD_SHARED, 0);
> b = 1;
> + membarrier(MEMBARRIER_CMD_SHARED, 0);
> + *read_a = a;
> }
>
> int
> main(int argc, char **argv)
> {
> + int read_a, read_b;
> +
> if (init_membarrier())
> exit(EXIT_FAILURE);
>
> @@ -309,8 +307,16 @@ main(int argc, char **argv)
> * this example short.
> */
>
> - slow_path();
> - fast_path();
> + slow_path(&read_a);
> + fast_path(&read_b);
> +
> + /*
> + * read_b == 0 implies read_a == 1 and
> + * read_a == 0 implies read_b == 1.
> + */
> +
> + if (read_b == 0 && read_a == 0)
> + abort();
>
> exit(EXIT_SUCCESS);
> }
>


--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/