1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.mina.transport.vmpipe;
20  
21  import java.lang.management.ManagementFactory;
22  import java.lang.management.ThreadInfo;
23  import java.lang.management.ThreadMXBean;
24  import java.util.concurrent.CountDownLatch;
25  import java.util.concurrent.TimeUnit;
26  import java.util.concurrent.atomic.AtomicReference;
27  
28  import junit.framework.TestCase;
29  
30  import org.apache.mina.common.ConnectFuture;
31  import org.apache.mina.common.IoAcceptor;
32  import org.apache.mina.common.IoConnector;
33  import org.apache.mina.common.IoHandlerAdapter;
34  import org.apache.mina.common.IoSession;
35  
36  /**
37   * @author Apache Mina Project (dev@mina.apache.org)
38   * @version $Rev: $, $Date:  $
39   */
40  public class VmPipeSessionCrossCommunicationTest extends TestCase {
41      public void testOneSessionTalkingBackAndForthDoesNotDeadlock() throws Exception {
42          final VmPipeAddress address = new VmPipeAddress(1);
43          final IoConnector connector = new VmPipeConnector();
44          final AtomicReference<IoSession> c1 = new AtomicReference<IoSession>();
45          final CountDownLatch latch = new CountDownLatch(1);
46          final CountDownLatch messageCount = new CountDownLatch(2);
47          IoAcceptor acceptor = new VmPipeAcceptor();
48  
49          acceptor.setHandler(new IoHandlerAdapter() {
50              @Override
51              public void messageReceived(IoSession session, Object message) throws Exception {
52                  System.out.println(Thread.currentThread().getName() + ": " + message);
53  
54                  if ("start".equals(message)) {
55                      session.write("open new");
56                  } else if ("re-use c1".equals(message)) {
57                      session.write("tell me something on c1 now");
58                  } else if (((String) message).startsWith("please don't deadlock")) {
59                      messageCount.countDown();
60                  } else {
61                      fail("unexpected message received " + message);
62                  }
63              }
64          });
65          acceptor.bind(address);
66  
67          connector.setHandler(new IoHandlerAdapter() {
68              @Override
69              public void messageReceived(IoSession session, Object message) throws Exception {
70                  System.out.println(Thread.currentThread().getName() + ": " + message);
71  
72                  if ("open new".equals(message)) {
73                      System.out.println("opening c2 from " + Thread.currentThread().getName());
74  
75                      IoConnector c2 = new VmPipeConnector();
76                      c2.setHandler(new IoHandlerAdapter() {
77                          @Override
78                          public void sessionOpened(IoSession session) throws Exception {
79                              session.write("re-use c1");
80                          }
81  
82                          @Override
83                          public void messageReceived(IoSession session, Object message) throws Exception {
84                              System.out.println(Thread.currentThread().getName() + ": " + message);
85  
86                              if ("tell me something on c1 now".equals(message)) {
87                                  latch.countDown();
88                                  c1.get().write("please don't deadlock via c1");
89                              } else {
90                                  fail("unexpected message received " + message);
91                              }
92                          }
93                      });
94  
95                      ConnectFuture c2Future = c2.connect(address);
96  
97                      c2Future.await();
98  
99                      latch.await();
100 
101                     c2Future.getSession().write("please don't deadlock via c2");
102                 } else {
103                     fail("unexpeced message received " + message);
104                 }
105             }
106         });
107 
108         ConnectFuture future = connector.connect(address);
109 
110         future.await();
111 
112         c1.set(future.getSession());
113         c1.get().write("start");
114 
115         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
116 
117         while (!messageCount.await(100, TimeUnit.MILLISECONDS)) {
118             long[] threads = threadMXBean.findMonitorDeadlockedThreads();
119 
120             if (null != threads) {
121                 StringBuffer sb = new StringBuffer(256);
122                 ThreadInfo[] infos = threadMXBean.getThreadInfo(threads, Integer.MAX_VALUE);
123 
124                 for (ThreadInfo info : infos) {
125                     sb.append(info.getThreadName())
126                             .append(" blocked on ")
127                             .append(info.getLockName())
128                             .append(" owned by ")
129                             .append(info.getLockOwnerName())
130                             .append("\n");
131                 }
132 
133                 for (ThreadInfo info : infos) {
134                     sb.append("\nStack for ").append(info.getThreadName()).append("\n");
135                     for (StackTraceElement element : info.getStackTrace()) {
136                         sb.append("\t").append(element).append("\n");
137                     }
138                 }
139 
140                 fail("deadlocked! \n" + sb);
141             }
142         }
143 
144         acceptor.setCloseOnDeactivation(false);
145         acceptor.dispose();
146     }
147 }