OSDN Git Service

Work around a dalvik JDWP/GC deadlock.
[android-x86/dalvik.git] / vm / jdwp / JdwpSocket.cpp
index d318b50..eaea607 100644 (file)
@@ -50,10 +50,9 @@ static void netFree(JdwpNetState* state);
  *
  * We only talk to one debugger at a time.
  */
-struct JdwpNetState {
+struct JdwpNetState : public JdwpNetStateBase {
     short   listenPort;
     int     listenSock;         /* listen for connection from debugger */
-    int     clientSock;         /* active connection to debugger */
     int     wakePipe[2];        /* break out of select */
 
     struct in_addr remoteAddr;
@@ -64,6 +63,18 @@ struct JdwpNetState {
     /* pending data from the network; would be more efficient as circular buf */
     unsigned char  inputBuffer[kInputBufferSize];
     int     inputCount;
+
+    JdwpNetState()
+    {
+        listenPort  = 0;
+        listenSock  = -1;
+        wakePipe[0] = -1;
+        wakePipe[1] = -1;
+
+        awaitingHandshake = false;
+
+        inputCount = 0;
+    }
 };
 
 static JdwpNetState* netStartup(short port);
@@ -89,7 +100,7 @@ static bool prepareSocket(JdwpState* state, const JdwpStartupParams* pParams)
             }
         }
         if (state->netState == NULL) {
-            LOGE("JDWP net startup failed (req port=%d)\n", pParams->port);
+            ALOGE("JDWP net startup failed (req port=%d)", pParams->port);
             return false;
         }
     } else {
@@ -98,9 +109,9 @@ static bool prepareSocket(JdwpState* state, const JdwpStartupParams* pParams)
     }
 
     if (pParams->suspend)
-        LOGI("JDWP will wait for debugger on port %d\n", port);
+        ALOGI("JDWP will wait for debugger on port %d", port);
     else
-        LOGD("JDWP will %s on port %d\n",
+        ALOGD("JDWP will %s on port %d",
             pParams->server ? "listen" : "connect", port);
 
     return true;
@@ -129,15 +140,8 @@ static bool awaitingHandshake(JdwpState* state)
  */
 static JdwpNetState* netStartup(short port)
 {
-    JdwpNetState* netState;
     int one = 1;
-
-    netState = (JdwpNetState*) malloc(sizeof(*netState));
-    memset(netState, 0, sizeof(*netState));
-    netState->listenSock = -1;
-    netState->clientSock = -1;
-    netState->wakePipe[0] = -1;
-    netState->wakePipe[1] = -1;
+    JdwpNetState* netState = new JdwpNetState;
 
     if (port < 0)
         return netState;
@@ -146,7 +150,7 @@ static JdwpNetState* netStartup(short port)
 
     netState->listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (netState->listenSock < 0) {
-        LOGE("Socket create failed: %s\n", strerror(errno));
+        ALOGE("Socket create failed: %s", strerror(errno));
         goto fail;
     }
 
@@ -154,7 +158,7 @@ static JdwpNetState* netStartup(short port)
     if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one,
             sizeof(one)) < 0)
     {
-        LOGE("setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno));
+        ALOGE("setsockopt(SO_REUSEADDR) failed: %s", strerror(errno));
         goto fail;
     }
 
@@ -167,15 +171,15 @@ static JdwpNetState* netStartup(short port)
     inet_aton("127.0.0.1", &addr.addrInet.sin_addr);
 
     if (bind(netState->listenSock, &addr.addrPlain, sizeof(addr)) != 0) {
-        LOGV("attempt to bind to port %u failed: %s\n", port, strerror(errno));
+        ALOGV("attempt to bind to port %u failed: %s", port, strerror(errno));
         goto fail;
     }
 
     netState->listenPort = port;
-    LOGVV("+++ bound to port %d\n", netState->listenPort);
+    LOGVV("+++ bound to port %d", netState->listenPort);
 
     if (listen(netState->listenSock, 5) != 0) {
-        LOGE("Listen failed: %s\n", strerror(errno));
+        ALOGE("Listen failed: %s", strerror(errno));
         goto fail;
     }
 
@@ -221,8 +225,8 @@ static void netShutdown(JdwpNetState* netState)
 
     /* if we might be sitting in select, kick us loose */
     if (netState->wakePipe[1] >= 0) {
-        LOGV("+++ writing to wakePipe\n");
-        (void) write(netState->wakePipe[1], "", 1);
+        ALOGV("+++ writing to wakePipe");
+        TEMP_FAILURE_RETRY(write(netState->wakePipe[1], "", 1));
     }
 }
 static void netShutdownExtern(JdwpState* state)
@@ -251,7 +255,7 @@ static void netFree(JdwpNetState* netState)
         netState->wakePipe[1] = -1;
     }
 
-    free(netState);
+    delete netState;
 }
 static void netFreeExtern(JdwpState* state)
 {
@@ -289,7 +293,7 @@ static bool isFdReadable(int sock)
     if (FD_ISSET(sock, &readfds))   /* make sure it's our fd */
         return true;
 
-    LOGE("WEIRD: odd behavior in select (count=%d)\n", count);
+    ALOGE("WEIRD: odd behavior in select (count=%d)", count);
     return false;
 }
 #endif
@@ -355,27 +359,27 @@ static bool acceptConnection(JdwpState* state)
             // When we call shutdown() on the socket, accept() returns with
             // EINVAL.  Don't gripe about it.
             if (errno == EINVAL)
-                LOGVV("accept failed: %s\n", strerror(errno));
+                LOGVV("accept failed: %s", strerror(errno));
             else
-                LOGE("accept failed: %s\n", strerror(errno));
+                ALOGE("accept failed: %s", strerror(errno));
             return false;
         }
     } while (sock < 0);
 
     netState->remoteAddr = addr.addrInet.sin_addr;
     netState->remotePort = ntohs(addr.addrInet.sin_port);
-    LOGV("+++ accepted connection from %s:%u\n",
+    ALOGV("+++ accepted connection from %s:%u",
         inet_ntoa(netState->remoteAddr), netState->remotePort);
 
     netState->clientSock = sock;
     netState->awaitingHandshake = true;
     netState->inputCount = 0;
 
-    LOGV("Setting TCP_NODELAY on accepted socket\n");
+    ALOGV("Setting TCP_NODELAY on accepted socket");
     setNoDelay(netState->clientSock);
 
     if (pipe(netState->wakePipe) < 0) {
-        LOGE("pipe failed");
+        ALOGE("pipe failed");
         return false;
     }
 
@@ -410,7 +414,7 @@ static bool establishConnection(JdwpState* state)
     int cc = gethostbyname_r(state->params.host, &he, auxBuf, sizeof(auxBuf),
             &pEntry, &h_errno);
     if (cc != 0) {
-        LOGW("gethostbyname_r('%s') failed: %s\n",
+        ALOGW("gethostbyname_r('%s') failed: %s",
             state->params.host, strerror(errno));
         return false;
     }
@@ -419,7 +423,7 @@ static bool establishConnection(JdwpState* state)
     h_errno = 0;
     pEntry = gethostbyname(state->params.host);
     if (pEntry == NULL) {
-        LOGW("gethostbyname('%s') failed: %s\n",
+        ALOGW("gethostbyname('%s') failed: %s",
             state->params.host, strerror(h_errno));
         return false;
     }
@@ -431,7 +435,7 @@ static bool establishConnection(JdwpState* state)
 
     addr.addrInet.sin_port = htons(state->params.port);
 
-    LOGI("Connecting out to '%s' %d\n",
+    ALOGI("Connecting out to '%s' %d",
         inet_ntoa(addr.addrInet.sin_addr), ntohs(addr.addrInet.sin_port));
 
     /*
@@ -441,7 +445,7 @@ static bool establishConnection(JdwpState* state)
     netState = state->netState;
     netState->clientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (netState->clientSock < 0) {
-        LOGE("Unable to create socket: %s\n", strerror(errno));
+        ALOGE("Unable to create socket: %s", strerror(errno));
         return false;
     }
 
@@ -449,7 +453,7 @@ static bool establishConnection(JdwpState* state)
      * Try to connect.
      */
     if (connect(netState->clientSock, &addr.addrPlain, sizeof(addr)) != 0) {
-        LOGE("Unable to connect to %s:%d: %s\n",
+        ALOGE("Unable to connect to %s:%d: %s",
             inet_ntoa(addr.addrInet.sin_addr), ntohs(addr.addrInet.sin_port),
             strerror(errno));
         close(netState->clientSock);
@@ -457,7 +461,7 @@ static bool establishConnection(JdwpState* state)
         return false;
     }
 
-    LOGI("Connection established to %s (%s:%d)\n",
+    ALOGI("Connection established to %s (%s:%d)",
         state->params.host, inet_ntoa(addr.addrInet.sin_addr),
         ntohs(addr.addrInet.sin_port));
     netState->awaitingHandshake = true;
@@ -466,7 +470,7 @@ static bool establishConnection(JdwpState* state)
     setNoDelay(netState->clientSock);
 
     if (pipe(netState->wakePipe) < 0) {
-        LOGE("pipe failed");
+        ALOGE("pipe failed");
         return false;
     }
 
@@ -488,7 +492,7 @@ static void closeConnection(JdwpState* state)
     if (netState->clientSock < 0)
         return;
 
-    LOGV("+++ closed connection to %s:%u\n",
+    ALOGV("+++ closed connection to %s:%u",
         inet_ntoa(netState->remoteAddr), netState->remotePort);
 
     close(netState->clientSock);
@@ -564,7 +568,7 @@ static void dumpPacket(const unsigned char* packetBuf)
 
     dataLen = length - (buf - packetBuf);
 
-    LOGV("--- %s: dataLen=%u id=0x%08x flags=0x%02x cmd=%d/%d\n",
+    ALOGV("--- %s: dataLen=%u id=0x%08x flags=0x%02x cmd=%d/%d",
         reply ? "reply" : "req",
         dataLen, id, flags, cmdSet, cmd);
     if (dataLen > 0)
@@ -614,30 +618,23 @@ static bool handlePacket(JdwpState* state)
         hdr.cmd = cmd;
         dvmJdwpProcessRequest(state, &hdr, buf, dataLen, pReply);
         if (expandBufGetLength(pReply) > 0) {
-            int cc;
+            ssize_t cc = netState->writePacket(pReply);
 
-            /*
-             * TODO: we currently assume the write() will complete in one
-             * go, which may not be safe for a network socket.  We may need
-             * to mutex this against sendRequest().
-             */
-            cc = write(netState->clientSock, expandBufGetBuffer(pReply),
-                    expandBufGetLength(pReply));
-            if (cc != (int) expandBufGetLength(pReply)) {
-                LOGE("Failed sending reply to debugger: %s\n", strerror(errno));
+            if (cc != (ssize_t) expandBufGetLength(pReply)) {
+                ALOGE("Failed sending reply to debugger: %s", strerror(errno));
                 expandBufFree(pReply);
                 return false;
             }
         } else {
-            LOGW("No reply created for set=%d cmd=%d\n", cmdSet, cmd);
+            ALOGW("No reply created for set=%d cmd=%d", cmdSet, cmd);
         }
         expandBufFree(pReply);
     } else {
-        LOGV("reply?!\n");
+        ALOGV("reply?!");
         assert(false);
     }
 
-    LOGV("----------\n");
+    ALOGV("----------");
 
     consumeBytes(netState, length);
     return true;
@@ -681,7 +678,7 @@ static bool processIncoming(JdwpState* state)
                 maxfd = netState->wakePipe[0];
 
             if (maxfd < 0) {
-                LOGV("+++ all fds are closed\n");
+                ALOGV("+++ all fds are closed");
                 return false;
             }
 
@@ -698,7 +695,7 @@ static bool processIncoming(JdwpState* state)
             if (fd >= 0) {
                 FD_SET(fd, &readfds);
             } else {
-                LOGI("NOTE: entering select w/o wakepipe\n");
+                ALOGI("NOTE: entering select w/o wakepipe");
             }
 
             /*
@@ -717,7 +714,7 @@ static bool processIncoming(JdwpState* state)
             if (selCount < 0) {
                 if (errno == EINTR)
                     continue;
-                LOGE("select failed: %s\n", strerror(errno));
+                ALOGE("select failed: %s", strerror(errno));
                 goto fail;
             }
 
@@ -725,15 +722,15 @@ static bool processIncoming(JdwpState* state)
                 FD_ISSET(netState->wakePipe[0], &readfds))
             {
                 if (netState->listenSock >= 0)
-                    LOGE("Exit wake set, but not exiting?\n");
+                    ALOGE("Exit wake set, but not exiting?");
                 else
-                    LOGD("Got wake-up signal, bailing out of select\n");
+                    ALOGD("Got wake-up signal, bailing out of select");
                 goto fail;
             }
             if (netState->listenSock >= 0 &&
                 FD_ISSET(netState->listenSock, &readfds))
             {
-                LOGI("Ignoring second debugger -- accepting and dropping\n");
+                ALOGI("Ignoring second debugger -- accepting and dropping");
                 union {
                     struct sockaddr_in   addrInet;
                     struct sockaddr      addrPlain;
@@ -743,7 +740,7 @@ static bool processIncoming(JdwpState* state)
                 tmpSock = accept(netState->listenSock, &addr.addrPlain,
                                 &addrlen);
                 if (tmpSock < 0)
-                    LOGI("Weird -- accept failed\n");
+                    ALOGI("Weird -- accept failed");
                 else
                     close(tmpSock);
             }
@@ -757,11 +754,11 @@ static bool processIncoming(JdwpState* state)
                     /* read failed */
                     if (errno != EINTR)
                         goto fail;
-                    LOGD("+++ EINTR hit\n");
+                    ALOGD("+++ EINTR hit");
                     return true;
                 } else if (readCount == 0) {
                     /* EOF hit -- far end went away */
-                    LOGD("+++ peer disconnected\n");
+                    ALOGD("+++ peer disconnected");
                     goto fail;
                 } else
                     break;
@@ -787,22 +784,22 @@ static bool processIncoming(JdwpState* state)
         if (memcmp(netState->inputBuffer,
                 kMagicHandshake, kMagicHandshakeLen) != 0)
         {
-            LOGE("ERROR: bad handshake '%.14s'\n", netState->inputBuffer);
+            ALOGE("ERROR: bad handshake '%.14s'", netState->inputBuffer);
             goto fail;
         }
 
         errno = 0;
-        cc = write(netState->clientSock, netState->inputBuffer,
-                kMagicHandshakeLen);
+        cc = TEMP_FAILURE_RETRY(write(netState->clientSock, netState->inputBuffer,
+                                      kMagicHandshakeLen));
         if (cc != kMagicHandshakeLen) {
-            LOGE("Failed writing handshake bytes: %s (%d of %d)\n",
+            ALOGE("Failed writing handshake bytes: %s (%d of %d)",
                 strerror(errno), cc, (int) kMagicHandshakeLen);
             goto fail;
         }
 
         consumeBytes(netState, kMagicHandshakeLen);
         netState->awaitingHandshake = false;
-        LOGV("+++ handshake complete\n");
+        ALOGV("+++ handshake complete");
         return true;
     }
 
@@ -827,26 +824,20 @@ fail:
 static bool sendRequest(JdwpState* state, ExpandBuf* pReq)
 {
     JdwpNetState* netState = state->netState;
-    int cc;
 
     /*dumpPacket(expandBufGetBuffer(pReq));*/
     if (netState->clientSock < 0) {
         /* can happen with some DDMS events */
-        LOGV("NOT sending request -- no debugger is attached\n");
+        ALOGV("NOT sending request -- no debugger is attached");
         return false;
     }
 
-    /*
-     * TODO: we currently assume the write() will complete in one
-     * go, which may not be safe for a network socket.  We may need
-     * to mutex this against handlePacket().
-     */
     errno = 0;
-    cc = write(netState->clientSock, expandBufGetBuffer(pReq),
-            expandBufGetLength(pReq));
-    if (cc != (int) expandBufGetLength(pReq)) {
-        LOGE("Failed sending req to debugger: %s (%d of %d)\n",
-            strerror(errno), cc, (int) expandBufGetLength(pReq));
+    ssize_t cc = netState->writePacket(pReq);
+
+    if (cc != (ssize_t) expandBufGetLength(pReq)) {
+        ALOGE("Failed sending req to debugger: %s (%d of %d)",
+            strerror(errno), (int) cc, (int) expandBufGetLength(pReq));
         return false;
     }
 
@@ -868,7 +859,7 @@ static bool sendBufferedRequest(JdwpState* state, const struct iovec* iov,
 
     if (netState->clientSock < 0) {
         /* can happen with some DDMS events */
-        LOGV("NOT sending request -- no debugger is attached\n");
+        ALOGV("NOT sending request -- no debugger is attached");
         return false;
     }
 
@@ -877,15 +868,10 @@ static bool sendBufferedRequest(JdwpState* state, const struct iovec* iov,
     for (i = 0; i < iovcnt; i++)
         expected += iov[i].iov_len;
 
-    /*
-     * TODO: we currently assume the writev() will complete in one
-     * go, which may not be safe for a network socket.  We may need
-     * to mutex this against handlePacket().
-     */
-    ssize_t actual;
-    actual = writev(netState->clientSock, iov, iovcnt);
+    ssize_t actual = netState->writeBufferedPacket(iov, iovcnt);
+
     if ((size_t)actual != expected) {
-        LOGE("Failed sending b-req to debugger: %s (%d of %zu)\n",
+        ALOGE("Failed sending b-req to debugger: %s (%d of %zu)",
             strerror(errno), (int) actual, expected);
         return false;
     }