Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: fd83bdafbd7c
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 03026bf5d330
Choose a head ref
  • 2 commits
  • 3 files changed
  • 1 contributor

Commits on Apr 11, 2018

  1. Copy the full SHA
    5ce4034 View commit details
  2. Copy the full SHA
    03026bf View commit details
Showing with 66 additions and 34 deletions.
  1. +12 −0 core/src/main/java/org/jruby/Ruby.java
  2. +30 −34 core/src/main/java/org/jruby/RubyThread.java
  3. +24 −0 spec/java_integration/exceptions/thread_spec.rb
12 changes: 12 additions & 0 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -2872,6 +2872,18 @@ public void printError(RubyException excp) {
}
}

public void printError(Throwable t) {
if (t instanceof RaiseException) {
printError(((RaiseException) t).getException());
}
PrintStream errorStream = getErrorStream();
try {
t.printStackTrace(errorStream);
} catch (Exception e) {
t.printStackTrace(System.err);
}
}

public void loadFile(String scriptName, InputStream in, boolean wrap) {
IRubyObject self = wrap ? getTopSelf().rbClone() : getTopSelf();
ThreadContext context = getCurrentContext();
64 changes: 30 additions & 34 deletions core/src/main/java/org/jruby/RubyThread.java
Original file line number Diff line number Diff line change
@@ -133,7 +133,7 @@ public class RubyThread extends RubyObject implements ExecutionContext {
* it here to continue propagating it while handling thread shutdown
* logic and abort_on_exception.
*/
private volatile RaiseException exitingException;
private volatile Throwable exitingException;

/** The ThreadGroup to which this thread belongs */
private volatile RubyThreadGroup threadGroup;
@@ -1072,10 +1072,14 @@ public IRubyObject join(ThreadContext context, IRubyObject[] args) {
}

if (exitingException != null) {
// Set $! in the current thread before exiting
runtime.getGlobalVariables().set("$!", (IRubyObject)exitingException.getException());
throw exitingException;

if (exitingException instanceof RaiseException) {
RaiseException raiseException = (RaiseException) exitingException;
// Set $! in the current thread before exiting
runtime.getGlobalVariables().set("$!", (IRubyObject) raiseException.getException());
} else {
runtime.getGlobalVariables().set("$!", JavaUtil.convertJavaToUsableRubyObject(runtime, exitingException));
}
Helpers.throwException(exitingException);
}

// check events before leaving
@@ -1626,44 +1630,36 @@ private boolean isCurrent() {
}

public void exceptionRaised(RaiseException exception) {
assert isCurrent();

RubyException rubyException = exception.getException();
Ruby runtime = rubyException.getRuntime();
if (runtime.getSystemExit().isInstance(rubyException)) {
runtime.getThreadService().getMainThread().raise(rubyException);
}
else if (abortOnException(runtime)) {
runtime.getThreadService().getMainThread().raise(rubyException);
return;
}
else if (runtime.isDebug()) {
runtime.printError(exception.getException());
}
exitingException = exception;
exceptionRaised((Throwable) exception);
}

/**
* For handling all non-Ruby exceptions bubbling out of threads
* @param exception
* For handling all exceptions bubbling out of threads
* @param throwable
*/
@SuppressWarnings("deprecation")
public void exceptionRaised(Throwable exception) {
if (exception instanceof RaiseException) {
exceptionRaised((RaiseException)exception);
return;
}
public void exceptionRaised(Throwable throwable) {
Ruby runtime = getRuntime();

assert isCurrent();

Ruby runtime = getRuntime();
if (abortOnException(runtime) && exception instanceof Error) {
// re-propagate on main thread
runtime.getThreadService().getMainThread().raise(JavaUtil.convertJavaToUsableRubyObject(runtime, exception));
IRubyObject rubyException;

if (throwable instanceof RaiseException) {
RaiseException exception = (RaiseException) throwable;
rubyException = exception.getException();
} else {
// just rethrow on this thread, let system handlers report it
Helpers.throwException(exception);
rubyException = JavaUtil.convertJavaToUsableRubyObject(runtime, throwable);
}

if (runtime.getSystemExit().isInstance(rubyException)) {
runtime.getThreadService().getMainThread().raise(rubyException);
} else if (abortOnException(runtime)) {
runtime.getThreadService().getMainThread().raise(rubyException);
} else if (runtime.isDebug()) {
runtime.printError(throwable);
}

exitingException = throwable;
}

private boolean abortOnException(Ruby runtime) {
24 changes: 24 additions & 0 deletions spec/java_integration/exceptions/thread_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require File.dirname(__FILE__) + "/../spec_helper"

describe "A Java exception bubbling out of a Ruby Thread" do
it "propagates out of Thread#join" do
t = Thread.new { raise java.lang.NullPointerException.new }
begin
t.join
fail "should not reach here"
rescue => e
expect(e.class).to equal(java.lang.NullPointerException)
end
end

it "propagates out of Thread#value" do
t = Thread.new { raise java.lang.NullPointerException.new }
begin
Thread.pass while t.status
t.value
fail "should not reach here"
rescue => e
expect(e.class).to equal(java.lang.NullPointerException)
end
end
end