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

Attachment: RubyBlockNativeThread.java
Description: Binary data

Attachment: 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

Reply via email to