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: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7848d871d35c
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2928b6dd49ac
Choose a head ref
  • 2 commits
  • 10 files changed
  • 1 contributor

Commits on Jun 12, 2015

  1. Copy the full SHA
    e32baa3 View commit details
  2. Fixed broken SignalException spec.

    This spec has two main problems:
    
    1. It contains a race between executing Process.kill, which will signal the
    process and processing that signal will raise a SignalException, and rescuing
    a SignalException. There's nothing that guarantees that the signal is even
    delivered by the OS before the thread of execution moves on.
    2. It assumes that the signal will be processed in this thread, thereby resulting
    in the exception being raised on this thread and it being possible to rescue the
    exception. This assumption would fail if this code were running in a thread other
    than the one processing signals.
    
    Signals are delivered and handled asynchronously. The signal trapping mechanism
    is the proper way to handle signals. The thread that the signal is processed on
    is undefined in Ruby. Rubinius now processes signals on a dedicated thread that
    is invisible to the other threads (ie, no user code will ever run on that thread
    other than signal handler blocks).
    brixen committed Jun 12, 2015
    Copy the full SHA
    2928b6d View commit details
Showing with 218 additions and 199 deletions.
  1. +35 −28 kernel/loader.rb
  2. +1 −1 spec/ruby/core/exception/signal_exception_spec.rb
  3. +5 −3 vm/builtin/system.cpp
  4. +15 −20 vm/environment.cpp
  5. +8 −0 vm/environment.hpp
  6. +11 −1 vm/shared_state.cpp
  7. +7 −9 vm/shared_state.hpp
  8. +119 −113 vm/signal.cpp
  9. +17 −18 vm/signal.hpp
  10. +0 −6 vm/state.cpp
63 changes: 35 additions & 28 deletions kernel/loader.rb
Original file line number Diff line number Diff line change
@@ -718,6 +718,11 @@ def flush_stdio
STDERR.flush unless STDERR.closed?
end

def exit_with_exception(e)
@exit_code = 1
Rubinius::Logger.log_exception "An exception occurred #{@stage}", e
end

# Cleanup and at_exit processing.
def epilogue
@stage = "running at_exit handlers"
@@ -737,8 +742,7 @@ def epilogue
flush_stdio

rescue Object => e
Rubinius::Logger.log_exception "An exception occurred #{@stage}", e
@exit_code = 1
exit_with_exception e
end

# Exit.
@@ -790,6 +794,34 @@ def done
Process.exit! @exit_code
end

def handle_exception(e)
case e
when SystemExit
@exit_code = e.status
when SyntaxError
@exit_code = 1

show_syntax_error(e)

STDERR.puts "\nBacktrace:"
STDERR.puts
STDERR.puts e.awesome_backtrace.show
when Interrupt
exit_with_exception e
when SignalException
Signal.trap(e.signo, "SIG_DFL")
Process.kill e.signo, Process.pid
when nil
# what?
else
exit_with_exception e
end
rescue Object => e
exit_with_exception e
ensure
epilogue
end

# Orchestrate everything.
def main
preamble
@@ -810,33 +842,8 @@ def main
script
repl

rescue SystemExit => e
@exit_code = e.status

epilogue
rescue SyntaxError => e
@exit_code = 1

show_syntax_error(e)

STDERR.puts "\nBacktrace:"
STDERR.puts
STDERR.puts e.awesome_backtrace.show
epilogue
rescue Interrupt => e
@exit_code = 1

Rubinius::Logger.log_exception "An exception occurred #{@stage}:", e
epilogue
rescue SignalException => e
Signal.trap(e.signo, "SIG_DFL")
Process.kill e.signo, Process.pid
epilogue
rescue Object => e
@exit_code = 1

Rubinius::Logger.log_exception "An exception occurred #{@stage}:", e
epilogue
handle_exception e
else
# We do this, run epilogue both in the rescue blocks and also here,
# so that at_exit{} hooks can read $!.
2 changes: 1 addition & 1 deletion spec/ruby/core/exception/signal_exception_spec.rb
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@
describe "rescueing SignalException" do
it "raises a SignalException when sent a signal" do
begin
Process.kill :TERM, Process.pid
raise SignalException.new(Signal.list["TERM"])
rescue SignalException => e
e.signo.should == Signal.list["TERM"]
end
8 changes: 5 additions & 3 deletions vm/builtin/system.cpp
Original file line number Diff line number Diff line change
@@ -1019,13 +1019,15 @@ namespace rubinius {
}

Object* System::vm_watch_signal(STATE, Fixnum* sig, Object* ignored) {
SignalThread* st = state->shared().signal_handler();
SignalThread* st = state->shared().signals();

if(st) {
native_int i = sig->to_native();
if(i < 0) {
st->add_signal(state, -i, SignalThread::eDefault);
st->add_signal_handler(state, -i, SignalThread::eDefault);
} else if(i > 0) {
st->add_signal(state, i, CBOOL(ignored) ? SignalThread::eIgnore : SignalThread::eCustom);
st->add_signal_handler(state, i,
CBOOL(ignored) ? SignalThread::eIgnore : SignalThread::eCustom);
}

return cTrue;
35 changes: 15 additions & 20 deletions vm/environment.cpp
Original file line number Diff line number Diff line change
@@ -79,6 +79,7 @@ namespace rubinius {
, signature_(0)
, signal_thread_(NULL)
, finalizer_thread_(NULL)
, loader_(NULL)
{
#ifdef ENABLE_LLVM
#if RBX_LLVM_API_VER < 305
@@ -107,6 +108,8 @@ namespace rubinius {
root_vm->metrics().init(metrics::eRubyMetrics);
state = new State(root_vm);

loader_ = new TypedRoot<Object*>(state);

NativeMethod::init_thread(state);

start_logging(state);
@@ -198,12 +201,6 @@ namespace rubinius {
#endif
}

void Environment::start_signals(STATE) {
state->vm()->set_run_signals(true);
signal_thread_ = new SignalThread(state, config);
signal_thread_->start(state);
}

void Environment::stop_signals(STATE) {
signal_thread_->stop(state);
}
@@ -597,7 +594,7 @@ namespace rubinius {
}

stop_jit(state);
stop_signals(state);
state->shared().signals()->stop(state);

root_vm->set_call_frame(0);

@@ -846,7 +843,7 @@ namespace rubinius {

load_argv(argc_, argv_);

start_signals(state);
state->shared().start_signals(state);
state->vm()->initialize_config();

load_tool();
@@ -870,23 +867,21 @@ namespace rubinius {
state->shared().start_console(state);
state->shared().start_metrics(state);

Object* loader = G(rubinius)->get_const(state, state->symbol("Loader"));
if(loader->nil_p()) {
rubinius::bug("Unable to find loader");
Object* klass = G(rubinius)->get_const(state, state->symbol("Loader"));
if(klass->nil_p()) {
rubinius::bug("unable to find class Rubinius::Loader");
}

OnStack<1> os(state, loader);
Object* instance = klass->send(state, 0, state->symbol("new"));
if(instance) {
loader_->set(instance);
} else {
rubinius::bug("unable to instantiate Rubinius::Loader");
}

// Enable the JIT after the core library has loaded
G(jit)->enable(state);

Object* inst = loader->send(state, 0, state->symbol("new"));
if(inst) {
OnStack<1> os2(state, inst);

inst->send(state, 0, state->symbol("main"));
} else {
rubinius::bug("Unable to instantiate loader");
}
loader_->get()->send(state, 0, state->symbol("main"));
}
}
8 changes: 8 additions & 0 deletions vm/environment.hpp
Original file line number Diff line number Diff line change
@@ -8,6 +8,8 @@
#include "config_parser.hpp"
#include "configuration.hpp"

#include "gc/root.hpp"

namespace rubinius {

class ConfigParser;
@@ -61,6 +63,8 @@ namespace rubinius {

utilities::thread::Mutex halt_lock_;

TypedRoot<Object*>* loader_;

public:
SharedState* shared;
VM* root_vm;
@@ -81,6 +85,10 @@ namespace rubinius {
return argv_;
}

Object* loader() {
return loader_->get();
}

void set_root_vm(VM* vm) {
root_vm = vm;
state->set_vm(vm);
12 changes: 11 additions & 1 deletion vm/shared_state.cpp
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@

#include "console.hpp"
#include "metrics.hpp"
#include "signal.hpp"
#include "world_state.hpp"
#include "builtin/randomizer.hpp"
#include "builtin/array.hpp"
@@ -31,7 +32,7 @@ namespace rubinius {

SharedState::SharedState(Environment* env, Configuration& config, ConfigParser& cp)
: internal_threads_(0)
, signal_thread_(0)
, signals_(0)
, finalizer_thread_(0)
, console_(0)
, metrics_(0)
@@ -142,6 +143,15 @@ namespace rubinius {
return threads;
}

SignalThread* SharedState::start_signals(STATE) {
SYNC(state);

signals_ = new SignalThread(state);
signals_->start(state);

return signals_;
}

console::Console* SharedState::start_console(STATE) {
SYNC(state);

16 changes: 7 additions & 9 deletions vm/shared_state.hpp
Original file line number Diff line number Diff line change
@@ -87,7 +87,7 @@ namespace rubinius {
class SharedState : public Lockable {
private:
InternalThreads* internal_threads_;
SignalThread* signal_thread_;
SignalThread* signals_;
FinalizerThread* finalizer_thread_;
console::Console* console_;
metrics::Metrics* metrics_;
@@ -160,14 +160,6 @@ namespace rubinius {
return internal_threads_;
}

SignalThread* signal_handler() const {
return signal_thread_;
}

void set_signal_handler(SignalThread* thr) {
signal_thread_ = thr;
}

FinalizerThread* finalizer_handler() const {
return finalizer_thread_;
}
@@ -215,6 +207,12 @@ namespace rubinius {
return primitive_hits_[primitive];
}

SignalThread* signals() const {
return signals_;
}

SignalThread* start_signals(STATE);

console::Console* console() const {
return console_;
}
Loading