OSDN Git Service

Work around a dalvik JDWP/GC deadlock.
[android-x86/dalvik.git] / vm / jdwp / JdwpMain.cpp
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * JDWP initialization.
19  */
20 #include "jdwp/JdwpPriv.h"
21 #include "Dalvik.h"
22 #include "Atomic.h"
23
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/time.h>
27 #include <time.h>
28 #include <errno.h>
29
30
31 static void* jdwpThreadStart(void* arg);
32
33 /*
34  * JdwpNetStateBase class implementation
35  */
36 JdwpNetStateBase::JdwpNetStateBase()
37 {
38     clientSock = -1;
39     dvmDbgInitMutex(&socketLock);
40 }
41
42 /*
43  * Write a packet. Grabs a mutex to assure atomicity.
44  */
45 ssize_t JdwpNetStateBase::writePacket(ExpandBuf* pReply)
46 {
47     dvmDbgLockMutex(&socketLock);
48     ssize_t cc = TEMP_FAILURE_RETRY(write(clientSock, expandBufGetBuffer(pReply),
49                                           expandBufGetLength(pReply)));
50     dvmDbgUnlockMutex(&socketLock);
51
52     return cc;
53 }
54
55 /*
56  * Write a buffered packet. Grabs a mutex to assure atomicity.
57  */
58 ssize_t JdwpNetStateBase::writeBufferedPacket(const struct iovec* iov,
59     int iovcnt)
60 {
61     dvmDbgLockMutex(&socketLock);
62     ssize_t actual = TEMP_FAILURE_RETRY(writev(clientSock, iov, iovcnt));
63     dvmDbgUnlockMutex(&socketLock);
64
65     return actual;
66 }
67
68 /*
69  * Initialize JDWP.
70  *
71  * Does not return until JDWP thread is running, but may return before
72  * the thread is accepting network connections.
73  */
74 JdwpState* dvmJdwpStartup(const JdwpStartupParams* pParams)
75 {
76     JdwpState* state = NULL;
77
78     /* comment this out when debugging JDWP itself */
79     android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);
80
81     state = (JdwpState*) calloc(1, sizeof(JdwpState));
82
83     state->params = *pParams;
84
85     state->requestSerial = 0x10000000;
86     state->eventSerial = 0x20000000;
87     dvmDbgInitMutex(&state->threadStartLock);
88     dvmDbgInitMutex(&state->attachLock);
89     dvmDbgInitMutex(&state->serialLock);
90     dvmDbgInitMutex(&state->eventLock);
91     state->eventThreadId = 0;
92     dvmDbgInitMutex(&state->eventThreadLock);
93     dvmDbgInitCond(&state->threadStartCond);
94     dvmDbgInitCond(&state->attachCond);
95     dvmDbgInitCond(&state->eventThreadCond);
96
97     switch (pParams->transport) {
98     case kJdwpTransportSocket:
99         // ALOGD("prepping for JDWP over TCP");
100         state->transport = dvmJdwpSocketTransport();
101         break;
102     case kJdwpTransportAndroidAdb:
103         // ALOGD("prepping for JDWP over ADB");
104         state->transport = dvmJdwpAndroidAdbTransport();
105         /* TODO */
106         break;
107     default:
108         ALOGE("Unknown transport %d", pParams->transport);
109         assert(false);
110         goto fail;
111     }
112
113     if (!dvmJdwpNetStartup(state, pParams))
114         goto fail;
115
116     /*
117      * Grab a mutex or two before starting the thread.  This ensures they
118      * won't signal the cond var before we're waiting.
119      */
120     dvmDbgLockMutex(&state->threadStartLock);
121     if (pParams->suspend)
122         dvmDbgLockMutex(&state->attachLock);
123
124     /*
125      * We have bound to a port, or are trying to connect outbound to a
126      * debugger.  Create the JDWP thread and let it continue the mission.
127      */
128     if (!dvmCreateInternalThread(&state->debugThreadHandle, "JDWP",
129             jdwpThreadStart, state))
130     {
131         /* state is getting tossed, but unlock these anyway for cleanliness */
132         dvmDbgUnlockMutex(&state->threadStartLock);
133         if (pParams->suspend)
134             dvmDbgUnlockMutex(&state->attachLock);
135         goto fail;
136     }
137
138     /*
139      * Wait until the thread finishes basic initialization.
140      * TODO: cond vars should be waited upon in a loop
141      */
142     dvmDbgCondWait(&state->threadStartCond, &state->threadStartLock);
143     dvmDbgUnlockMutex(&state->threadStartLock);
144
145
146     /*
147      * For suspend=y, wait for the debugger to connect to us or for us to
148      * connect to the debugger.
149      *
150      * The JDWP thread will signal us when it connects successfully or
151      * times out (for timeout=xxx), so we have to check to see what happened
152      * when we wake up.
153      */
154     if (pParams->suspend) {
155         dvmChangeStatus(NULL, THREAD_VMWAIT);
156         dvmDbgCondWait(&state->attachCond, &state->attachLock);
157         dvmDbgUnlockMutex(&state->attachLock);
158         dvmChangeStatus(NULL, THREAD_RUNNING);
159
160         if (!dvmJdwpIsActive(state)) {
161             ALOGE("JDWP connection failed");
162             goto fail;
163         }
164
165         ALOGI("JDWP connected");
166
167         /*
168          * Ordinarily we would pause briefly to allow the debugger to set
169          * breakpoints and so on, but for "suspend=y" the VM init code will
170          * pause the VM when it sends the VM_START message.
171          */
172     }
173
174     return state;
175
176 fail:
177     dvmJdwpShutdown(state);     // frees state
178     return NULL;
179 }
180
181 /*
182  * Reset all session-related state.  There should not be an active connection
183  * to the client at this point.  The rest of the VM still thinks there is
184  * a debugger attached.
185  *
186  * This includes freeing up the debugger event list.
187  */
188 void dvmJdwpResetState(JdwpState* state)
189 {
190     /* could reset the serial numbers, but no need to */
191
192     dvmJdwpUnregisterAll(state);
193     assert(state->eventList == NULL);
194
195     /*
196      * Should not have one of these in progress.  If the debugger went away
197      * mid-request, though, we could see this.
198      */
199     if (state->eventThreadId != 0) {
200         ALOGW("WARNING: resetting state while event in progress");
201         assert(false);
202     }
203 }
204
205 /*
206  * Tell the JDWP thread to shut down.  Frees "state".
207  */
208 void dvmJdwpShutdown(JdwpState* state)
209 {
210     void* threadReturn;
211
212     if (state == NULL)
213         return;
214
215     if (dvmJdwpIsTransportDefined(state)) {
216         if (dvmJdwpIsConnected(state))
217             dvmJdwpPostVMDeath(state);
218
219         /*
220          * Close down the network to inspire the thread to halt.
221          */
222         if (gDvm.verboseShutdown)
223             ALOGD("JDWP shutting down net...");
224         dvmJdwpNetShutdown(state);
225
226         if (state->debugThreadStarted) {
227             state->run = false;
228             if (pthread_join(state->debugThreadHandle, &threadReturn) != 0) {
229                 ALOGW("JDWP thread join failed");
230             }
231         }
232
233         if (gDvm.verboseShutdown)
234             ALOGD("JDWP freeing netstate...");
235         dvmJdwpNetFree(state);
236         state->netState = NULL;
237     }
238     assert(state->netState == NULL);
239
240     dvmJdwpResetState(state);
241     free(state);
242 }
243
244 /*
245  * Are we talking to a debugger?
246  */
247 bool dvmJdwpIsActive(JdwpState* state)
248 {
249     return dvmJdwpIsConnected(state);
250 }
251
252 /*
253  * Entry point for JDWP thread.  The thread was created through the VM
254  * mechanisms, so there is a java/lang/Thread associated with us.
255  */
256 static void* jdwpThreadStart(void* arg)
257 {
258     JdwpState* state = (JdwpState*) arg;
259
260     ALOGV("JDWP: thread running");
261
262     /*
263      * Finish initializing "state", then notify the creating thread that
264      * we're running.
265      */
266     state->debugThreadHandle = dvmThreadSelf()->handle;
267     state->run = true;
268     android_atomic_release_store(true, &state->debugThreadStarted);
269
270     dvmDbgLockMutex(&state->threadStartLock);
271     dvmDbgCondBroadcast(&state->threadStartCond);
272     dvmDbgUnlockMutex(&state->threadStartLock);
273
274     /* set the thread state to VMWAIT so GCs don't wait for us */
275     dvmDbgThreadWaiting();
276
277     /*
278      * Loop forever if we're in server mode, processing connections.  In
279      * non-server mode, we bail out of the thread when the debugger drops
280      * us.
281      *
282      * We broadcast a notification when a debugger attaches, after we
283      * successfully process the handshake.
284      */
285     while (state->run) {
286         bool first;
287
288         if (state->params.server) {
289             /*
290              * Block forever, waiting for a connection.  To support the
291              * "timeout=xxx" option we'll need to tweak this.
292              */
293             if (!dvmJdwpAcceptConnection(state))
294                 break;
295         } else {
296             /*
297              * If we're not acting as a server, we need to connect out to the
298              * debugger.  To support the "timeout=xxx" option we need to
299              * have a timeout if the handshake reply isn't received in a
300              * reasonable amount of time.
301              */
302             if (!dvmJdwpEstablishConnection(state)) {
303                 /* wake anybody who was waiting for us to succeed */
304                 dvmDbgLockMutex(&state->attachLock);
305                 dvmDbgCondBroadcast(&state->attachCond);
306                 dvmDbgUnlockMutex(&state->attachLock);
307                 break;
308             }
309         }
310
311         /* prep debug code to handle the new connection */
312         dvmDbgConnected();
313
314         /* process requests until the debugger drops */
315         first = true;
316         while (true) {
317             // sanity check -- shouldn't happen?
318             if (dvmThreadSelf()->status != THREAD_VMWAIT) {
319                 ALOGE("JDWP thread no longer in VMWAIT (now %d); resetting",
320                     dvmThreadSelf()->status);
321                 dvmDbgThreadWaiting();
322             }
323
324             if (!dvmJdwpProcessIncoming(state))     /* blocking read */
325                 break;
326
327             if (first && !dvmJdwpAwaitingHandshake(state)) {
328                 /* handshake worked, tell the interpreter that we're active */
329                 first = false;
330
331                 /* set thread ID; requires object registry to be active */
332                 state->debugThreadId = dvmDbgGetThreadSelfId();
333
334                 /* wake anybody who's waiting for us */
335                 dvmDbgLockMutex(&state->attachLock);
336                 dvmDbgCondBroadcast(&state->attachCond);
337                 dvmDbgUnlockMutex(&state->attachLock);
338             }
339         }
340
341         dvmJdwpCloseConnection(state);
342
343         if (state->ddmActive) {
344             state->ddmActive = false;
345
346             /* broadcast the disconnect; must be in RUNNING state */
347             dvmDbgThreadRunning();
348             dvmDbgDdmDisconnected();
349             dvmDbgThreadWaiting();
350         }
351
352         /* release session state, e.g. remove breakpoint instructions */
353         dvmJdwpResetState(state);
354
355         /* tell the interpreter that the debugger is no longer around */
356         dvmDbgDisconnected();
357
358         /* if we had threads suspended, resume them now */
359         dvmUndoDebuggerSuspensions();
360
361         /* if we connected out, this was a one-shot deal */
362         if (!state->params.server)
363             state->run = false;
364     }
365
366     /* back to running, for thread shutdown */
367     dvmDbgThreadRunning();
368
369     ALOGV("JDWP: thread exiting");
370     return NULL;
371 }
372
373
374 /*
375  * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
376  */
377 pthread_t dvmJdwpGetDebugThread(JdwpState* state)
378 {
379     if (state == NULL)
380         return 0;
381
382     return state->debugThreadHandle;
383 }
384
385
386 /*
387  * Support routines for waitForDebugger().
388  *
389  * We can't have a trivial "waitForDebugger" function that returns the
390  * instant the debugger connects, because we run the risk of executing code
391  * before the debugger has had a chance to configure breakpoints or issue
392  * suspend calls.  It would be nice to just sit in the suspended state, but
393  * most debuggers don't expect any threads to be suspended when they attach.
394  *
395  * There's no JDWP event we can post to tell the debugger, "we've stopped,
396  * and we like it that way".  We could send a fake breakpoint, which should
397  * cause the debugger to immediately send a resume, but the debugger might
398  * send the resume immediately or might throw an exception of its own upon
399  * receiving a breakpoint event that it didn't ask for.
400  *
401  * What we really want is a "wait until the debugger is done configuring
402  * stuff" event.  We can approximate this with a "wait until the debugger
403  * has been idle for a brief period".
404  */
405
406 /*
407  * Get a notion of the current time, in milliseconds.
408  */
409 s8 dvmJdwpGetNowMsec()
410 {
411 #ifdef HAVE_POSIX_CLOCKS
412     struct timespec now;
413     clock_gettime(CLOCK_MONOTONIC, &now);
414     return now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
415 #else
416     struct timeval now;
417     gettimeofday(&now, NULL);
418     return now.tv_sec * 1000LL + now.tv_usec / 1000LL;
419 #endif
420 }
421
422 /*
423  * Return the time, in milliseconds, since the last debugger activity.
424  *
425  * Returns -1 if no debugger is attached, or 0 if we're in the middle of
426  * processing a debugger request.
427  */
428 s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
429 {
430     if (!gDvm.debuggerActive) {
431         ALOGD("dvmJdwpLastDebuggerActivity: no active debugger");
432         return -1;
433     }
434
435     s8 last = dvmQuasiAtomicRead64(&state->lastActivityWhen);
436
437     /* initializing or in the middle of something? */
438     if (last == 0) {
439         ALOGV("+++ last=busy");
440         return 0;
441     }
442
443     /* now get the current time */
444     s8 now = dvmJdwpGetNowMsec();
445     assert(now >= last);
446
447     ALOGV("+++ debugger interval=%lld", now - last);
448     return now - last;
449 }