24
24
25
25
import java .io .IOException ;
26
26
import java .net .Socket ;
27
+ import java .util .concurrent .BlockingQueue ;
27
28
import java .util .concurrent .Callable ;
28
29
import java .util .concurrent .CountDownLatch ;
30
+ import java .util .concurrent .LinkedBlockingQueue ;
31
+ import java .util .concurrent .atomic .AtomicBoolean ;
29
32
33
+ import com .oracle .truffle .api .TruffleSafepoint ;
30
34
import com .oracle .truffle .espresso .jdwp .api .ErrorCodes ;
31
35
import com .oracle .truffle .espresso .jdwp .api .JDWPContext ;
32
36
@@ -43,7 +47,8 @@ private DebuggerConnection(SocketConnection connection, DebuggerController contr
43
47
}
44
48
45
49
static void establishDebuggerConnection (DebuggerController controller , DebuggerController .SetupState setupState , boolean isReconnect , CountDownLatch startupLatch ) {
46
- Thread jdwpReceiver = new Thread (new JDWPReceiver (controller , setupState , isReconnect , startupLatch ), "jdwp-receiver" );
50
+ Thread jdwpReceiver = controller .getContext ().createSystemThread (new JDWPReceiver (controller , setupState , isReconnect , startupLatch ));
51
+ jdwpReceiver .setName ("jdwp-receiver" );
47
52
controller .addDebuggerReceiverThread (jdwpReceiver );
48
53
jdwpReceiver .setDaemon (true );
49
54
jdwpReceiver .start ();
@@ -104,25 +109,22 @@ public void run() {
104
109
105
110
private static class JDWPReceiver implements Runnable {
106
111
107
- private static final Object NOT_ENTERED_MARKER = new Object ();
108
112
private DebuggerController .SetupState setupState ;
109
113
private final DebuggerController controller ;
110
- private RequestedJDWPEvents requestedJDWPEvents ;
111
- private DebuggerConnection debuggerConnection ;
112
114
private final boolean isReconnect ;
113
115
private final CountDownLatch latch ;
114
116
115
117
JDWPReceiver (DebuggerController controller , DebuggerController .SetupState setupState , boolean isReconnect , CountDownLatch latch ) {
116
118
this .setupState = setupState ;
117
119
this .controller = controller ;
118
- this .requestedJDWPEvents = new RequestedJDWPEvents (controller );
119
120
this .isReconnect = isReconnect ;
120
121
this .latch = latch ;
121
122
}
122
123
123
124
@ Override
124
125
public void run () {
125
126
// first, complete the connection setup which is potentially blocking
127
+ DebuggerConnection debuggerConnection ;
126
128
try {
127
129
Socket connectionSocket ;
128
130
if (setupState .socket != null ) {
@@ -161,7 +163,8 @@ public void run() {
161
163
}
162
164
163
165
// OK, we're ready to fire up the JDWP transmitter thread too
164
- Thread jdwpSender = new Thread (new JDWPSender (socketConnection ), "jdwp-transmitter" );
166
+ Thread jdwpSender = controller .getContext ().createSystemThread (new JDWPSender (socketConnection ));
167
+ jdwpSender .setName ("jdwp-transmitter" );
165
168
controller .addDebuggerSenderThread (jdwpSender );
166
169
jdwpSender .setDaemon (true );
167
170
jdwpSender .start ();
@@ -190,36 +193,75 @@ public void run() {
190
193
latch .countDown ();
191
194
}
192
195
// Now, begin processing packets when they start to flow from the debugger.
193
- // Make sure this thread is entered in the context
196
+ final BlockingQueue <Packet > packetQueue = new LinkedBlockingQueue <>();
197
+ final AtomicBoolean processorClose = new AtomicBoolean (false );
198
+ Thread jdwpProcessor = controller .getContext ().createPolyglotThread (new JDWPProcessor (controller , debuggerConnection , packetQueue , processorClose ));
199
+ jdwpProcessor .setName ("jdwp-processor" );
200
+ controller .addDebuggerProcessorThread (jdwpProcessor );
201
+ jdwpProcessor .setDaemon (true );
202
+ jdwpProcessor .start ();
194
203
try {
195
204
while (!Thread .currentThread ().isInterrupted () && !controller .isClosing ()) {
196
- Object previous = NOT_ENTERED_MARKER ;
197
205
try {
198
- // get the packet outside the Truffle context, because it's a blocking IO
199
- // operation
200
206
Packet packet = Packet .fromByteArray (debuggerConnection .connection .readPacket ());
201
- previous = controller .enterTruffleContext ();
202
- processPacket (packet );
207
+ packetQueue .add (packet );
203
208
} catch (IOException e ) {
204
209
if (!debuggerConnection .isOpen ()) {
205
210
// when the socket is closed, we're done
206
211
break ;
207
212
}
208
213
if (!Thread .currentThread ().isInterrupted ()) {
209
214
controller .warning (() -> "Failed to process jdwp packet with message: " + e .getMessage ());
215
+ Thread .currentThread ().interrupt (); // And set the interrupt flag again
210
216
}
211
217
} catch (ConnectionClosedException e ) {
212
218
break ;
213
- } finally {
214
- if (previous != NOT_ENTERED_MARKER ) {
215
- controller .leaveTruffleContext (previous );
216
- }
217
219
}
218
220
}
219
221
} finally {
222
+ processorClose .set (true );
223
+ jdwpProcessor .interrupt ();
220
224
controller .getEventListener ().onDetach ();
221
225
}
222
226
}
227
+ }
228
+
229
+ private static class JDWPProcessor implements Runnable {
230
+
231
+ private final DebuggerController controller ;
232
+ private final DebuggerConnection debuggerConnection ;
233
+ private final RequestedJDWPEvents requestedJDWPEvents ;
234
+ private final BlockingQueue <Packet > packetQueue ;
235
+ private final AtomicBoolean close ;
236
+
237
+ private JDWPProcessor (DebuggerController controller , DebuggerConnection debuggerConnection ,
238
+ BlockingQueue <Packet > packetQueue , AtomicBoolean close ) {
239
+ this .controller = controller ;
240
+ this .debuggerConnection = debuggerConnection ;
241
+ this .requestedJDWPEvents = new RequestedJDWPEvents (controller );
242
+ this .packetQueue = packetQueue ;
243
+ this .close = close ;
244
+ }
245
+
246
+ @ Override
247
+ public void run () {
248
+ while (!close .get ()) {
249
+ Packet packet ;
250
+ try {
251
+ packet = TruffleSafepoint .getCurrent ().setBlockedFunction (null , TruffleSafepoint .Interrupter .THREAD_INTERRUPT ,
252
+ BlockingQueue ::take , packetQueue , () -> breakIfClosed (), null );
253
+ } catch (ProcessorClosedException ex ) {
254
+ break ;
255
+ }
256
+ processPacket (packet );
257
+ }
258
+ }
259
+
260
+ private void breakIfClosed () {
261
+ if (close .get ()) {
262
+ throw new ProcessorClosedException ();
263
+ }
264
+ }
223
265
224
266
private void processPacket (Packet packet ) {
225
267
JDWPContext context = controller .getContext ();
@@ -665,6 +707,11 @@ private void processPacket(Packet packet) {
665
707
debuggerConnection .handleReply (packet , new CommandResult (reply ));
666
708
}
667
709
}
710
+
711
+ private static class ProcessorClosedException extends RuntimeException {
712
+
713
+ private static final long serialVersionUID = 8467327507834079474L ;
714
+ }
668
715
}
669
716
670
717
private static CommandResult unknownCommandSet (Packet packet , DebuggerController controller ) {
0 commit comments