Index: src/org/jruby/RubyIO.java
===================================================================
RCS file: /var/cvs/jruby/jruby/src/org/jruby/RubyIO.java,v
retrieving revision 1.54
diff -u -r1.54 RubyIO.java
--- src/org/jruby/RubyIO.java	15 Jun 2006 14:17:22 -0000	1.54
+++ src/org/jruby/RubyIO.java	27 Jun 2006 19:14:51 -0000
@@ -17,7 +17,7 @@
  * Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
  * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
- * Copyright (C) 2006 Evan Buswell <evan@heron.sytes.net>
+ * Copyright (C) 2006 Evan Buswell <ebuswell@gmail.com>
  * 
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
@@ -40,7 +40,6 @@
 import java.io.OutputStream;
 import java.lang.ref.WeakReference;
 import java.nio.channels.Channel;
-import java.nio.channels.SelectableChannel;
 
 import org.jruby.runtime.builtin.IRubyObject;
 import org.jruby.util.IOHandler;
@@ -808,6 +807,13 @@
         return result;
     }
 
+    public boolean getBlocking() {
+	if(!(handler instanceof IOHandlerNio)) {
+	    return true;
+	}
+	return ((IOHandlerNio) handler).getBlocking();
+    }
+
     public IRubyObject fcntl(IRubyObject cmd, IRubyObject arg) throws IOException {
         long realCmd = cmd.convertToInteger().getLongValue();
         
@@ -826,15 +832,18 @@
             if((realArg & IOModes.NONBLOCK) == IOModes.NONBLOCK) {
                 block = true;
             }
-            
-            Channel channel = getChannel();
-            if (channel != null && channel instanceof SelectableChannel) {
-                try {
-                    ((SelectableChannel)channel).configureBlocking(block);
-                } catch (IOException e) {
-                    throw getRuntime().newIOError(e.getMessage());
-                }
-            }         
+
+	    if(!(handler instanceof IOHandlerNio)) {
+		// cryptic for the uninitiated...
+		throw getRuntime().newNotImplementedError("FCNTL only works with Nio based handlers");
+	    }
+	
+	    try {
+		((IOHandlerNio) handler).setBlocking(block);
+            } catch (IOException e) {
+		throw getRuntime().newIOError(e.getMessage());
+	    }
+
         }
         
         return getRuntime().newFixnum(0);
Index: src/org/jruby/runtime/builtin/meta/IOMetaClass.java
===================================================================
RCS file: /var/cvs/jruby/jruby/src/org/jruby/runtime/builtin/meta/IOMetaClass.java,v
retrieving revision 1.19
diff -u -r1.19 IOMetaClass.java
--- src/org/jruby/runtime/builtin/meta/IOMetaClass.java	14 Jun 2006 03:13:53 -0000	1.19
+++ src/org/jruby/runtime/builtin/meta/IOMetaClass.java	27 Jun 2006 19:14:52 -0000
@@ -15,7 +15,7 @@
  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  * Copyright (C) 2005 Thomas E Enebo <enebo@acm.org>
  * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
- * Copyright (C) 2006 Evan Buswell <evan@heron.sytes.net>
+ * Copyright (C) 2006 Evan Buswell <ebuswell@gmail.com>
  * 
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
@@ -276,17 +276,17 @@
             ret.add(RubyArray.newArray(runtime, r));
             ret.add(RubyArray.newArray(runtime, w));
             ret.add(RubyArray.newArray(runtime, e));
-            // make all sockets blocking again
-            List toReset = new ArrayList();
+            // make all sockets blocking as configured again
             for (Iterator i = selector.keys().iterator(); i.hasNext(); ) {
                 SelectionKey key = (SelectionKey) i.next();
-                toReset.add(key.channel());
+		SelectableChannel channel = key.channel();
+		synchronized(channel.blockingLock()) {
+		    boolean blocking = ((RubyIO) key.attachment()).getBlocking();
+		    key.cancel();
+		    channel.configureBlocking(blocking);
+		}
             }
             selector.close();
-            for (Iterator i = toReset.iterator(); i.hasNext(); ) {
-                SelectableChannel channel = (SelectableChannel) i.next();
-                channel.configureBlocking(true);
-            }
             return RubyArray.newArray(runtime, ret);
         } catch(IOException e) {
             throw runtime.newIOError(e.getMessage());
Index: src/org/jruby/util/IOHandlerNio.java
===================================================================
RCS file: /var/cvs/jruby/jruby/src/org/jruby/util/IOHandlerNio.java,v
retrieving revision 1.3
diff -u -r1.3 IOHandlerNio.java
--- src/org/jruby/util/IOHandlerNio.java	22 Jun 2006 01:28:00 -0000	1.3
+++ src/org/jruby/util/IOHandlerNio.java	27 Jun 2006 19:14:52 -0000
@@ -11,7 +11,7 @@
  * implied. See the License for the specific language governing
  * rights and limitations under the License.
  *
- * Copyright (C) 2006 Evan Buswell <evan@heron.sytes.net>
+ * Copyright (C) 2006 Evan Buswell <ebuswell@gmail.com>
  * 
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
@@ -36,8 +36,9 @@
 import java.nio.channels.Channel;
 import java.nio.channels.WritableByteChannel;
 import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.SelectableChannel;
 import java.nio.channels.FileChannel;
-import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.IllegalBlockingModeException;
 import java.nio.ByteBuffer;
 
 import java.io.IOException;
@@ -51,6 +52,7 @@
     private ByteBuffer inBuffer;
 
     private boolean bufferedIO = false;
+    private boolean blocking = true;
 
     public IOHandlerNio(IRuby runtime, Channel channel) throws IOException {
         super(runtime);
@@ -64,9 +66,6 @@
             mode += "w";
             isOpen = true;
         }
-        if (channel instanceof AbstractSelectableChannel) {
-            ((AbstractSelectableChannel)channel).configureBlocking(false);
-        }
         if ("rw".equals(mode)) {
             modes = new IOModes(runtime, IOModes.RDWR);
             isOpen = true;
@@ -99,6 +98,23 @@
         }
     }
 
+    public void setBlocking(boolean block) throws IOException {
+	if(!(channel instanceof SelectableChannel))
+	    return;
+	synchronized(((SelectableChannel) channel).blockingLock()) {
+	    blocking = block;
+	    try {
+		((SelectableChannel) channel).configureBlocking(block);
+	    } catch(IllegalBlockingModeException e) {
+		// ignore this; select() will set the correct mode when it is finished
+	    }
+	}
+    }
+
+    public boolean getBlocking() {
+	return blocking;
+    }
+
     /* Unbuffered operations */
     
     public String sysread(int length) throws EOFException, BadDescriptorException, IOException {
@@ -113,7 +129,7 @@
                 eof = true;
                 break;
             }
-        	if (bytesRead == 0) {
+        	if (bytesRead == 0 && !blocking) {
         	    // only should happen for nonblocking IO...break and allow the next call to try again
         	    break;
         	}
@@ -271,6 +287,8 @@
             }
             ret.append(consumeInBuffer(remaining));
             remaining -= i;
+	    if(!blocking)
+		break;
         }
         if (eof && ret.length() == 0) {
             throw new EOFException();
@@ -340,6 +358,8 @@
             if (fillInBuffer() < 0) {
                 eof = true;
 	    }
+	    if(!blocking)
+		break;
         }
         if (eof && !inBuffer.hasRemaining() && ret.length() == 0) {
             throw new EOFException();
