I'm on vacation so I haven't had a chance to look at this patch. Beware that there are issues with nonblocking io and select(). While a SocketChannel is being select()ed, it *must* be in nonblocking mode. I was thinking about implementing fcntl for nonblocking io, but the problem is what if while one thread is select()ing on a socket, another sets the socket blocking? Either we have to block the fcntl until the select completes or we have to do some weird threading delay-set magic.
Granted there might not be one single instance of something like this happening, but then again there might. Evan Ola Bini wrote: > Hi > > I've managed to fix a working fcntl implementation that sets > nonblocking io when asked to. Patch is attached. > This makes a simple daytime server work flawlessly. > > When I scale this up and try something like this: > > require 'webrick' > include WEBrick > > s = HTTPServer.new( > :Port => 2000, > :DocumentRoot => %q(d:\web\htdocs) > ) > > trap("INT"){ s.shutdown } > s.start > > ... we get into trouble again. Guess what it is? > java.lang.RuntimeException: java.lang.InterruptedException > at org.jruby.RubyThread.criticalizeOrDieIfKilled(RubyThread.java:293) > at org.jruby.RubyThread.pollThreadEvents(RubyThread.java:278) > at > org.jruby.runtime.ThreadContext.pollThreadEvents(ThreadContext.java:471) > at > org.jruby.evaluator.EvaluationState.executeNext(EvaluationState.java:257) > at > org.jruby.evaluator.EvaluationState.begin(EvaluationState.java:297) > at > org.jruby.internal.runtime.methods.EvaluateCallable.internalCall(EvaluateCallable.java:67) > > at > org.jruby.internal.runtime.methods.AbstractCallable.call(AbstractCallable.java:64) > > at org.jruby.runtime.ThreadContext.yield(ThreadContext.java:347) > at org.jruby.runtime.Block.call(Block.java:114) > at org.jruby.RubyProc.call(RubyProc.java:118) > at org.jruby.RubyProc.call(RubyProc.java:104) > at > org.jruby.internal.runtime.RubyNativeThread.run(RubyNativeThread.java:75) > Caused by: java.lang.InterruptedException > at java.lang.Object.wait(Native Method) > at java.lang.Object.wait(Object.java:429) > at org.jruby.RubyThread.waitIfCriticalized(RubyThread.java:260) > at org.jruby.RubyThread.criticalizeOrDieIfKilled(RubyThread.java:290) > ... 11 more > > > Our old friend. The server actually does work, but sillyness slow, > even on a localhost. Maybe some uses of timeout here too? Doesn't seem > to be in the relevant parts, actually, but there is obviously > something strange going on... > > Anyway, fcntl takes us one step further. > > Regards > Ola Bini > ------------------------------------------------------------------------ > > Index: src/org/jruby/runtime/builtin/meta/IOMetaClass.java > =================================================================== > RCS file: > /cvsroot/jruby/jruby/src/org/jruby/runtime/builtin/meta/IOMetaClass.java,v > retrieving revision 1.18 > diff -u -r1.18 IOMetaClass.java > --- src/org/jruby/runtime/builtin/meta/IOMetaClass.java 26 May 2006 > 01:47:52 -0000 1.18 > +++ src/org/jruby/runtime/builtin/meta/IOMetaClass.java 13 Jun 2006 > 11:34:47 -0000 > @@ -95,6 +95,7 @@ > defineMethod("each_line", Arity.optional()); > defineMethod("eof", Arity.noArguments()); > defineAlias("eof?", "eof"); > + defineMethod("fcntl", Arity.twoArguments()); > defineMethod("fileno", Arity.noArguments()); > defineMethod("flush", Arity.noArguments()); > defineMethod("fsync", Arity.noArguments()); > Index: src/org/jruby/RubyIO.java > =================================================================== > RCS file: /cvsroot/jruby/jruby/src/org/jruby/RubyIO.java,v > retrieving revision 1.52 > diff -u -r1.52 RubyIO.java > --- src/org/jruby/RubyIO.java 24 May 2006 01:34:03 -0000 1.52 > +++ src/org/jruby/RubyIO.java 13 Jun 2006 11:47:55 -0000 > @@ -40,6 +40,7 @@ > 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; > @@ -806,6 +807,31 @@ > return result; > } > > + public IRubyObject fcntl(final IRubyObject cmd, final IRubyObject arg) > throws IOException { > + if(arg instanceof RubyNumeric) { > + final long realCmd = ((RubyNumeric)cmd).getLongValue(); > + final long realArg = ((RubyNumeric)arg).getLongValue(); > + if(realCmd == 1L) { > + // cmd is F_SETFL > + boolean block = false; > + if((realArg & IOModes.NONBLOCK) == IOModes.NONBLOCK) { > + block = true; > + } > + final Channel chn = getChannel(); > + if(chn != null && chn instanceof SelectableChannel) { > + try { > + ((SelectableChannel)chn).configureBlocking(block); > + } catch(final IOException e) { > + throw getRuntime().newIOError(e.getMessage()); > + } > + } > + } > + return RubyFixnum.zero(getRuntime()); > + } else { > + return getRuntime().getNil(); > + } > + } > + > public IRubyObject puts(IRubyObject[] args) { > checkArgumentCount(args, 0, -1); > > Index: src/builtin/fcntl.rb > =================================================================== > RCS file: /cvsroot/jruby/jruby/src/builtin/fcntl.rb,v > retrieving revision 1.1 > diff -u -r1.1 fcntl.rb > --- src/builtin/fcntl.rb 23 Nov 2005 10:55:36 -0000 1.1 > +++ src/builtin/fcntl.rb 13 Jun 2006 11:42:58 -0000 > @@ -0,0 +1,12 @@ > +class Fcntl > + F_SETFL = 1 > + O_RDWR = File::RDWR > + O_TRUNC = File::TRUNC > + O_RDONLY = File::RDONLY > + O_EXCL = File::EXCL > + O_ACCMODE = File::NOCTTY > + O_NONBLOCK = File::NONBLOCK > + O_CREAT = File::CREAT > + O_WRONLY = File::WRONLY > + O_APPEND = File::APPEND > +end > > > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------ > > _______________________________________________ > Jruby-devel mailing list > Jruby-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/jruby-devel > _______________________________________________ Jruby-devel mailing list Jruby-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jruby-devel