1 /*
   2 * Copyright (c) 2018, 2019, 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 java.lang.Continuation preemption
  27 *
  28 * @run testng/othervm/timeout=60 -Xint -XX:-UseContinuationLazyCopy Preempt
  29 * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -Xint -XX:+UseContinuationLazyCopy  Preempt
  30 * @run testng/othervm -XX:-TieredCompilation -Xcomp -XX:CompileOnly=java/lang/Continuation,Preempt -XX:-UseContinuationLazyCopy Preempt
  31 * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -Xcomp -XX:CompileOnly=java/lang/Continuation,Preempt -XX:+UseContinuationLazyCopy Preempt
  32 * @run testng/othervm -XX:TieredStopAtLevel=3 -Xcomp -XX:CompileOnly=java/lang/Continuation,Preempt -XX:-UseContinuationLazyCopy Preempt
  33 * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:TieredStopAtLevel=3 -Xcomp -XX:CompileOnly=java/lang/Continuation,Preempt -XX:+UseContinuationLazyCopy Preempt
  34 */
  35 
  36 // * @run testng/othervm -XX:+UnlockExperimentalVMOptions -XX:-TieredCompilation -XX:+UseJVMCICompiler -Xcomp -XX:CompileOnly=java/lang/Continuation,Preempt -XX:-UseContinuationLazyCopy Preempt
  37 // * @run testng/othervm -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+UseJVMCICompiler -Xcomp -XX:CompileOnly=java/lang/Continuation,Preempt -XX:+UseContinuationLazyCopy Preempt
  38 
  39 // TODO:
  40 // - Add tests for failed preemptions
  41 // - Add tests for additional safepoint types
  42 // - Add tests with -XX:-ThreadLocalHandshakes
  43 
  44 import java.util.ArrayList;
  45 import java.util.Arrays;
  46 import java.util.List;
  47 import java.util.stream.Collectors;
  48 import java.util.stream.IntStream;
  49 
  50 import org.testng.annotations.Test;
  51 import org.testng.annotations.DataProvider;
  52 import static org.testng.Assert.*;
  53 
  54 import java.util.concurrent.atomic.AtomicInteger;
  55 import java.util.concurrent.atomic.AtomicReference;
  56 import java.util.concurrent.CountDownLatch;
  57 
  58 @Test
  59 public class Preempt {
  60     static final ContinuationScope FOO = new ContinuationScope() {};
  61     final Continuation cont = new Continuation(FOO, ()-> { this.loop(); });
  62     CountDownLatch startLatch = new CountDownLatch(1);
  63     CountDownLatch preemptLatch = new CountDownLatch(1);
  64     volatile boolean run;
  65     volatile int x;
  66 
  67     public void test1() throws Exception {
  68         System.out.println("test1");
  69 
  70         final Thread t0 = Thread.currentThread();
  71         Thread t = new Thread(() -> {
  72             try {
  73                 startLatch.await();
  74                 {
  75                     var res = cont.tryPreempt(t0);
  76                     assertEquals(res, Continuation.PreemptStatus.SUCCESS);
  77                 }
  78                 preemptLatch.await();
  79                 {
  80                     var res = cont.tryPreempt(t0);
  81                     assertEquals(res, Continuation.PreemptStatus.SUCCESS);
  82                 }
  83             } catch (InterruptedException e) {
  84                 throw new RuntimeException(e);
  85             }
  86         });
  87         t.start();
  88 
  89         run = true;
  90 
  91         cont.run();
  92         assertEquals(cont.isDone(), false);
  93         assertEquals(cont.isPreempted(), true);
  94 
  95         List<String> frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
  96         assertEquals(frames.containsAll(Arrays.asList("loop", "lambda$new$0", "enter")), true);
  97 
  98         cont.run();
  99         assertEquals(cont.isDone(), false);
 100         assertEquals(cont.isPreempted(), true);
 101 
 102         t.join();
 103     }
 104 
 105     private void loop() {
 106         while (run) {
 107             x++;
 108             if (startLatch.getCount() > 0) {
 109                 startLatch.countDown();
 110             }
 111             if (cont.isPreempted() && preemptLatch.getCount() > 0) {
 112                 preemptLatch.countDown();
 113             }
 114         }
 115     }
 116 }