All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openjdk.jcstress.samples.JMMSample_05_TotalOrder Maven / Gradle / Ivy

/*
 * Copyright (c) 2016, Red Hat Inc.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package org.openjdk.jcstress.samples;

import org.openjdk.jcstress.annotations.Actor;
import org.openjdk.jcstress.annotations.JCStressTest;
import org.openjdk.jcstress.annotations.Outcome;
import org.openjdk.jcstress.annotations.State;
import org.openjdk.jcstress.infra.results.II_Result;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;

import static org.openjdk.jcstress.annotations.Expect.*;

public class JMMSample_05_TotalOrder {

    /*
      ----------------------------------------------------------------------------------------------------------

        Another property comes for the inter-thread semantics deals not with
        partial, but total order. In JMM, synchronization order mandates that
        special "synchronization" actions always form a total order, consistent
        with program order.

        The most famous example that needs total order of operation is Dekker
        idiom, the building block of Dekker lock.

              [OK] org.openjdk.jcstress.samples.JMMSample_05_TotalOrder.PlainDekker
            (JVM args: [-server])
          Observed state   Occurrences              Expectation  Interpretation
                    0, 0    12,006,499   ACCEPTABLE_INTERESTING  Violates sequential consistency
                    0, 1    53,849,842               ACCEPTABLE  Trivial under sequential consistency
                    1, 0    39,405,818               ACCEPTABLE  Trivial under sequential consistency
                    1, 1            21               ACCEPTABLE  Trivial under sequential consistency
    */

    @JCStressTest
    @Outcome(id = {"0, 1", "1, 0", "1, 1"}, expect = ACCEPTABLE, desc = "Trivial under sequential consistency")
    @Outcome(id = "0, 0",                   expect = ACCEPTABLE_INTERESTING,  desc = "Violates sequential consistency")
    @State
    public static class PlainDekker {
        int x;
        int y;

        @Actor
        public void actor1(II_Result r) {
            x = 1;
            r.r1 = y;
        }

        @Actor
        public void actor2(II_Result r) {
            y = 1;
            r.r2 = x;
        }
    }

    /*
      ----------------------------------------------------------------------------------------------------------

        Adding volatile to both $x and $y bring them together into synchronization order,
        and thus require the results to be consistent with the case when reads/writes
        form a total order.

              [OK] org.openjdk.jcstress.samples.JMMSample_05_TotalOrder.VolatileDekker
            (JVM args: [-server])
          Observed state   Occurrences   Expectation  Interpretation
                    0, 0             0     FORBIDDEN  Violates sequential consistency
                    0, 1    52,228,833    ACCEPTABLE  Trivial under sequential consistency
                    1, 0    60,725,076    ACCEPTABLE  Trivial under sequential consistency
                    1, 1       313,541    ACCEPTABLE  Trivial under sequential consistency
     */

    @JCStressTest
    @Outcome(id = {"0, 1", "1, 0", "1, 1"}, expect = ACCEPTABLE, desc = "Trivial under sequential consistency")
    @Outcome(id = "0, 0",                   expect = FORBIDDEN,  desc = "Violates sequential consistency")
    @State
    public static class VolatileDekker {
        volatile int x;
        volatile int y;

        @Actor
        public void actor1(II_Result r) {
            x = 1;
            r.r1 = y;
        }

        @Actor
        public void actor2(II_Result r) {
            y = 1;
            r.r2 = x;
        }
    }

    /*
      ----------------------------------------------------------------------------------------------------------

        VarHandles acquire and release modes are too weak to achieve the required effect.
        VarHandles opaque mode is also too weak.

              [OK] org.openjdk.jcstress.samples.JMMSample_05_TotalOrder.AcqRelDekker
            (JVM args: [-server])
          Observed state   Occurrences              Expectation  Interpretation
                    0, 0    13,708,261   ACCEPTABLE_INTERESTING  Violates sequential consistency
                    0, 1    36,033,448               ACCEPTABLE  Trivial under sequential consistency
                    1, 0    27,158,587               ACCEPTABLE  Trivial under sequential consistency
                    1, 1        70,204               ACCEPTABLE  Trivial under sequential consistency
     */

    @JCStressTest
    @Outcome(id = {"0, 1", "1, 0", "1, 1"}, expect = ACCEPTABLE, desc = "Trivial under sequential consistency")
    @Outcome(id = "0, 0",                   expect = ACCEPTABLE_INTERESTING,  desc = "Violates sequential consistency")
    @State
    public static class AcqRelDekker {
        static final VarHandle VH_X;
        static final VarHandle VH_Y;

        static {
            try {
                VH_X = MethodHandles.lookup().findVarHandle(AcqRelDekker.class, "x", int.class);
                VH_Y = MethodHandles.lookup().findVarHandle(AcqRelDekker.class, "y", int.class);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new IllegalStateException(e);
            }
        }

        int x;
        int y;

        @Actor
        public void actor1(II_Result r) {
            VH_X.setRelease(this, 1);
            r.r1 = (int) VH_Y.getAcquire(this);
        }

        @Actor
        public void actor2(II_Result r) {
            VH_Y.setRelease(this, 1);
            r.r2 = (int) VH_X.getAcquire(this);
        }
    }


    /*
      ----------------------------------------------------------------------------------------------------------

        Conclusion: total order is only available for volatiles. Anything else is weaker and does not
        give totality.

        Do inter-thread reads/writes form total order consistent with program order?

          plain:                           no
          volatile:                       yes
          VH (plain):                      no
          VH (opaque):                     no
          VH (acq/rel):                    no
          VH (volatile):                  yes
     */

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy