Ok, third time lucky, I hope.The last patch for Signal worked pretty well in some use scenarios. There was one fatal flaw, though... It doesn't do ANYTHING if you want to execute the block more than once. Ouch.
So solve this, I've devised a solution where a new RubyThread is created each time the signal happens, but this demands that I have more control over Thread-creation. Because of this there are two new classes in the org.jruby.internal.runtime-package (RubyBlockNativeThread and NativeBlockThread) which makes it possible for me to set which block, proc and frame to use, after the NativeThread has been created. I added a new factory method to RubyThread to create a new thread with this implementation instead, too. There is probably some better refactoring of all this functionality, but right now this works really well.
/O
RubyBlockNativeThread.java
Description: Binary data
NativeBlockThread.java
Description: Binary data
Index: src/org/jruby/RubyKernel.java =================================================================== RCS file: /cvsroot/jruby/jruby/src/org/jruby/RubyKernel.java,v retrieving revision 1.53 diff -u -r1.53 RubyKernel.java --- src/org/jruby/RubyKernel.java 24 May 2006 01:34:03 -0000 1.53 +++ src/org/jruby/RubyKernel.java 17 Jun 2006 14:26:17 -0000 @@ -50,6 +50,8 @@ import org.jruby.ast.util.ArgsUtil; import org.jruby.exceptions.JumpException; import org.jruby.exceptions.RaiseException; +import org.jruby.runtime.Block; +import org.jruby.runtime.Frame; import org.jruby.runtime.CallType; import org.jruby.runtime.CallbackFactory; import org.jruby.runtime.Visibility; @@ -657,8 +659,53 @@ throw je; } + private static class JRubyProcObject implements Runnable { + private final RubyProc proc; + private final Block block; + private final Frame frame; + public JRubyProcObject(final RubyProc proc, final Block block, final Frame frame) { + this.proc = proc; + this.block = block; + this.frame = frame; + } + public void run() { + proc.getRuntime().getCurrentContext().pushBlock(this.block); + RubyThread.startThread(proc.getRuntime().getClass("Thread"),proc,block,frame,new IRubyObject[0]); + // proc.startThread(); + } + } + public static IRubyObject trap(IRubyObject recv, IRubyObject[] args) { - // FIXME: We can probably fake some basic signals, but obviously can't do everything. For now, stub. + String sigName = null; + long sigNum = -1; + if(args[0] instanceof RubyNumeric) { + sigNum = RubyNumeric.num2long(args[0]); + } else { + sigName = args[0].toString(); + if(sigName.startsWith("SIG")) { + sigName = sigName.substring("SIG".length()); + } + } + RubyProc proc = null; + Block blk = null; + Frame fre = null; + if(args.length>1) { + if(args[1] instanceof RubyString) { + // Handle cases of IGNORE, SIG_IGN, DEFAULT and SIG_DFL + } + } else { + if (recv.getRuntime().getCurrentContext().isBlockGiven()) { + proc = recv.getRuntime().newProc(); + fre = recv.getRuntime().getCurrentContext().getCurrentFrame(); + blk = (Block)recv.getRuntime().getCurrentContext().getCurrentBlock(); + // proc = RubyThread.notStartThread(recv.getRuntime().getClass("Thread"),new IRubyObject[0]); + } + } + if(null != sigName) { + recv.getRuntime().getSignalHandler().handleSignal(sigName,new JRubyProcObject(proc,blk,fre)); + } else { + recv.getRuntime().getSignalHandler().handleSignal(sigNum,new JRubyProcObject(proc,blk,fre)); + } return recv.getRuntime().getNil(); } Index: src/org/jruby/RubyThread.java =================================================================== RCS file: /cvsroot/jruby/jruby/src/org/jruby/RubyThread.java,v retrieving revision 1.23 diff -u -r1.23 RubyThread.java --- src/org/jruby/RubyThread.java 16 Jun 2006 18:13:26 -0000 1.23 +++ src/org/jruby/RubyThread.java 17 Jun 2006 14:31:23 -0000 @@ -72,6 +72,10 @@ private volatile boolean killed = false; public Object killLock = new Object(); private RubyThread joinedByCriticalThread; + + public int hashCode() { + return threadImpl.hashCode(); + } public static RubyClass createThreadClass(IRuby runtime) { RubyClass threadClass = runtime.defineClass("Thread", runtime.getObject()); @@ -219,6 +223,48 @@ return rubyThread; } + + static RubyThread startThread(final IRubyObject recv, final RubyProc proc, final org.jruby.runtime.Block block, final org.jruby.runtime.Frame frame, final IRubyObject[] args) { + final IRuby runtime = recv.getRuntime(); + /* + if (!runtime.getCurrentContext().isBlockGiven()) { + throw runtime.newThreadError("must be called with a block"); + }*/ + final RubyThread rubyThread = new RubyThread(runtime, (RubyClass) recv); + rubyThread.callInit(args); + + rubyThread.threadImpl = new org.jruby.internal.runtime.NativeBlockThread(rubyThread, args); + rubyThread.threadImpl.setProcInfo(proc,block,frame); + rubyThread.threadImpl.start(); + + // make sure the thread has started before continuing, so it will appear "runnable" to the rest of Ruby + rubyThread.ensureStarted(); + + return rubyThread; + } + + static RubyThread notStartThread(final IRubyObject recv, final IRubyObject[] args) { + final IRuby runtime = recv.getRuntime(); + if (!runtime.getCurrentContext().isBlockGiven()) { + throw runtime.newThreadError("must be called with a block"); + } + final RubyThread rubyThread = new RubyThread(runtime, (RubyClass) recv); + rubyThread.callInit(args); + + rubyThread.threadImpl = new NativeThread(rubyThread, args); + // rubyThread.threadImpl.start(); + + // make sure the thread has started before continuing, so it will appear "runnable" to the rest of Ruby + // rubyThread.ensureStarted(); + + return rubyThread; + } + + + void startThread() { + threadImpl.start(); + ensureStarted(); + } public void cleanTerminate() { try { Index: src/org/jruby/internal/runtime/NativeThread.java =================================================================== RCS file: /cvsroot/jruby/jruby/src/org/jruby/internal/runtime/NativeThread.java,v retrieving revision 1.3 diff -u -r1.3 NativeThread.java --- src/org/jruby/internal/runtime/NativeThread.java 31 Dec 2004 20:55:44 -0000 1.3 +++ src/org/jruby/internal/runtime/NativeThread.java 17 Jun 2006 14:34:03 -0000 @@ -28,15 +28,21 @@ package org.jruby.internal.runtime; import org.jruby.RubyThread; +import org.jruby.RubyProc; +import org.jruby.runtime.Block; +import org.jruby.runtime.Frame; + import org.jruby.runtime.builtin.IRubyObject; /** * @author cnutter */ public class NativeThread { - private Thread nativeThread; + protected Thread nativeThread; public RubyThread rubyThread; - + + protected NativeThread() { + } public NativeThread(RubyThread rubyThread, IRubyObject[] args) { this.rubyThread = rubyThread; @@ -79,4 +85,8 @@ public boolean isInterrupted() { return nativeThread.isInterrupted(); } + + public void setProcInfo(final RubyProc proc, final Block currentBlock, final Frame currentFrame) { + ((RubyNativeThread)nativeThread).setProcInfo(proc,currentBlock,currentFrame); + } } Index: src/org/jruby/internal/runtime/RubyNativeThread.java =================================================================== RCS file: /cvsroot/jruby/jruby/src/org/jruby/internal/runtime/RubyNativeThread.java,v retrieving revision 1.15 diff -u -r1.15 RubyNativeThread.java --- src/org/jruby/internal/runtime/RubyNativeThread.java 16 Jun 2006 18:13:26 -0000 1.15 +++ src/org/jruby/internal/runtime/RubyNativeThread.java 17 Jun 2006 14:12:52 -0000 @@ -40,7 +40,7 @@ import org.jruby.runtime.builtin.IRubyObject; public class RubyNativeThread extends Thread { - private IRuby runtime; + private IRuby runtime; private Frame currentFrame; private Block currentBlock; private RubyProc proc; @@ -61,6 +61,12 @@ public RubyThread getRubyThread() { return rubyThread; } + + public void setProcInfo(final RubyProc proc, final Block currentBlock, final Frame currentFrame) { + this.proc = proc; + this.currentBlock = currentBlock; + this.currentFrame = currentFrame; + } public void run() { runtime.getThreadService().registerNewThread(rubyThread);
_______________________________________________ Jruby-devel mailing list Jruby-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jruby-devel