1 /* 2 * Copyright (c) 2015, 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 * @bug 8143214 27 * @summary Verify that StackWalker works well when one instance of StackWalker 28 * is used by several threads sequentially or concurrently. 29 * @run testng AcrossThreads 30 */ 31 32 package test.java.lang.StackWalker; 33 34 import java.util.ArrayList; 35 import java.util.EnumSet; 36 import java.util.HashMap; 37 import java.util.List; 38 import java.util.Map; 39 40 import java.lang.StackWalker.StackFrame; 41 import static java.lang.StackWalker.Option.*; 42 43 import org.testng.annotations.*; 44 import static org.testng.Assert.*; 45 46 public class AcrossThreads { 47 static final StackWalker WALKERS[] = new StackWalker[] { 48 StackWalker.getInstance(RETAIN_CLASS_REFERENCE), 49 StackWalker.getInstance(EnumSet.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE)), 50 StackWalker.getInstance(EnumSet.of(SHOW_HIDDEN_FRAMES, RETAIN_CLASS_REFERENCE)) 51 }; 52 53 @DataProvider walkerProvider()54 public StackWalker[][] walkerProvider() { 55 return new StackWalker[][] { 56 new StackWalker[] { WALKERS[0] }, 57 new StackWalker[] { WALKERS[1] }, 58 new StackWalker[] { WALKERS[2] } 59 }; 60 } 61 62 @Test(dataProvider = "walkerProvider") test(StackWalker walker)63 public void test(StackWalker walker) { 64 Thread t1 = new T1(walker); 65 // call methods of one instance of StackWalker sequentially in T1, T2, T3. 66 t1.start(); 67 try { 68 t1.join(); 69 } catch (InterruptedException e) { } 70 71 List<Thread> threads = new ArrayList<Thread>(); 72 for (int i = 0; i < 100; i++) { 73 threads.add(new T1(walker)); 74 threads.add(new T2(walker)); 75 threads.add(new T3(walker)); 76 } 77 // call methods of one instance of StackWalker concurrently in several threads. 78 threads.parallelStream().forEach(t -> { 79 t.setDaemon(true); 80 t.start(); 81 }); 82 threads.parallelStream().forEach(t -> { 83 try { 84 t.join(); 85 } catch (InterruptedException e) { } 86 }); 87 } 88 89 interface Consumer { 90 final int LOOPS = 5; 91 consume()92 public void consume(); 93 assertWalker(StackWalker walker, int n)94 default public void assertWalker(StackWalker walker, int n) { 95 if (--n == 0) { 96 Map<String, Integer> methods = new HashMap<String, Integer>(); 97 walker.forEach(f -> { 98 Integer i = methods.putIfAbsent(f.getMethodName(), 1); 99 if (i != null) { 100 methods.put(f.getMethodName(), i + 1); 101 } 102 }); 103 104 // verify that walker.forEach(...) reaches the specified methods. 105 assertTrue(methods.get("consume") == 1); 106 assertTrue(methods.get("run") == 1); 107 assertTrue(methods.get("assertWalker") == LOOPS); 108 109 // verify that walker.walk(...) reaches the specified methods. 110 assertTrue(walker.walk(s -> s.map(StackFrame::getMethodName) 111 .filter(mn -> mn.equals("consume")) 112 .count()) == 1); 113 assertTrue(walker.walk(s -> s.map(StackFrame::getMethodName) 114 .filter(mn -> mn.equals("run")) 115 .count()) == 1); 116 assertTrue(walker.walk(s -> s.map(StackFrame::getMethodName) 117 .filter(mn -> mn.equals("assertWalker")) 118 .count()) == LOOPS); 119 } else { 120 assertWalker(walker, n); 121 } 122 } 123 } 124 125 class T1 extends Thread implements Consumer { 126 final StackWalker walker; 127 T1(StackWalker walker)128 public T1(StackWalker walker) { 129 this.walker = walker; 130 } 131 run()132 public void run() { 133 consume(); 134 135 Thread t2 = new T2(walker); 136 t2.start(); 137 try { 138 t2.join(); 139 } catch (InterruptedException e) { } 140 141 consume(); 142 } 143 consume()144 public void consume() { 145 assertWalker(walker, LOOPS); 146 147 // verify walker.walk() reaches T1 class through methods run() and consume(). 148 assertTrue(walker.walk(s -> s.filter(f -> T1.class == f.getDeclaringClass()) 149 .count()) == 2); 150 151 assertCallerClass(walker); 152 assertEquals(T1.class, walker.getCallerClass()); 153 } 154 } 155 156 class T2 extends Thread implements Consumer { 157 final StackWalker walker; 158 T2(StackWalker walker)159 public T2(StackWalker walker) { 160 this.walker = walker; 161 } 162 run()163 public void run() { 164 consume(); 165 166 Thread t3 = new T3(walker); 167 t3.start(); 168 try { 169 t3.join(); 170 } catch (InterruptedException e) { } 171 172 consume(); 173 } 174 consume()175 public void consume() { 176 assertWalker(walker, LOOPS); 177 178 // verify walker.walk() reaches T2 class through methods run() and consume(). 179 assertTrue(walker.walk(s -> s.filter(f -> T2.class == f.getDeclaringClass()) 180 .count()) == 2); 181 // verify T1 is not reached, even if call is invoked 182 // from test()->T1.start()->T1.run()->T2 183 assertTrue(walker.walk(s -> s.filter(f -> T1.class == f.getDeclaringClass()) 184 .count()) == 0); 185 186 assertCallerClass(walker); 187 assertEquals(T2.class, walker.getCallerClass()); 188 } 189 } 190 191 class T3 extends Thread implements Consumer { 192 final StackWalker walker; 193 T3(StackWalker walker)194 public T3(StackWalker walker) { 195 this.walker = walker; 196 } 197 run()198 public void run() { 199 consume(); 200 } 201 consume()202 public void consume() { 203 assertWalker(walker, LOOPS); 204 205 // verify walker.walk() reaches T1 class through methods run() and consume(). 206 assertTrue(walker.walk(s -> s.filter(f -> T3.class == f.getDeclaringClass()) 207 .count()) == 2); 208 // verify T1, T2 is not reached, even if call is invoked 209 // from test() -> T1.start() -> T1.run() -> T2.start() -> T2.run() -> T3 210 assertTrue(walker.walk(s -> s.filter(f -> T2.class == f.getDeclaringClass()) 211 .count()) == 0); 212 assertTrue(walker.walk(s -> s.filter(f -> T1.class == f.getDeclaringClass()) 213 .count()) == 0); 214 215 assertCallerClass(walker); 216 assertEquals(T3.class, walker.getCallerClass()); 217 } 218 } 219 assertCallerClass(StackWalker walker)220 static void assertCallerClass(StackWalker walker) { 221 // verify walker.getCallerClass() get the expected class. 222 call(walker); 223 } 224 call(StackWalker walker)225 static void call(StackWalker walker) { 226 Class<?> c = walker.getCallerClass(); 227 assertEquals(c, AcrossThreads.class); 228 } 229 } 230