Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin' into 1.8.7
Browse files Browse the repository at this point in the history
Conflicts:
	Gemfile.lock
	gems_list.txt
	kernel/common/array.rb
	kernel/common/enumerable.rb
	kernel/common/enumerator.rb
	kernel/common/struct.rb
	spec/ruby/core/enumerable/each_cons_spec.rb
	spec/ruby/core/enumerator/lazy/take_spec.rb
	spec/ruby/core/struct/each_pair_spec.rb
	vm/include/capi/ruby/ruby.h
	vm/shared_state.hpp
brixen committed Jun 12, 2015
2 parents c20de9e + 57cc497 commit a97b41b
Showing 29 changed files with 342 additions and 220 deletions.
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -8,15 +8,15 @@ before_install:
- echo $LANG
- echo $LC_ALL
- if [ $TRAVIS_OS_NAME == linux ]; then sudo apt-get update && sudo apt-get install -y llvm-3.4 llvm-3.4-dev; fi
- if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install llvm && brew link --force llvm; fi
- if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install llvm35 && brew link --force llvm35; fi
- rvm use $RVM --install --binary --fuzzy
- gem update --system
- gem --version

before_script:
- travis_retry bundle
- if [ $TRAVIS_OS_NAME == linux ]; then travis_retry ./configure --llvm-config llvm-config-3.4; fi
- if [ $TRAVIS_OS_NAME == osx ]; then travis_retry ./configure --llvm-config /usr/local/opt/llvm/bin/llvm-config; fi
- if [ $TRAVIS_OS_NAME == osx ]; then travis_retry ./configure; fi

script: rake ci

@@ -49,6 +49,4 @@ env:

os:
- linux
# - osx

osx_image: xcode61
- osx
3 changes: 0 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -27,6 +27,3 @@ DEPENDENCIES
redcard (~> 1.0)
rubinius-bridge (~> 1.0)
rubinius-build_tools (~> 1.0)

BUNDLED WITH
1.10.3
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2007-2014, Evan Phoenix and contributors
Copyright (c) 2007-2015, Evan Phoenix and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
4 changes: 2 additions & 2 deletions configure
Original file line number Diff line number Diff line change
@@ -574,8 +574,8 @@ class Configure
if macports?
config = macports_llvm_config
else
out = Bundler.with_clean_env { `brew list llvm | grep '/llvm-config$'` }
config = out.chomp if $?.success?
out = Bundler.with_clean_env { `brew --prefix llvm35` }.chomp
config = "#{out}/bin/llvm-config-3.5" if $?.success?
end
end
end
10 changes: 5 additions & 5 deletions gems_list.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
bundler-1.10.3.gem
bundler-1.9.9.gem
ffi2-generators-0.1.1.gem
json-1.8.3.gem
json-1.8.2.gem
minitest-4.7.5.gem
racc-1.4.12.gem
rake-10.4.2.gem
rb-readline-0.5.3.gem
rb-readline-0.5.2.gem
rdoc-4.2.0.gem
rubinius-ast-1.3.0.gem
rubinius-build_tools-1.0.0.gem
@@ -18,7 +18,7 @@ rubinius-profiler-2.0.2.gem
rubinius-toolset-2.3.1.gem
rubysl-1.1.0.gem
rubysl-abbrev-1.0.1.gem
rubysl-base64-1.0.1.gem
rubysl-base64-1.0.0.gem
rubysl-benchmark-1.0.0.gem
rubysl-bigdecimal-1.0.0.gem
rubysl-cgi-1.0.0.gem
@@ -28,7 +28,7 @@ rubysl-csv-1.0.1.gem
rubysl-curses-1.0.0.gem
rubysl-date-1.0.1.gem
rubysl-delegate-1.0.0.gem
rubysl-digest-1.2.0.gem
rubysl-digest-1.0.1.gem
rubysl-drb-1.0.0.gem
rubysl-e2mmap-1.0.0.gem
rubysl-english-1.0.0.gem
2 changes: 2 additions & 0 deletions kernel/bootstrap/thunk.rb
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@ def self.new(value)
Rubinius.primitive :thunk_create
raise PrimitiveFailure, "Thunk.new primitive failed"
end

attr_accessor :value
end

class CallUnit
13 changes: 12 additions & 1 deletion kernel/common/array.rb
Original file line number Diff line number Diff line change
@@ -1599,7 +1599,18 @@ def zip(*others)
size.times do |i|
slot = out.at(i)
slot << @tuple.at(@start + i)
others.each { |ary| slot << ary.at(i) }
others.each do |other|
slot << case other
when Array
other.at i
else
begin
other.next
rescue StopIteration
nil
end
end
end
end

if block_given?
63 changes: 35 additions & 28 deletions kernel/loader.rb
Original file line number Diff line number Diff line change
@@ -704,6 +704,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"
@@ -723,8 +728,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.
@@ -776,6 +780,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
@@ -795,33 +827,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 library/rubygems.rb
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
require 'thread'

module Gem
VERSION = '2.4.6'
VERSION = '2.4.8'
end

# Must be first since it unloads the prelude from 1.9.2
8 changes: 7 additions & 1 deletion library/rubygems/remote_fetcher.rb
Original file line number Diff line number Diff line change
@@ -94,7 +94,13 @@ def api_endpoint(uri)
rescue Resolv::ResolvError
uri
else
URI.parse "#{uri.scheme}://#{res.target}#{uri.path}"
target = res.target.to_s.strip

if /\.#{Regexp.quote(host)}\z/ =~ target
return URI.parse "#{uri.scheme}://#{target}#{uri.path}"
end

uri
end
end

13 changes: 13 additions & 0 deletions spec/core/module/thunk_method_spec.rb
Original file line number Diff line number Diff line change
@@ -20,4 +20,17 @@
it "returns the coerced name" do
@class.thunk_method("a_reader", @value).should equal(:a_reader)
end

it "creates an executable that can be used to read the value" do
@class.thunk_method(:thunk, @value)
@class.instance_method(:thunk).executable.value.should equal(@value)
end

it "creates an executable that can be used to change the value" do
@class.thunk_method(:thunk, @value)
new_value = Object.new
@class.instance_method(:thunk).executable.value = new_value
@class.instance_method(:thunk).executable.value.should equal(new_value)
@class.new.thunk.should equal(new_value)
end
end
6 changes: 6 additions & 0 deletions spec/ruby/core/enumerator/size_spec.rb
Original file line number Diff line number Diff line change
@@ -19,4 +19,10 @@
enum.size.should == 301
end
end

it "returns the result from size.call if the size respond to call " do
obj = mock('call')
obj.should_receive(:call).and_return(42)
Enumerator.new(obj) {}.size.should == 42
end
end
2 changes: 1 addition & 1 deletion spec/ruby/core/exception/signal_exception_spec.rb
Original file line number Diff line number Diff line change
@@ -117,7 +117,7 @@

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
18 changes: 18 additions & 0 deletions spec/ruby/core/marshal/shared/load.rb
Original file line number Diff line number Diff line change
@@ -579,6 +579,24 @@
end
end

describe "for a Bignum" do
platform_is :wordsize => 64 do
context "that is Bignum on 32-bit platforms but Fixnum on 64-bit" do
it "dumps a Fixnum" do
val = Marshal.load("\004\bl+\ab:wU")
val.should == 1433877090
val.class.should == Fixnum
end

it "dumps an array containing multiple references to the Bignum as an array of Fixnum" do
arr = Marshal.load("\004\b[\al+\a\223BwU@\006")
arr.should == [1433879187, 1433879187]
arr.each { |v| v.class.should == Fixnum }
end
end
end
end

describe "for a Time" do
it "loads" do
Marshal.send(@method, Marshal.dump(Time.at(1))).should == Time.at(1)
20 changes: 20 additions & 0 deletions spec/ruby/optional/capi/ext/hash_spec.c
Original file line number Diff line number Diff line change
@@ -11,6 +11,18 @@ VALUE hash_spec_rb_hash(VALUE self, VALUE hash) {
}
#endif

#ifdef HAVE_RB_HASH_DUP
VALUE hash_spec_rb_hash_dup(VALUE self, VALUE hash) {
return rb_hash_dup(hash);
}
#endif

#ifdef HAVE_RB_HASH_FREEZE
VALUE hash_spec_rb_hash_freeze(VALUE self, VALUE hash) {
return rb_hash_freeze(hash);
}
#endif

#ifdef HAVE_RB_HASH_AREF
VALUE hash_spec_rb_hash_aref(VALUE self, VALUE hash, VALUE key) {
return rb_hash_aref(hash, key);
@@ -107,6 +119,14 @@ void Init_hash_spec() {
rb_define_method(cls, "rb_hash", hash_spec_rb_hash, 1);
#endif

#ifdef HAVE_RB_HASH_DUP
rb_define_method(cls, "rb_hash_dup", hash_spec_rb_hash_dup, 1);
#endif

#ifdef HAVE_RB_HASH_FREEZE
rb_define_method(cls, "rb_hash_freeze", hash_spec_rb_hash_freeze, 1);
#endif

#ifdef HAVE_RB_HASH_AREF
rb_define_method(cls, "rb_hash_aref", hash_spec_rb_hash_aref, 2);
rb_define_method(cls, "rb_hash_aref_nil", hash_spec_rb_hash_aref_nil, 2);
2 changes: 2 additions & 0 deletions spec/ruby/optional/capi/ext/rubyspec.h
Original file line number Diff line number Diff line change
@@ -303,6 +303,8 @@

/* Hash */
#define HAVE_RB_HASH 1
#define HAVE_RB_HASH_DUP 1
#define HAVE_RB_HASH_FREEZE 1
#define HAVE_RB_HASH_AREF 1
#define HAVE_RB_HASH_ASET 1
#define HAVE_RB_HASH_DELETE 1
15 changes: 15 additions & 0 deletions spec/ruby/optional/capi/hash_spec.rb
Original file line number Diff line number Diff line change
@@ -49,6 +49,21 @@
end
end

describe "rb_hash_dup" do
it "returns a copy of the hash" do
hsh = {}
dup = @s.rb_hash_dup(hsh)
dup.should == hsh
dup.should_not equal(hsh)
end
end

describe "rb_hash_freeze" do
it "freezes the hash" do
@s.rb_hash_freeze({}).frozen?.should be_true
end
end

describe "rb_hash_aref" do
it "returns the value associated with the key" do
hsh = {:chunky => 'bacon'}
8 changes: 5 additions & 3 deletions vm/builtin/system.cpp
Original file line number Diff line number Diff line change
@@ -923,13 +923,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;
2 changes: 1 addition & 1 deletion vm/capi/array.cpp
Original file line number Diff line number Diff line change
@@ -216,7 +216,7 @@ extern "C" {
}

/* @todo Check 64-bit? */
VALUE rb_ary_entry(VALUE self, int index) {
VALUE rb_ary_entry(VALUE self, long index) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();

Array* array = capi_get_array(env, self);
8 changes: 8 additions & 0 deletions vm/capi/hash.cpp
Original file line number Diff line number Diff line change
@@ -10,6 +10,14 @@ extern "C" {
return capi_fast_call(rb_cHash, rb_intern("new"), 0);
}

VALUE rb_hash_dup(VALUE self) {
return capi_fast_call(self, rb_intern("dup"), 0);
}

VALUE rb_hash_freeze(VALUE self) {
return capi_fast_call(self, rb_intern("freeze"), 0);
}

VALUE rb_hash_aref(VALUE self, VALUE key) {
return capi_fast_call(self, rb_intern("[]"), 1, key);
}
35 changes: 15 additions & 20 deletions vm/environment.cpp
Original file line number Diff line number Diff line change
@@ -78,6 +78,7 @@ namespace rubinius {
, signature_(0)
, signal_thread_(NULL)
, finalizer_thread_(NULL)
, loader_(NULL)
{
#ifdef ENABLE_LLVM
#if RBX_LLVM_API_VER < 305
@@ -106,6 +107,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);
@@ -197,12 +200,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);
}
@@ -591,7 +588,7 @@ namespace rubinius {
}

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

root_vm->set_call_frame(0);

@@ -840,7 +837,7 @@ namespace rubinius {

load_argv(argc_, argv_);

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

load_tool();
@@ -864,23 +861,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);
1 change: 1 addition & 0 deletions vm/gc/finalize.hpp
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ namespace rubinius {
public:
FinalizeObject()
: object(NULL)
, kind(eManaged)
, status(eLive)
, finalizer(0)
, ruby_finalizer(0)
8 changes: 7 additions & 1 deletion vm/include/capi/ruby.h
Original file line number Diff line number Diff line change
@@ -668,7 +668,7 @@ VALUE rb_uint2big(unsigned long number);
VALUE rb_ary_dup(VALUE self);

/** Return object at index. Out-of-bounds access returns Qnil. */
VALUE rb_ary_entry(VALUE self, int index);
VALUE rb_ary_entry(VALUE self, long index);

/** Return Qtrue if the array includes the item. */
VALUE rb_ary_includes(VALUE self, VALUE obj);
@@ -1103,6 +1103,12 @@ VALUE rb_uint2big(unsigned long number);
/** Create a new Hash object */
VALUE rb_hash_new();

/** Duplicate the Hash object */
VALUE rb_hash_dup(VALUE self);

/** Freeze the Hash object */
VALUE rb_hash_freeze(VALUE self);

/** Return the value associated with the key, including default values. */
VALUE rb_hash_aref(VALUE self, VALUE key);

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)
@@ -144,6 +145,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
@@ -90,7 +90,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_;
@@ -167,14 +167,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_;
}
@@ -235,6 +227,12 @@ namespace rubinius {
kcode_page_ = page;
}

SignalThread* signals() const {
return signals_;
}

SignalThread* start_signals(STATE);

console::Console* console() const {
return console_;
}
232 changes: 119 additions & 113 deletions vm/signal.cpp
Original file line number Diff line number Diff line change
@@ -3,35 +3,31 @@
#include "vm.hpp"
#include "call_frame.hpp"
#include "environment.hpp"
#include "on_stack.hpp"
#include "signal.hpp"
#include "configuration.hpp"

#include "builtin/module.hpp"
#include "builtin/array.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/constant_scope.hpp"
#include "builtin/jit.hpp"
#include "builtin/module.hpp"
#include "builtin/module.hpp"
#include "builtin/native_method.hpp"
#include "builtin/string.hpp"
#include "builtin/thread.hpp"

#include <string>
#include <iostream>
#include <fcntl.h>

#include "util/logger.hpp"

#include "dtrace/dtrace.h"

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#include <iostream>
#include <string>

#ifdef USE_EXECINFO
#include <execinfo.h>
#endif
@@ -53,33 +49,62 @@ namespace rubinius {
// crashing inside the crash handler.
static struct utsname machine_info;

SignalThread::SignalThread(STATE, Configuration& config)
: InternalThread(state, "rbx.signal", InternalThread::eSmall)
SignalThread::SignalThread(STATE)
: InternalThread(state, "rbx.signals", InternalThread::eSmall)
, shared_(state->shared())
, target_(state->vm())
, queued_signals_(0)
, queue_index_(0)
, process_index_(0)
{
signal_thread_ = this;
shared_.set_signal_handler(this);
install_default_handlers();
}

setup_default_handlers();
void SignalThread::signal_handler(int signal) {
signal_thread_->queue_signal(signal);
}

void SignalThread::queue_signal(int signal) {
if(thread_exit_) return;

metrics().system_metrics.os_signals_received++;

{
thread::Mutex::LockGuard guard(lock_);

pending_signals_[queue_index_] = signal;
/* GCC 4.8.2 can't tell that this code is equivalent.
* queue_index_ = ++queue_index_ % pending_signal_size_;
*/
++queue_index_;
queue_index_ %= pending_signal_size_;

condition_.signal();
}
}

void SignalThread::initialize(STATE) {
InternalThread::initialize(state);

for(int i = 0; i < NSIG; i++) {
Thread::create(state, vm());

for(int i = 0; i < pending_signal_size_; i++) {
pending_signals_[i] = 0;
}

worker_lock_.init();
worker_cond_.init();
queue_index_ = process_index_ = 0;

watch_lock_.init();
lock_.init();
condition_.init();
}

void SignalThread::wakeup(STATE) {
InternalThread::wakeup(state);

worker_cond_.signal();
{
thread::Mutex::LockGuard guard(lock_);
condition_.signal();
}
}

void SignalThread::stop(STATE) {
@@ -92,11 +117,78 @@ namespace rubinius {
InternalThread::stop(state);
}

void SignalThread::run(STATE) {
GCTokenImpl gct;
state->gc_independent(gct, 0);

#ifndef RBX_WINDOWS
sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_BLOCK, &set, NULL);
#endif

metrics().init(metrics::eRubyMetrics);

while(!thread_exit_) {
int signal = pending_signals_[process_index_];
pending_signals_[process_index_] = 0;

/* GCC 4.8.2 can't tell that this code is equivalent.
* process_index_ = ++process_index_ % pending_signal_size_;
*/
++process_index_;
process_index_ %= pending_signal_size_;

if(signal > 0) {
GCDependent guard(state, 0);
vm()->set_call_frame(0);

metrics().system_metrics.os_signals_processed++;

Array* args = 0;
OnStack<1> os(state, args);

args = Array::create(state, 1);
args->set(state, 0, Fixnum::from(signal));

if(!G(rubinius)->send(state, 0, state->symbol("received_signal"), args, cNil)) {
if(state->thread_state()->raise_reason() == cException ||
state->thread_state()->raise_reason() == cExit) {
Array* args = 0;
Exception* exc = 0;
OnStack<2> os(state, args, exc);

exc = state->thread_state()->current_exception();
state->thread_state()->clear_raise();

args = Array::create(state, 1);
args->set(state, 0, exc);

state->shared().env()->loader()->send(
state, 0, state->symbol("handle_exception"), args, cNil);

state->shared().env()->halt_and_exit(state);

break;
}
}

vm()->set_call_frame(0);
} else {
thread::Mutex::LockGuard guard(lock_);

if(queue_index_ != process_index_) continue;
condition_.wait(lock_);
}

vm()->set_call_frame(0);
}
}

void SignalThread::print_machine_info(PrintFunction function) {
function("node info: %s %s", machine_info.nodename, machine_info.version);
}


#define RBX_PROCESS_INFO_LEN 256

void SignalThread::print_process_info(PrintFunction function) {
@@ -126,116 +218,30 @@ namespace rubinius {
function("process info: %s", process_info);
}

void SignalThread::run(STATE) {
#ifndef RBX_WINDOWS
sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_BLOCK, &set, NULL);
#endif

GCTokenImpl gct;

metrics().init(metrics::eRubyMetrics);

while(!thread_exit_) {
{
utilities::thread::Mutex::LockGuard lg(worker_lock_);
if(thread_exit_) break;
state->gc_independent(gct, 0);
worker_cond_.wait(worker_lock_);
// If we should exit now, don't try to become
// dependent first but break and exit the thread
if(thread_exit_) break;
}
state->gc_dependent(gct, 0);
{
utilities::thread::Mutex::LockGuard lg(worker_lock_);
if(thread_exit_) break;
}

target_->wakeup(state, gct, 0);
}
}

void SignalThread::signal_handler(int sig) {
signal_thread_->handle_signal(sig);
}

void SignalThread::handle_signal(int sig) {
if(thread_exit_) return;

target_->metrics().system_metrics.os_signals_received++;

queued_signals_ = 1;
pending_signals_[sig] = 1;

target_->set_check_local_interrupts();

if(target_->should_interrupt_with_signal()) {
if(!pthread_equal(pthread_self(), target_->os_thread())) {
#ifdef RBX_WINDOWS
// TODO: Windows
#else
pthread_kill(target_->os_thread(), SIGVTALRM);
#endif
}
}

worker_cond_.signal();
}

void SignalThread::add_signal(STATE, int sig, HandlerType type) {
SYNC(state);
utilities::thread::Mutex::LockGuard lg(worker_lock_);
void SignalThread::add_signal_handler(STATE, int signal, HandlerType type) {
thread::SpinLock::LockGuard guard(watch_lock_);

#ifndef RBX_WINDOWS
struct sigaction action;

if(type == eDefault) {
action.sa_handler = SIG_DFL;
watched_signals_.remove(sig);
watched_signals_.remove(signal);
} else if(type == eIgnore) {
action.sa_handler = SIG_IGN;
watched_signals_.push_back(sig);
watched_signals_.push_back(signal);
} else {
action.sa_handler = signal_handler;
watched_signals_.push_back(sig);
watched_signals_.push_back(signal);
}

action.sa_flags = 0;
sigfillset(&action.sa_mask);

sigaction(sig, &action, NULL);
sigaction(signal, &action, NULL);
#endif
}

bool SignalThread::deliver_signals(STATE, CallFrame* call_frame) {
queued_signals_ = 0;

for(int i = 0; i < NSIG; i++) {
if(pending_signals_[i] > 0) {
pending_signals_[i] = 0;

target_->metrics().system_metrics.os_signals_processed++;

Array* args = Array::create(state, 1);
args->set(state, 0, Fixnum::from(i));

// Check whether the send raised an exception and
// stop running the handlers if that happens
if(!G(rubinius)->send(state, call_frame,
state->symbol("received_signal"), args, cNil)) {
if(state->thread_state()->raise_reason() == cException ||
state->thread_state()->raise_reason() == cExit) {
return false;
}
}
}
}

return true;
}

void SignalThread::print_backtraces() {
STATE = shared_.env()->state;
ThreadList* threads = shared_.threads();
@@ -398,7 +404,7 @@ namespace rubinius {
}
#endif

void SignalThread::setup_default_handlers() {
void SignalThread::install_default_handlers() {
#ifndef RBX_WINDOWS
// Get the machine info.
uname(&machine_info);
35 changes: 17 additions & 18 deletions vm/signal.hpp
Original file line number Diff line number Diff line change
@@ -16,16 +16,18 @@ namespace rubinius {
struct CallFrame;

class SignalThread : public InternalThread, public Lockable {
const static int pending_signal_size_ = 256;
SharedState& shared_;
VM* target_;

int pending_signals_[NSIG];
int queued_signals_;
int pending_signals_[pending_signal_size_];
int queue_index_;
int process_index_;

std::list<int> watched_signals_;
utilities::thread::SpinLock watch_lock_;

utilities::thread::Condition worker_cond_;
utilities::thread::Mutex worker_lock_;
utilities::thread::Condition condition_;
utilities::thread::Mutex lock_;

public:
enum HandlerType {
@@ -34,28 +36,25 @@ namespace rubinius {
eCustom
};

SignalThread(STATE, Configuration& config);
SignalThread(STATE);

SharedState& shared() {
return shared_;
}

void initialize(STATE);
void setup_default_handlers();

void add_signal(State*, int sig, HandlerType type = eCustom);
void handle_signal(int sig);
static void signal_handler(int sig);

bool deliver_signals(STATE, CallFrame* call_frame);
static void signal_handler(int signal);

void print_backtraces();

void open_pipes();
void install_default_handlers();

void initialize(STATE);
void run(STATE);
void stop(STATE);
void wakeup(STATE);
void stop(STATE);

void queue_signal(int signal);
void add_signal_handler(State*, int signal, HandlerType type = eCustom);

void print_backtraces();

typedef void (*PrintFunction)(const char* message, ...);

6 changes: 0 additions & 6 deletions vm/state.cpp
Original file line number Diff line number Diff line change
@@ -22,12 +22,6 @@ namespace rubinius {
set_call_frame(call_frame);
vm_->clear_check_local_interrupts();

if(vm_->run_signals_) {
if(!vm_->shared.signal_handler()->deliver_signals(this, call_frame)) {
return false;
}
}

Exception* exc = vm_->interrupted_exception_.get();
if(!exc->nil_p()) {
vm_->interrupted_exception_.set(nil<Exception>());

0 comments on commit a97b41b

Please sign in to comment.