Skip to content

Commit

Permalink
Implement Thread.report_on_exception and Thread#report_on_exception
Browse files Browse the repository at this point in the history
* Fixes oracle#1476.
  • Loading branch information
eregon committed Nov 23, 2018
1 parent 08f062b commit d08c70c
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 10 deletions.
5 changes: 0 additions & 5 deletions spec/tags/core/thread/report_on_exception_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
slow:Thread.report_on_exception defaults to false
fails:Thread.report_on_exception= changes the default value for new threads
fails:Thread#report_on_exception returns whether the Thread will print a backtrace if it exits with an exception
fails:Thread#report_on_exception= when set to true prints a backtrace on $stderr if it terminates with an exception
fails:Thread#report_on_exception= when used in conjunction with Thread#abort_on_exception first reports then send the exception back to the main Thread
fails:Thread.report_on_exception defaults to false
7 changes: 6 additions & 1 deletion src/main/java/org/truffleruby/core/CoreLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ public class CoreLibrary {
private final DynamicObject truffleInteropForeignClass;
private final DynamicObject truffleKernelOperationsModule;
private final DynamicObject truffleRegexpOperationsModule;
private final DynamicObject truffleThreadOperationsModule;
private final DynamicObject bigDecimalClass;
private final DynamicObject encodingCompatibilityErrorClass;
private final DynamicObject encodingUndefinedConversionErrorClass;
Expand Down Expand Up @@ -537,7 +538,7 @@ public CoreLibrary(RubyContext context) {
defineModule(truffleModule, "POSIX");
defineModule(truffleModule, "Readline");
defineModule(truffleModule, "ReadlineHistory");
defineModule(truffleModule, "ThreadOperations");
truffleThreadOperationsModule = defineModule(truffleModule, "ThreadOperations");
defineModule(truffleModule, "WeakRefOperations");
handleClass = defineClass(truffleModule, objectClass, "Handle");
handleFactory = Layouts.HANDLE.createHandleShape(handleClass, handleClass);
Expand Down Expand Up @@ -1385,6 +1386,10 @@ public DynamicObject getTruffleKernelOperationsModule() {
return truffleKernelOperationsModule;
}

public DynamicObject getTruffleThreadOperationsModule() {
return truffleThreadOperationsModule;
}

public DynamicObject getTruffleRegexpOperationsModule() {
return truffleRegexpOperationsModule;
}
Expand Down
28 changes: 25 additions & 3 deletions src/main/java/org/truffleruby/core/thread/ThreadManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleException;
import com.oracle.truffle.api.TruffleStackTraceElement;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
Expand Down Expand Up @@ -275,11 +277,31 @@ private static void setThreadValue(RubyContext context, DynamicObject thread, Ob
private static void setException(RubyContext context, DynamicObject thread, DynamicObject exception, Node currentNode) {
// A Thread is always shared (Thread.list)
SharedObjects.propagate(context, thread, exception);

// We materialize the backtrace eagerly here, as the exception escapes the thread and needs
// to capture the backtrace from this thread.
final TruffleException truffleException = Layouts.EXCEPTION.getBacktrace(exception).getTruffleException();
if (truffleException != null) {
TruffleStackTraceElement.fillIn((Throwable) truffleException);
}

final DynamicObject mainThread = context.getThreadManager().getRootThread();
final boolean isSystemExit = Layouts.BASIC_OBJECT.getLogicalClass(exception) == context.getCoreLibrary().getSystemExitClass();
if (thread != mainThread && (isSystemExit || Layouts.THREAD.getAbortOnException(thread))) {
ThreadNodes.ThreadRaisePrimitiveNode.raiseInThread(context, mainThread, exception, currentNode);

if (thread != mainThread) {
final boolean isSystemExit = Layouts.BASIC_OBJECT.getLogicalClass(exception) == context.getCoreLibrary().getSystemExitClass();

if (!isSystemExit && (boolean) ReadObjectFieldNode.read(thread, "@report_on_exception", false)) {
context.send(context.getCoreLibrary().getTruffleThreadOperationsModule(),
"report_exception",
thread,
exception);
}

if (isSystemExit || Layouts.THREAD.getAbortOnException(thread)) {
ThreadNodes.ThreadRaisePrimitiveNode.raiseInThread(context, mainThread, exception, currentNode);
}
}

Layouts.THREAD.setException(thread, exception);
}

Expand Down
12 changes: 11 additions & 1 deletion src/main/ruby/core/thread.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,10 @@ def self.handle_interrupt(config, &block)
end

@abort_on_exception = false
@report_on_exception = false

class << self
attr_accessor :abort_on_exception
attr_accessor :abort_on_exception, :report_on_exception

def new(*args, &block)
thread = Truffle.invoke_primitive(:thread_allocate, self)
Expand All @@ -227,6 +228,7 @@ def start(*args, &block)
# Instance methods

attr_reader :recursive_objects, :randomizer
attr_accessor :report_on_exception

def initialize(*args, &block)
Kernel.raise ThreadError, 'must be called with a block' unless block
Expand All @@ -241,6 +243,7 @@ def initialize(*args, &block)
@thread_local_variables = {}
@recursive_objects = {}
@randomizer = Truffle::Randomizer.new
@report_on_exception = Thread.report_on_exception
end

def freeze
Expand Down Expand Up @@ -473,6 +476,13 @@ def marshal_dump
end
end

module Truffle::ThreadOperations
def self.report_exception(thread, exception)
message = "#{thread.inspect} terminated with exception:\n#{exception.full_message}"
$stderr.write message
end
end

Truffle::KernelOperations.define_hooked_variable(
:$SAFE,
-> { Thread.current.safe_level },
Expand Down

0 comments on commit d08c70c

Please sign in to comment.