Revision: 7871
Author: [email protected]
Date: Fri Apr  2 19:51:57 2010
Log: Fixed bugs in server-side code, all tests pass.


http://code.google.com/p/google-web-toolkit/source/detail?r=7871

Modified:
/changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelClient.java /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/ShmFutexTransport.java /changes/jat/csproto/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java /changes/jat/csproto/dev/core/test/com/google/gwt/dev/shell/TestBrowserChannel.java
 /changes/jat/csproto/jni/linux/ShmFutexTransport.cpp
 /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86.so
 /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86_64.so
 /changes/jat/csproto/plugins/platform/Linux/Futex.cpp
 /changes/jat/csproto/plugins/platform/Linux/Futex.h
 /changes/jat/csproto/plugins/platform/Linux/ShmBuffer.h
 /changes/jat/csproto/plugins/platform/Linux/ShmFutex.cpp
 /changes/jat/csproto/plugins/platform/Linux/ShmFutex.h

=======================================
--- /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java Thu Apr 1 11:03:27 2010 +++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java Fri Apr 2 19:51:57 2010
@@ -1253,12 +1253,12 @@

     @Override
     public void send() throws IOException {
-      DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
-      getBrowserChannel().beginWriteMessage();
+      BrowserChannel channel = getBrowserChannel();
+      DataOutputStream stream = channel.getStreamToOtherSide();
+      channel.beginWriteMessage();
       stream.writeByte(MessageType.PROTOCOL_VERSION.getId());
       stream.writeInt(protocolVersion);
-      stream.flush();
-      getBrowserChannel().endWriteMessage();
+      channel.endWriteMessage();
     }
   }

@@ -1275,7 +1275,6 @@
       final DataOutputStream stream = channel.getStreamToOtherSide();
       channel.beginWriteMessage();
       stream.writeByte(MessageType.QUIT.getId());
-      stream.flush();
       channel.endWriteMessage();
     }

@@ -1314,7 +1313,6 @@
       DataOutputStream stream = channel.getStreamToOtherSide();
       channel.beginWriteMessage();
       stream.writeByte(MessageType.REQUEST_ICON.getId());
-      stream.flush();
       channel.endWriteMessage();
     }

@@ -1349,7 +1347,6 @@
       stream.writeBoolean(isException);
       channel.writeValue(stream, returnValue);
       channel.endWriteMessage();
-      stream.flush();
     }

     public static void send(BrowserChannel channel,
@@ -1425,12 +1422,13 @@

     @Override
     public void send() throws IOException {
-      DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
-      getBrowserChannel().beginWriteMessage();
+      BrowserChannel channel = getBrowserChannel();
+      DataOutputStream stream = channel.getStreamToOtherSide();
+      channel.beginWriteMessage();
       stream.writeByte(MessageType.SWITCH_TRANSPORT.getId());
       writeUtf8String(stream, transport);
       writeUtf8String(stream, transportArgs);
-      getBrowserChannel().endWriteMessage();
+      channel.endWriteMessage();
     }
   }

@@ -1469,7 +1467,6 @@
         }
       }
       channel.endWriteMessage();
-      stream.flush();
     }

     private byte[] iconBytes;
@@ -1642,14 +1639,23 @@
this(new DefaultTransport(inputStream, outputStream), objectRefFactory);
   }

+  /**
+   * Starts reading a message on the channel.
+   */
   public void beginReadMessage() {
     transport.beginReadMessage();
   }

+  /**
+   * Starts writing a message on the channel.
+   */
   public void beginWriteMessage() {
     transport.beginWriteMessage();
   }

+  /**
+   * Indicates a complete message has been read.
+   */
   public void endReadMessage() {
     transport.endReadMessage();
   }
@@ -1663,7 +1669,14 @@
     }
   }

+  /**
+ * Indicates a complete message has been written, flushes the output stream.
+   */
   public void endWriteMessage() {
+    try {
+      streamToOtherSide.flush();
+    } catch (IOException e) {
+    }
     transport.endWriteMessage();
   }

@@ -1706,6 +1719,12 @@
   protected DataOutputStream getStreamToOtherSide() {
     return streamToOtherSide;
   }
+
+  protected MessageType readMessageType() throws IOException,
+      BrowserChannelException {
+    beginReadMessage();
+    return Message.readMessageType(getStreamFromOtherSide());
+  }

   protected Value readValue(DataInputStream stream) throws IOException {
     ValueType tag;
=======================================
--- /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelClient.java Fri Feb 19 06:35:15 2010 +++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelClient.java Fri Apr 2 19:51:57 2010
@@ -125,7 +125,11 @@

   // TODO (amitmanjhi): refer the state (message?) transition diagram
   /**
-   * returns true iff execution completes normally.
+   * Process a client connection.
+   *
+   * @throws IOException
+   * @throws BrowserChannelException
+   * @return true on successful completion of LoadModule
    */
   public boolean process() throws IOException, BrowserChannelException {
     if (!init()) {
@@ -162,7 +166,7 @@
         + " message");
     new CheckVersionsMessage(this, PROTOCOL_VERSION_OLDEST,
         PROTOCOL_VERSION_CURRENT, versionString).send();
-    MessageType type = Message.readMessageType(getStreamFromOtherSide());
+    MessageType type = readMessageType();
     switch (type) {
       case PROTOCOL_VERSION:
ProtocolVersionMessage protocolMessage = ProtocolVersionMessage.receive(this);
@@ -178,7 +182,7 @@
       default:
         return false;
     }
-
+    // TODO(jat): try alternate transports?
     return true;
   }

@@ -186,7 +190,7 @@
       boolean expectReturn) throws IOException, BrowserChannelException {
     while (true) {
       ExceptionOrReturnValue returnValue;
-      MessageType type = Message.readMessageType(getStreamFromOtherSide());
+      MessageType type = readMessageType();
       logger.log(TreeLogger.INFO, "client: received " + type + ", thread: "
           + Thread.currentThread().getName());
       try {
=======================================
--- /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Thu Apr 1 11:03:27 2010 +++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Fri Apr 2 19:51:57 2010
@@ -281,9 +281,7 @@
   public void reactToMessages(SessionHandlerServer handler) {
     do {
       try {
-        beginReadMessage();
-        MessageType messageType = Message.readMessageType(
-            getStreamFromOtherSide());
+        MessageType messageType = readMessageType();
         switch (messageType) {
           case FREE_VALUE:
             final FreeMessage freeMsg = FreeMessage.receive(this);
@@ -300,8 +298,10 @@
             handleInvokeSpecial(handler);
             break;
           case QUIT:
+            QuitMessage.receive(this);
             return;
           default:
+            endReadMessage();
             throw new RemoteDeathError(new BrowserChannelException(
                 "Invalid message type " + messageType));
         }
@@ -326,10 +326,7 @@
SessionHandlerServer handler) throws BrowserChannelException, RemoteDeathError {
     do {
       try {
-        getStreamToOtherSide().flush();
-        beginReadMessage();
-        MessageType messageType = Message.readMessageType(
-            getStreamFromOtherSide());
+        MessageType messageType = readMessageType();
         switch (messageType) {
           case FREE_VALUE:
             final FreeMessage freeMsg = FreeMessage.receive(this);
@@ -348,10 +345,12 @@
             handleInvokeSpecial(handler);
             break;
           case QUIT:
+            QuitMessage.receive(this);
// if we got an unexpected QUIT here, the remote plugin probably // realized it was dying and had time to close the socket properly.
             throw new RemoteDeathError(null);
           default:
+            endReadMessage();
             throw new BrowserChannelException("Invalid message type "
                 + messageType + " received waiting for return.");
         }
@@ -372,26 +371,13 @@
       logger.log(TreeLogger.ERROR,
           "Unrecognized command for client; closing connection", e);
     } finally {
-      try {
-        shutdown();
-      } catch (IOException ignored) {
-      }
       endSession();
     }
   }
-
-  /**
-   * Close the connection to the browser.
-   *
-   * @throws IOException
-   */
-  public void shutdown() throws IOException {
-    QuitMessage.send(this);
-  }

   // @VisibleForTesting
protected void processConnection() throws IOException, BrowserChannelException {
-    MessageType type = Message.readMessageType(getStreamFromOtherSide());
+    MessageType type = readMessageType();
     // TODO(jat): add support for getting the a shim plugin downloading the
     //    real plugin via a GetRealPlugin message before CheckVersions
     String url = null;
@@ -460,7 +446,7 @@
         }
         protocolVersion = Math.min(PROTOCOL_VERSION_CURRENT, maxVersion);
         new ProtocolVersionMessage(this, protocolVersion).send();
-        type = Message.readMessageType(getStreamFromOtherSide());
+        type = readMessageType();

// Optionally allow client to request switch of transports. Inband is // always supported, so a return of an empty transport string requires
@@ -484,7 +470,7 @@
           if (newTransport != null) {
             changeTransport(newTransport);
           }
-          type = Message.readMessageType(getStreamFromOtherSide());
+          type = readMessageType();
         }

         // Now we expect a LoadModule message to load a GWT module.
@@ -518,7 +504,7 @@
           iconBytes = iconCache.get(userAgent);
         } else {
           RequestIconMessage.send(this);
-          type = Message.readMessageType(getStreamFromOtherSide());
+          type = readMessageType();
           if (type != MessageType.USER_AGENT_ICON) {
             logger.log(TreeLogger.ERROR, "Unexpected message type " + type
                 + "; expecting UserAgentIcon");
=======================================
--- /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/ShmFutexTransport.java Fri Apr 2 12:22:36 2010 +++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/ShmFutexTransport.java Fri Apr 2 19:51:57 2010
@@ -18,6 +18,7 @@
 import com.google.gwt.dev.shell.TransportFactory.TransportArgs;

 import java.io.Closeable;
+import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -31,16 +32,6 @@
  */
 public class ShmFutexTransport implements Transport {

-  private interface ShmFutexInputStream extends Closeable {
-    boolean beginRead();
-    void endRead();
-  }
-
-  private interface ShmFutexOutputStream extends Closeable {
-    boolean beginWrite();
-    void endWrite();
-  }
-
   /**
    * InputStream for the client side of the shm+futex transport.
    */
@@ -49,7 +40,7 @@

     public boolean beginRead() {
       boolean success = false;
-      // HACK: retry for a while, need to handle fragmentation
+      // HACK: retry for a while, need to handle other side dying
       for (int i = 0; i < 100; ++i) {
         success = nativeBeginClientRead(shmFutexAddr);
         if (success) {
@@ -73,6 +64,9 @@
     public int read() {
       try {
         if (serverToClientBuf.position() >= serverToClientBuf.limit()) {
+          if (serverToClientBuf.limit() == 0) {
+            return -1;
+          }
           // ran out of buffer, mark free and wait for full again
           nativeEndClientRead(shmFutexAddr);
           if (!nativeBeginClientRead(shmFutexAddr)) {
@@ -128,6 +122,9 @@
     public void write(int b) throws IOException {
       try {
         if (clientToServerBuf.position() >= clientToServerBuf.limit()) {
+          if (clientToServerBuf.limit() == 0) {
+            throw new EOFException();
+          }
           // ran out of buffer, mark free and wait for full again
           nativeEndClientWrite(shmFutexAddr);
           if (!nativeBeginClientWrite(shmFutexAddr)) {
@@ -143,6 +140,16 @@
       }
     }
   }
+
+  private interface ShmFutexInputStream extends Closeable {
+    boolean beginRead();
+    void endRead();
+  }
+
+  private interface ShmFutexOutputStream extends Closeable {
+    boolean beginWrite();
+    void endWrite();
+  }

   /**
    * InputStream for the server side of the shm+futex transport.
@@ -152,7 +159,7 @@

     public boolean beginRead() {
       boolean success = false;
-      // HACK: retry for a while, need to handle fragmentation
+      // HACK: retry for a while, need to handle other side dying
       for (int i = 0; i < 100; ++i) {
         success = nativeBeginServerRead(shmFutexAddr);
         if (success) {
@@ -180,6 +187,9 @@
     public int read() {
       try {
         if (clientToServerBuf.position() >= clientToServerBuf.limit()) {
+          if (clientToServerBuf.limit() == 0) {
+            return -1;
+          }
           // ran out of buffer, mark free and wait for full again
           nativeEndServerRead(shmFutexAddr);
           if (!nativeBeginServerRead(shmFutexAddr)) {
@@ -235,6 +245,9 @@
     public void write(int b) throws IOException {
       try {
         if (serverToClientBuf.position() >= serverToClientBuf.limit()) {
+          if (serverToClientBuf.limit() == 0) {
+            throw new EOFException();
+          }
           // ran out of buffer, mark free and wait for full again
           nativeEndServerWrite(shmFutexAddr);
           if (!nativeBeginServerWrite(shmFutexAddr)) {
@@ -354,9 +367,23 @@
   private static native MappedByteBuffer nativeGetClientToServerBuf(
       long shmFutexAddr);

+  /**
+   * Get the current futex status.  Note that this should only be used for
+   * debugging, as there is no protectection against these values changing
+   * while being read, and they may have changed since they were read.  The
+   * only guarantee is that the value returned for each one existed at one
+   * point.
+   *
+   * @param shmFutexAddr
+ * @param status int[4] containing the client->server full, C->S empty, S->C
+   *     full, and S->C empty futex status words
+   */
+  private static native void nativeGetFutexStatus(long shmFutexAddr,
+      int[] status);
+
   private static native MappedByteBuffer nativeGetServerToClientBuf(
       long shmFutexAddr);
-
+
   /**
    * Remove the shm key (existing mappings will keep the segment around
    * until they are detached).
@@ -371,7 +398,7 @@
    * @param ownsShm true if this instance owns the shm segment
    */
private static native void nativeShutdown(long shmFutexAddr, boolean ownsShm);
-
+
   private boolean readMessage = false;

   /**
@@ -391,6 +418,11 @@

   private final String key;

+  /**
+   * Lock held while closing the channel.
+   */
+  private final Object closeLock = new Object();
+
   private ShmFutexTransport(long shmFutexAddr, String key) {
     this.shmFutexAddr = shmFutexAddr;
     this.key = key;
@@ -410,27 +442,29 @@
     istr = new ShmFutexServerInputStream();
     ostr = new ShmFutexServerOutputStream();
   }
-
+
   public boolean beginReadMessage() {
     return istr.beginRead();
   }
-
+
   public boolean beginWriteMessage() {
     return ostr.beginWrite();
   }

   public void closeChannel() {
-    try {
-      istr.close();
-    } catch (IOException ignored) {
-    }
-    try {
-      ostr.close();
-    } catch (IOException ignored) {
-    }
-    if (shmFutexAddr != 0) {
-      nativeShutdown(shmFutexAddr, ownsShm);
-      shmFutexAddr = 0;
+    synchronized (closeLock) {
+      try {
+        istr.close();
+      } catch (IOException ignored) {
+      }
+      try {
+        ostr.close();
+      } catch (IOException ignored) {
+      }
+      if (shmFutexAddr != 0) {
+        nativeShutdown(shmFutexAddr, ownsShm);
+        shmFutexAddr = 0;
+      }
     }
   }

@@ -449,7 +483,24 @@
   public OutputStream getOutputStream() {
     return (OutputStream) ostr;
   }
-
+
+  @Override
+  public String toString() {
+    StringBuilder buf = new StringBuilder();
+    buf.append("shmFutexAddr=0x" + Long.toHexString(shmFutexAddr));
+    if (shmFutexAddr != 0) {
+      int[] status = new int[4];
+      nativeGetFutexStatus(shmFutexAddr, status);
+ buf.append(": C->S full=").append(status[0]).append(", empty=").append(
+          status[1]).append(": ");
+      appendBuf(buf, clientToServerBuf, 8);
+ buf.append("; S->C full=" + status[2] + ", empty=" + status[3]).append(
+          ": ");
+      appendBuf(buf, serverToClientBuf, 8);
+    }
+    return buf.toString();
+  }
+
   @Override
   protected void finalize() throws Throwable {
     if (shmFutexAddr != 0) {
@@ -457,8 +508,25 @@
       shmFutexAddr = 0;
     }
   }
-
+
   protected void removeKey() {
     nativeRemoveKey(key);
   }
-}
+
+  /**
+ * For debugging purposes, add the first few bytes of the supplied bytebuffer
+   * onto an output buffer.
+   *
+   * @param buf
+   * @param mappedBuf
+   * @param n
+   */
+ private void appendBuf(StringBuilder buf, MappedByteBuffer mappedBuf, int n) {
+    String zeros = "00";
+    for (int i = 0; i < n; ++i) {
+      byte val = mappedBuf.get(i);
+      String hex = Integer.toHexString(val & 255);
+      buf.append(' ').append(zeros.substring(hex.length())).append(hex);
+    }
+  }
+}
=======================================
--- /changes/jat/csproto/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java Thu Apr 1 11:03:27 2010 +++ /changes/jat/csproto/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java Fri Apr 2 19:51:57 2010
@@ -44,31 +44,6 @@
  * protocol versions.
  */
 public class BrowserChannelServerTest extends TestCase {
-
-  /**
-   * A BrowserChannelServer that can notify when the connection is closed.
-   */
-  private class TestBrowserChannelServer extends BrowserChannelServer {
-
-    private final Semaphore finishNotify = new Semaphore(0);
-
-    public TestBrowserChannelServer(TreeLogger logger,
-        InputStream inputStream, OutputStream outputStream,
-        SessionHandlerServer handler) {
-      super(logger, inputStream, outputStream, handler, true);
-    }
-
-    @Override
-    protected void processConnection() throws IOException,
-        BrowserChannelException {
-      super.processConnection();
-      finishNotify.release();
-    }
-
-    public void waitForClose() throws InterruptedException {
-      finishNotify.acquire();
-    }
-  }

   /**
    * Maintains a connected pair of piped streams.
@@ -98,6 +73,31 @@
       return output;
     }
   }
+
+  /**
+   * A BrowserChannelServer that can notify when the connection is closed.
+   */
+  private class TestBrowserChannelServer extends BrowserChannelServer {
+
+    private final Semaphore finishNotify = new Semaphore(0);
+
+    public TestBrowserChannelServer(TreeLogger logger,
+        InputStream inputStream, OutputStream outputStream,
+        SessionHandlerServer handler) {
+      super(logger, inputStream, outputStream, handler, true);
+    }
+
+    public void waitForClose() throws InterruptedException {
+      finishNotify.acquire();
+    }
+
+    @Override
+    protected void processConnection() throws IOException,
+        BrowserChannelException {
+      super.processConnection();
+      finishNotify.release();
+    }
+  }

   /**
    * A SessionHandler which keeps track of parameters from the LoadModule
@@ -200,44 +200,7 @@
       // TODO: some way to make test show skipped instead of passed?
       return;
     }
-    TestSessionHandler handler = new TestSessionHandler();
-    TestBrowserChannelServer server = new TestBrowserChannelServer(
-        new FailErrorLogger(), clientToServer.getInputStream(),
-        serverToClient.getOutputStream(), handler);
-    TestBrowserChannel client = new TestBrowserChannel(
-        serverToClient.getInputStream(), clientToServer.getOutputStream());
-    new CheckVersionsMessage(client, 2, 2,
-        HostedHtmlVersion.EXPECTED_GWT_ONLOAD_VERSION).send();
-    MessageType type = client.readMessageType();
-    assertEquals(MessageType.PROTOCOL_VERSION, type);
- ProtocolVersionMessage protocolMessage = ProtocolVersionMessage.receive(
-        client);
-    assertEquals(2, protocolMessage.getProtocolVersion());
-    String shmFutexName = factory.getName();
- new ChooseTransportMessage(client, new String[] {shmFutexName }).send();
-    type = client.readMessageType();
-    assertEquals(MessageType.SWITCH_TRANSPORT, type);
-    SwitchTransportMessage switchMessage = SwitchTransportMessage.receive(
-        client);
-    assertEquals(shmFutexName, switchMessage.getTransport());
-    Transport transport = factory.connectTransport(
-        switchMessage.getTransportArgs());
-    assertNotNull(transport);
-    client.changeTransport(transport);
-    new LoadModuleMessage(client, "url", "tabkey", "session", "testModule",
-        "userAgent").send();
-    type = client.readMessageType();
-    assertEquals("testModule", handler.getModuleName());
-    assertEquals("userAgent", handler.getUserAgent());
-    assertEquals("url", handler.getUrl());
-    assertEquals("tabkey", handler.getTabKey());
-    assertEquals("session", handler.getSessionKey());
-    assertNull(handler.getUserAgentIcon());
-    assertEquals(MessageType.RETURN, type);
-    ReturnMessage.receive(client);
-    QuitMessage.send(client);
-    server.waitForClose();
-    assertNull(handler.getLoadedModule());
+    protocolVersion2Test(factory);
   }

   /**
@@ -278,6 +241,18 @@
    * @throws InterruptedException
    */
   public void testVersion2() throws IOException, BrowserChannelException,
+      InterruptedException {
+    protocolVersion2Test(null);
+  }
+
+  /**
+   * Test a version 3 client interacting with the server.
+   *
+   * @throws IOException
+   * @throws BrowserChannelException
+   * @throws InterruptedException
+   */
+  public void testVersion3() throws IOException, BrowserChannelException,
       InterruptedException {
     TestSessionHandler handler = new TestSessionHandler();
     TestBrowserChannelServer server = new TestBrowserChannelServer(
@@ -285,22 +260,34 @@
         serverToClient.getOutputStream(), handler);
     TestBrowserChannel client = new TestBrowserChannel(
         serverToClient.getInputStream(), clientToServer.getOutputStream());
-    new CheckVersionsMessage(client, 2, 2,
+    new CheckVersionsMessage(client, 2, 3,
         HostedHtmlVersion.EXPECTED_GWT_ONLOAD_VERSION).send();
     MessageType type = client.readMessageType();
     assertEquals(MessageType.PROTOCOL_VERSION, type);
ProtocolVersionMessage protocolMessage = ProtocolVersionMessage.receive(
         client);
-    assertEquals(2, protocolMessage.getProtocolVersion());
+    assertEquals(3, protocolMessage.getProtocolVersion());
     new LoadModuleMessage(client, "url", "tabkey", "session", "testModule",
         "userAgent").send();
     type = client.readMessageType();
+    byte[] iconBytes = null;
+    if (type == MessageType.REQUEST_ICON) {
+      RequestIconMessage.receive(client);
+      iconBytes = new byte[] { 0, 1, 2, 3, 4, 5 };
+      UserAgentIconMessage.send(client, iconBytes);
+      type = client.readMessageType();
+    }
     assertEquals("testModule", handler.getModuleName());
     assertEquals("userAgent", handler.getUserAgent());
     assertEquals("url", handler.getUrl());
     assertEquals("tabkey", handler.getTabKey());
     assertEquals("session", handler.getSessionKey());
-    assertNull(handler.getUserAgentIcon());
+    byte[] receivedIcon = handler.getUserAgentIcon();
+    assertNotNull(receivedIcon);
+    assertEquals(iconBytes.length, receivedIcon.length);
+    for (int i = 0; i < iconBytes.length; ++i) {
+      assertEquals(iconBytes[i], receivedIcon[i]);
+    }
     assertEquals(MessageType.RETURN, type);
     ReturnMessage.receive(client);
     QuitMessage.send(client);
@@ -309,51 +296,63 @@
   }

   /**
-   * Test a version 3 client interacting with the server.
+   * Tests protocol version 2, optionally with an alternate transport.
    *
-   * @throws IOException
-   * @throws BrowserChannelException
-   * @throws InterruptedException
+   * @param factory factory for alternate transport, or null if none
+   * @throws IOException
+   * @throws BrowserChannelException
+   * @throws InterruptedException
    */
-  public void testVersion3() throws IOException, BrowserChannelException,
-      InterruptedException {
+  private void protocolVersion2Test(TransportFactory factory)
+      throws IOException, BrowserChannelException, InterruptedException {
     TestSessionHandler handler = new TestSessionHandler();
     TestBrowserChannelServer server = new TestBrowserChannelServer(
         new FailErrorLogger(), clientToServer.getInputStream(),
         serverToClient.getOutputStream(), handler);
     TestBrowserChannel client = new TestBrowserChannel(
         serverToClient.getInputStream(), clientToServer.getOutputStream());
-    new CheckVersionsMessage(client, 2, 3,
+
+    // exchange protocol versions
+    new CheckVersionsMessage(client, 2, 2,
         HostedHtmlVersion.EXPECTED_GWT_ONLOAD_VERSION).send();
     MessageType type = client.readMessageType();
     assertEquals(MessageType.PROTOCOL_VERSION, type);
ProtocolVersionMessage protocolMessage = ProtocolVersionMessage.receive(
         client);
-    assertEquals(3, protocolMessage.getProtocolVersion());
+    assertEquals(2, protocolMessage.getProtocolVersion());
+
+    // try the alternate transport if we have one
+    if (factory != null) {
+      String transportName = factory.getName();
+ new ChooseTransportMessage(client, new String[] {transportName }).send();
+      type = client.readMessageType();
+      assertEquals(MessageType.SWITCH_TRANSPORT, type);
+ SwitchTransportMessage switchMessage = SwitchTransportMessage.receive(
+          client);
+      assertEquals(transportName, switchMessage.getTransport());
+      Transport transport = factory.connectTransport(
+          switchMessage.getTransportArgs());
+      assertNotNull(transport);
+      client.changeTransport(transport);
+    }
+
+    // send the load module message, wait for return value
     new LoadModuleMessage(client, "url", "tabkey", "session", "testModule",
         "userAgent").send();
     type = client.readMessageType();
-    byte[] iconBytes = null;
-    if (type == MessageType.REQUEST_ICON) {
-      RequestIconMessage.receive(client);
-      iconBytes = new byte[] { 0, 1, 2, 3, 4, 5 };
-      UserAgentIconMessage.send(client, iconBytes);
-      type = client.readMessageType();
-    }
+    assertEquals(MessageType.RETURN, type);
+    ReturnMessage.receive(client);
+
+    // after return these should be set
     assertEquals("testModule", handler.getModuleName());
     assertEquals("userAgent", handler.getUserAgent());
     assertEquals("url", handler.getUrl());
     assertEquals("tabkey", handler.getTabKey());
     assertEquals("session", handler.getSessionKey());
-    byte[] receivedIcon = handler.getUserAgentIcon();
-    assertNotNull(receivedIcon);
-    assertEquals(iconBytes.length, receivedIcon.length);
-    for (int i = 0; i < iconBytes.length; ++i) {
-      assertEquals(iconBytes[i], receivedIcon[i]);
-    }
-    assertEquals(MessageType.RETURN, type);
-    ReturnMessage.receive(client);
+    assertNull(handler.getUserAgentIcon());
     QuitMessage.send(client);
+
+    // wait for the server to shutdown, and verify that no module is loaded
     server.waitForClose();
     assertNull(handler.getLoadedModule());
   }
=======================================
--- /changes/jat/csproto/dev/core/test/com/google/gwt/dev/shell/TestBrowserChannel.java Tue Oct 13 16:57:19 2009 +++ /changes/jat/csproto/dev/core/test/com/google/gwt/dev/shell/TestBrowserChannel.java Fri Apr 2 19:51:57 2010
@@ -45,6 +45,6 @@
   public MessageType readMessageType() throws IOException,
       BrowserChannelException {
     getStreamToOtherSide().flush();
-    return Message.readMessageType(getStreamFromOtherSide());
+    return super.readMessageType();
   }
 }
=======================================
--- /changes/jat/csproto/jni/linux/ShmFutexTransport.cpp Wed Mar 31 18:19:25 2010 +++ /changes/jat/csproto/jni/linux/ShmFutexTransport.cpp Fri Apr 2 19:51:57 2010
@@ -145,6 +145,22 @@
   env->SetObjectArrayElement(outputKey, 0, keyStr);
   return reinterpret_cast<jlong>(shmFutex);
 }
+
+/*
+ * Class:     com_google_gwt_dev_shell_ShmFutexTransport
+ * Method:    nativeGetFutexStatus
+ * Signature: (J[I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_ShmFutexTransport_nativeGetFutexStatus
+    (JNIEnv *env, jclass, jlong addr, jintArray outputStatus) {
+  ShmFutex* shmFutex = reinterpret_cast<ShmFutex*>(addr);
+  int futexStatus[2];
+  shmFutex->getClientToServerFutexStatus(futexStatus);
+  env->SetIntArrayRegion(outputStatus, 0, 2, futexStatus);
+  shmFutex->getServerToClientFutexStatus(futexStatus);
+  env->SetIntArrayRegion(outputStatus, 2, 2, futexStatus);
+}

 /*
  * Class:     com_google_gwt_dev_shell_ShmFutexTransport
=======================================
--- /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86.so Wed Mar 31 20:30:31 2010 +++ /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86.so Fri Apr 2 19:51:57 2010
Binary file, no diff available.
=======================================
--- /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86_64.so Wed Mar 31 20:30:31 2010 +++ /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86_64.so Fri Apr 2 19:51:57 2010
Binary file, no diff available.
=======================================
--- /changes/jat/csproto/plugins/platform/Linux/Futex.cpp Wed Mar 31 17:07:40 2010 +++ /changes/jat/csproto/plugins/platform/Linux/Futex.cpp Fri Apr 2 19:51:57 2010
@@ -65,6 +65,13 @@
 Futex::Futex(bool locked) : lockWord(locked ? LOCKED : UNLOCKED) {
   // TODO(jat): register Futex for kernel cleanup
 }
+
+void Futex::destroy() {
+  // TODO(jat): unregister Futex for kernel cleanup
+  lockWord = UNLOCKED | FUTEX_OWNER_DIED;
+  // wake up everyone
+  futex(&lockWord, FUTEX_WAKE, 0x7fffffff, 0, 0, 0);
+}

 bool Futex::lock(bool wantTimeout) {
   while (true) {
=======================================
--- /changes/jat/csproto/plugins/platform/Linux/Futex.h Wed Mar 31 12:05:41 2010 +++ /changes/jat/csproto/plugins/platform/Linux/Futex.h Fri Apr 2 19:51:57 2010
@@ -20,13 +20,22 @@
 public:
   enum State { UNLOCKED=0, LOCKED=1, WAITING=2 };

+ // note that the constructor should only be called for the one that actually
+  // owns it -- others should just start using it without initialization
   Futex(bool locked = false);

+  // see above: the destructor will render the futex unusable, and wake up
+  // anyone waiting on the futex
+  void destroy();
+
   // returns true if successful, false if timed out (if requested)
   // (caller should verify the other side is there and retry)
   bool lock(bool wantTimeout = false);
   void unlock();

+  // use only for debugging!
+  int getStatus() { return lockWord; }
+
   void dump();
 private:
   // TODO: register Futexes using robust futex mechanism
=======================================
--- /changes/jat/csproto/plugins/platform/Linux/ShmBuffer.h Wed Mar 31 10:18:10 2010 +++ /changes/jat/csproto/plugins/platform/Linux/ShmBuffer.h Fri Apr 2 19:51:57 2010
@@ -35,6 +35,12 @@
   void endWrite() { fullLock.unlock(); }

   volatile char* getBuf() { return (volatile char*) buf; }
+
+  // use only for debugging!
+  void getFutexStatus(int* status) {
+    status[0] = fullLock.getStatus();
+    status[1] = emptyLock.getStatus();
+  }

   void dump() {
     printf("  full lock = ");
@@ -42,6 +48,13 @@
     printf("  empty lock = ");
     emptyLock.dump();
   }
+
+  // only call this if you want to destory the underlying futexes and cause
+  // all waiters to wake up and fail
+  void destroy() {
+    fullLock.destroy();
+    emptyLock.destroy();
+  }
 private:
   Futex fullLock;
   Futex emptyLock;
=======================================
--- /changes/jat/csproto/plugins/platform/Linux/ShmFutex.cpp Wed Mar 31 17:07:40 2010 +++ /changes/jat/csproto/plugins/platform/Linux/ShmFutex.cpp Fri Apr 2 19:51:57 2010
@@ -83,6 +83,8 @@

 // detach this memory segment, destroy futexes
 ShmFutex::~ShmFutex() {
+  clientToServer.destroy();
+  serverToClient.destroy();
   detach();
 }

=======================================
--- /changes/jat/csproto/plugins/platform/Linux/ShmFutex.h Wed Mar 31 17:07:40 2010 +++ /changes/jat/csproto/plugins/platform/Linux/ShmFutex.h Fri Apr 2 19:51:57 2010
@@ -65,6 +65,13 @@
   volatile char* getClientToServerBuf() { return clientToServer.getBuf(); }
   volatile char* getServerToClientBuf() { return serverToClient.getBuf(); }

+  // use only for debugging!
+  void getClientToServerFutexStatus(int* status) {
+    clientToServer.getFutexStatus(status);
+  }
+  void getServerToClientFutexStatus(int* status) {
+    serverToClient.getFutexStatus(status);
+  }
   void dump();
 private:
   int magic;

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

To unsubscribe, reply using "remove me" as the subject.

Reply via email to