From e58ec4b8a0fbce0dc10421557bdc82ba90efa4fe Mon Sep 17 00:00:00 2001 From: "PSp..om" Date: Sun, 27 Mar 2011 05:39:00 +0000 Subject: [PATCH] Added code that will wake up the blocked kernel-caller if there are events to deal with. This wasn't a big deal for connects because there's always an accompanying message but for disconnects we wouldn't get events until the next message came through. Always meant to go back and fix it and now I have. Note: this is because our adapters use a single thread for pulling envelopes off and for dispatching connection events. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7123 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../com/jme3/network/base/KernelAdapter.java | 8 ++++++-- .../com/jme3/network/kernel/Kernel.java | 7 +++++++ .../jme3/network/kernel/tcp/SelectorKernel.java | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/engine/src/networking/com/jme3/network/base/KernelAdapter.java b/engine/src/networking/com/jme3/network/base/KernelAdapter.java index 8c5d5576c..55599ef13 100644 --- a/engine/src/networking/com/jme3/network/base/KernelAdapter.java +++ b/engine/src/networking/com/jme3/network/base/KernelAdapter.java @@ -140,7 +140,9 @@ public class KernelAdapter extends Thread byte[] data = env.getData(); ByteBuffer buffer = ByteBuffer.wrap(data); - protocol.addBuffer( buffer ); + int count = protocol.addBuffer( buffer ); + if( count == 0 ) + throw new RuntimeException( "Envelope contained incomplete data:" + env ); // Should be complete... and maybe we should check but we don't Message m = null; @@ -153,7 +155,7 @@ public class KernelAdapter extends Thread protected void createAndDispatch( EndpointEvent event ) { // Only need to tell the server about disconnects - if( event.getType() == EndpointEvent.Type.REMOVE ) { + if( event.getType() == EndpointEvent.Type.REMOVE ) { connectionClosed( event.getEndpoint() ); } } @@ -177,6 +179,8 @@ public class KernelAdapter extends Thread // Grab the next envelope Envelope e = kernel.read(); + if( e == Kernel.EVENTS_PENDING ) + continue; // We'll catch it up above // Check for pending events that might have // come in while we were blocking. This is usually diff --git a/engine/src/networking/com/jme3/network/kernel/Kernel.java b/engine/src/networking/com/jme3/network/kernel/Kernel.java index efb2bfdb7..5e456dca0 100644 --- a/engine/src/networking/com/jme3/network/kernel/Kernel.java +++ b/engine/src/networking/com/jme3/network/kernel/Kernel.java @@ -46,6 +46,13 @@ import com.jme3.network.Filter; */ public interface Kernel { + /** + * A marker envelope returned from read() that indicates that + * there are events pending. This allows a single thread to + * more easily process the envelopes and endpoint events. + */ + public static final Envelope EVENTS_PENDING = new Envelope( null, new byte[0], false ); + /** * Initializes the kernel and starts any internal processing. */ diff --git a/engine/src/networking/com/jme3/network/kernel/tcp/SelectorKernel.java b/engine/src/networking/com/jme3/network/kernel/tcp/SelectorKernel.java index 7840f7114..cc74730c0 100644 --- a/engine/src/networking/com/jme3/network/kernel/tcp/SelectorKernel.java +++ b/engine/src/networking/com/jme3/network/kernel/tcp/SelectorKernel.java @@ -160,11 +160,22 @@ public class SelectorKernel extends AbstractKernel protected void removeEndpoint( NioEndpoint p, SocketChannel c ) { +System.out.println( "removeEndpoint(" + p + ", " + c + ")" ); endpoints.remove( p.getId() ); // Enqueue an endpoint event for the listeners addEvent( EndpointEvent.createRemove( this, p ) ); - } + + // If there are no pending messages then add one so that the + // kernel-user knows to wake up if it is only listening for + // envelopes. + if( !hasEnvelopes() ) { + // Note: this is not really a race condition. At worst, our + // event has already been handled by now and it does no harm + // to check again. + addEnvelope( EVENTS_PENDING ); + } + } /** * Called by the endpoints when they need to be closed. @@ -393,7 +404,11 @@ public class SelectorKernel extends AbstractKernel i.remove(); if( !key.isValid() ) + { + // When does this happen? + log.log( Level.INFO, "Key is not valid:{0}.", key ); continue; + } if( key.isAcceptable() ) accept(key);