1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
38
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 }