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.