jdk/test/com/sun/jdi/InvokeHangTest.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2006-2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    21  * have any questions.
       
    22  */
       
    23 
       
    24 /**
       
    25  *  @test
       
    26  *  @bug 6293795
       
    27  *  @summary  Backend hangs when invokeMethod is called from a JDI eventHandler
       
    28  *
       
    29  *  @author jjh
       
    30  *
       
    31  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
       
    32  *  @run compile -g InvokeHangTest.java
       
    33  *  @run main InvokeHangTest
       
    34  */
       
    35 import com.sun.jdi.*;
       
    36 import com.sun.jdi.event.*;
       
    37 import com.sun.jdi.request.*;
       
    38 
       
    39 import java.util.*;
       
    40 
       
    41 /*
       
    42  * This debuggee basically runs two threads each of
       
    43  * which loop, hitting a bkpt in each iteration.
       
    44  *
       
    45  */
       
    46 class InvokeHangTarg extends Thread {
       
    47     static boolean one = false;
       
    48     static String name1 = "Thread 1";
       
    49     static String name2 = "Thread 2";
       
    50     static int count = 100;
       
    51 
       
    52     public static void main(String[] args) {
       
    53         System.out.println("Howdy!");
       
    54         InvokeHangTarg t1 = new InvokeHangTarg(name1);
       
    55         InvokeHangTarg t2 = new InvokeHangTarg(name2);
       
    56 
       
    57         t1.start();
       
    58         t2.start();
       
    59     }
       
    60 
       
    61     // This is called from the debugger via invokeMethod
       
    62     public double invokeee() {
       
    63         System.out.println("Debuggee: invokeee in thread "+Thread.currentThread().toString());
       
    64         yield();
       
    65         return longMethod(2);
       
    66     }
       
    67     public double longMethod(int n) {
       
    68         double a = 0;
       
    69         double s = 0;
       
    70         for (int i = 0; i < n; i++) {
       
    71             a += i;
       
    72             for (int j = -1000*i; j < 1000*i; j++) {
       
    73                 a = a*(1 + i/(j + 0.5));
       
    74                 s += Math.sin(a);
       
    75             }
       
    76         }
       
    77         System.out.println("Debuggee: invokeee finished");
       
    78         return s;
       
    79     }
       
    80 
       
    81     public InvokeHangTarg(String name) {
       
    82         super(name);
       
    83     }
       
    84 
       
    85     public void run() {
       
    86         if (getName().equals(name1)) {
       
    87             run1();
       
    88         } else {
       
    89             run2();
       
    90         }
       
    91     }
       
    92 
       
    93     public void bkpt1(int i) {
       
    94         System.out.println("Debuggee: " + Thread.currentThread() +" is running:" + i);
       
    95         try {
       
    96             Thread.currentThread().sleep(2);
       
    97         } catch (InterruptedException iex) {}
       
    98         //yield();
       
    99     }
       
   100 
       
   101     public void run1() {
       
   102         int i = 0;
       
   103         while (i < count) {
       
   104             i++;
       
   105             bkpt1(i);
       
   106         }
       
   107     }
       
   108 
       
   109     public void bkpt2(int i) {
       
   110         System.out.println("Debuggee: " + Thread.currentThread() +" is running:" + i);
       
   111         try {
       
   112             Thread.currentThread().sleep(2);
       
   113         } catch (InterruptedException iex) {}
       
   114             //yield();
       
   115     }
       
   116 
       
   117     public void run2() {
       
   118         int i = 0;
       
   119         while (i < count) {
       
   120             i++;
       
   121             bkpt2(i);
       
   122         }
       
   123     }
       
   124 }
       
   125 
       
   126 /********** test program **********/
       
   127 
       
   128 public class InvokeHangTest extends TestScaffold {
       
   129     ReferenceType targetClass;
       
   130     ThreadReference mainThread;
       
   131     BreakpointRequest request1;
       
   132     BreakpointRequest request2;
       
   133     static volatile int bkpts = 0;
       
   134     Thread timerThread;
       
   135     static int waitTime = 20000;
       
   136 
       
   137     InvokeHangTest (String args[]) {
       
   138         super(args);
       
   139     }
       
   140 
       
   141     public static void main(String[] args)      throws Exception {
       
   142         new InvokeHangTest(args).startTests();
       
   143     }
       
   144 
       
   145     void doInvoke(ThreadReference thread, ObjectReference ref, String methodName) {
       
   146         List methods = ref.referenceType().methodsByName(methodName);
       
   147         Method method = (Method) methods.get(0);
       
   148         try {
       
   149             System.err.println("  Debugger: Invoking in thread" + thread);
       
   150             ref.invokeMethod(thread, method, new ArrayList(), ref.INVOKE_NONVIRTUAL);
       
   151             System.err.println("  Debugger: Invoke done");
       
   152         } catch (Exception ex) {
       
   153             ex.printStackTrace();
       
   154             failure("failure: Exception");
       
   155         }
       
   156     }
       
   157 
       
   158     // BreakpointEvent handler
       
   159     public void breakpointReached(BreakpointEvent event) {
       
   160         if (bkpts == 0) {
       
   161             /*
       
   162              * This thread will watch for n secs to go by with no
       
   163              * calls to this method.
       
   164              */
       
   165             timerThread.start();
       
   166         }
       
   167 
       
   168         synchronized("abc") {
       
   169             /*
       
   170              * Note that this will most likely never get to
       
   171              * the number of times the two bkpt lines in the debuggee
       
   172              * are hit because bkpts are lost while they are disabled.
       
   173              */
       
   174             bkpts++;
       
   175         }
       
   176 
       
   177         /*
       
   178          * The bug occurs when the requests are disabled
       
   179          * and then an invoke is done in the event handler.  In some cases
       
   180          * the other thread has hit a bkpt and the back-end is waiting
       
   181          * to send it.  When the back-end resumes the debuggee to do the
       
   182          * invokeMethod, this 2nd bkpt is released, the debuggee is suspended, including
       
   183          * the thread on which the invoke was done (because it is a SUSPEND_ALL bkpt),
       
   184          * the bkpt is sent to the front-end, but the client event handler is sitting
       
   185          * here waiting for the invoke to finish, so it doesn't get the 2nd bkpt and
       
   186          * do the resume for it.  Thus, the debuggee is suspended waiting for a resume
       
   187          * that never comes.
       
   188          */
       
   189         request1.disable();
       
   190         request2.disable();
       
   191 
       
   192         ThreadReference thread = event.thread();
       
   193         try {
       
   194             StackFrame sf = thread.frame(0);
       
   195             System.err.println("  Debugger: Breakpoint hit at "+sf.location());
       
   196             doInvoke(thread, sf.thisObject(), "invokeee");
       
   197         } catch (IncompatibleThreadStateException itsex) {
       
   198             itsex.printStackTrace();
       
   199             failure("failure: Exception");
       
   200         }
       
   201         request1.enable();
       
   202         request2.enable();
       
   203 
       
   204     }
       
   205 
       
   206     /********** test core **********/
       
   207 
       
   208     protected void runTests() throws Exception {
       
   209 
       
   210         /*
       
   211          * Get to the top of main()
       
   212          * to determine targetClass and mainThread
       
   213          */
       
   214         BreakpointEvent bpe = startToMain("InvokeHangTarg");
       
   215         targetClass = bpe.location().declaringType();
       
   216         mainThread = bpe.thread();
       
   217         EventRequestManager erm = vm().eventRequestManager();
       
   218         final Thread mainThread = Thread.currentThread();
       
   219 
       
   220         /*
       
   221          * Set event requests
       
   222          */
       
   223         Location loc1 = findMethod(targetClass, "bkpt1", "(I)V").location();
       
   224         Location loc2 = findMethod(targetClass, "bkpt2", "(I)V").location();
       
   225         request1 = erm.createBreakpointRequest(loc1);
       
   226         request2 = erm.createBreakpointRequest(loc2);
       
   227         request1.enable();
       
   228         request2.enable();
       
   229 
       
   230         /*
       
   231          * This thread will be started when we get the first bkpt.
       
   232          * (Which we always expect to get).
       
   233          * It awakens every n seconds and checks to see if we
       
   234          * got any breakpoint events while it was asleep.  If not, then
       
   235          * we assume the debuggee is hung and fail the test.
       
   236          */
       
   237         timerThread = new Thread("test timer") {
       
   238                 public void run() {
       
   239                     int myBkpts = bkpts;
       
   240                     while (true) {
       
   241                         try {
       
   242                             Thread.sleep(waitTime);
       
   243                             System.out.println("bkpts = " + bkpts);
       
   244                             if (myBkpts == bkpts) {
       
   245                                 // no bkpt for 'waitTime' msecs
       
   246                                 failure("failure: Debuggee appears to be hung");
       
   247                                 vmDisconnected = true;
       
   248                                 // This awakens the main thread which is
       
   249                                 // waiting for a VMDisconnect.
       
   250                                 mainThread.interrupt();
       
   251                                 break;
       
   252                             }
       
   253                             myBkpts = bkpts;
       
   254                         } catch (InterruptedException ee) {
       
   255                             // If the test completes, this occurs.
       
   256                             println("timer Interrupted");
       
   257                             break;
       
   258                         }
       
   259                     }
       
   260                 }
       
   261             };
       
   262 
       
   263         /*
       
   264          * resume the target, listening for events
       
   265          */
       
   266         listenUntilVMDisconnect();
       
   267         timerThread.interrupt();
       
   268         /*
       
   269          * deal with results of test
       
   270          * if anything has called failure("foo") testFailed will be true
       
   271          */
       
   272         if (!testFailed) {
       
   273             println("InvokeHangTest: passed; bkpts = " + bkpts);
       
   274         } else {
       
   275             throw new Exception("InvokeHangTest: failed; bkpts = " + bkpts);
       
   276         }
       
   277     }
       
   278 }