1 /*
  2 * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
  3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4 *
  5 * This code is free software; you can redistribute it and/or modify it
  6 * under the terms of the GNU General Public License version 2 only, as
  7 * published by the Free Software Foundation.
  8 *
  9 * This code is distributed in the hope that it will be useful, but WITHOUT
 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12 * version 2 for more details (a copy is included in the LICENSE file that
 13 * accompanied this code).
 14 *
 15 * You should have received a copy of the GNU General Public License version
 16 * 2 along with this work; if not, write to the Free Software Foundation,
 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18 *
 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20 * or visit www.oracle.com if you need additional information or have any
 21 * questions.
 22 */
 23 
 24 /**
 25 * @test
 26 * @summary Tests for jdk.internal.vm.Continuation preemption
 27 * @modules java.base/jdk.internal.vm
 28 *
 29 * @run testng/othervm/timeout=60 -Xlog:jvmcont+preempt=trace -Xint Preempt
 30 * @run testng/othervm -XX:-TieredCompilation -Xcomp -XX:CompileOnly=jdk/internal/vm/Continuation,Preempt Preempt
 31 * @run testng/othervm -XX:TieredStopAtLevel=3 -Xcomp -XX:CompileOnly=jdk/internal/vm/Continuation,Preempt Preempt
 32 * @run testng/othervm -Xlog:jvmcont+preempt=trace -XX:-UseTLAB -Xint Preempt
 33 */
 34 
 35 // * @run testng/othervm -XX:+UnlockExperimentalVMOptions -XX:-TieredCompilation -XX:+UseJVMCICompiler -Xcomp -XX:CompileOnly=jdk/internal/vm/Continuation,Preempt Preempt
 36 
 37 // TODO:
 38 // - Add tests for failed preemptions
 39 
 40 import jdk.internal.vm.Continuation;
 41 import jdk.internal.vm.ContinuationScope;
 42 
 43 import java.util.ArrayList;
 44 import java.util.Arrays;
 45 import java.util.List;
 46 import java.util.stream.Collectors;
 47 import java.util.stream.IntStream;
 48 
 49 import org.testng.annotations.Test;
 50 import org.testng.annotations.DataProvider;
 51 import static org.testng.Assert.*;
 52 
 53 import java.util.concurrent.atomic.AtomicInteger;
 54 import java.util.concurrent.atomic.AtomicReference;
 55 import java.util.concurrent.CountDownLatch;
 56 
 57 @Test
 58 public class Preempt {
 59     static final ContinuationScope FOO = new ContinuationScope() {};
 60     final Continuation cont = new Continuation(FOO, ()-> { this.loop(); });
 61     CountDownLatch startLatch = new CountDownLatch(1);
 62     CountDownLatch preemptLatch = new CountDownLatch(1);
 63     volatile boolean run;
 64     volatile int x;
 65 
 66     public void test1() throws Exception {
 67         System.out.println("test1");
 68 
 69         final Thread t0 = Thread.currentThread();
 70         Thread t = new Thread(() -> {
 71             try {
 72                 startLatch.await();
 73                 {
 74                     Continuation.PreemptStatus res;
 75                     int i = 0;
 76                     do {
 77                         res = cont.tryPreempt(t0);
 78                         Thread.sleep(10);
 79                         i++;
 80                     } while (i < 100 && res == Continuation.PreemptStatus.TRANSIENT_FAIL_PINNED_NATIVE);
 81                     assertEquals(res, Continuation.PreemptStatus.SUCCESS, "res: " + res + " i: " + i);
 82                 }
 83                 preemptLatch.await();
 84                 {
 85                     Continuation.PreemptStatus res;
 86                     int i = 0;
 87                     do {
 88                         res = cont.tryPreempt(t0);
 89                         Thread.sleep(10);
 90                         i++;
 91                     } while (i < 100 && res == Continuation.PreemptStatus.TRANSIENT_FAIL_PINNED_NATIVE);
 92                     assertEquals(res, Continuation.PreemptStatus.SUCCESS, "res: " + res + " i: " + i);
 93                 }
 94             } catch (InterruptedException e) {
 95                 throw new RuntimeException(e);
 96             }
 97         });
 98         t.start();
 99 
100         run = true;
101 
102         cont.run();
103         assertEquals(cont.isDone(), false);
104         assertEquals(cont.isPreempted(), true);
105 
106         List<String> frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
107         assertEquals(frames.containsAll(Arrays.asList("loop", "lambda$new$0", "enter")), true);
108 
109         cont.run();
110         assertEquals(cont.isDone(), false);
111         assertEquals(cont.isPreempted(), true);
112 
113         t.join();
114     }
115 
116     private void loop() {
117         while (run) {
118             x++;
119 
120             // Continuation.pin(); try { System.out.println("$$$ " + x + " $$$"); } finally { Continuation.unpin(); }
121 
122             if (startLatch.getCount() > 0) {
123                 startLatch.countDown();
124             }
125             if (cont.isPreempted() && preemptLatch.getCount() > 0) {
126                 preemptLatch.countDown();
127             }
128         }
129     }
130 }