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

Commits on May 24, 2016

  1. Allow per-Thread, per-Fiber stack sizing.

    Thread.new, Thread.start, Thread.fork, and Fiber.new all take an optional
    keyword argument of the form: 'stack_size: Fixnum', where Fixnum includes
    objects that respond to #to_int. The keyword argument, if present, sets the
    size of the Thread's or Fiber's stack size. If the argument is not present or
    is zero, the default stack size, configured with -Xmachine.thread.stack_size
    and -Xmachine.fiber.stack_size are used instead.
    
    Added configuration for machine.thread.stack_size to set the default size of
    Thread stacks. Also moved fiber.stack_size configuration under machine
    section.
    
    Also added configuration for machine.stack_cushion to set the size in bytes of
    the cushion to leave at the stack end when checking for stack usage. This is
    necessary because we check the stack usage before calling a method. The method
    may use quite a bit of stack but we can't know this beforehand (hand-wavy
    "can't" here). If we are near the end but not yet at the end, we could easily
    exhaust the stack after calling the method and then segfault.
    brixen committed May 24, 2016
    Copy the full SHA
    c26139a View commit details
  2. Copy the full SHA
    c8b0422 View commit details
4 changes: 3 additions & 1 deletion core/enumerator.rb
Original file line number Diff line number Diff line change
@@ -449,6 +449,8 @@ def zip(*lists)

if Rubinius::Fiber::ENABLED
class FiberGenerator
STACK_SIZE = 40_960

attr_reader :result

def initialize(obj)
@@ -477,7 +479,7 @@ def rewind

def reset
@done = false
@fiber = Rubinius::Fiber.new(0) do
@fiber = Rubinius::Fiber.new stack_size: STACK_SIZE do
obj = @object
@result = obj.each do |*val|
Rubinius::Fiber.yield *val
11 changes: 5 additions & 6 deletions core/fiber.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
module Rubinius
class Fiber
def self.create(callable)
Rubinius.primitive :fiber_new
raise NotImplementedError, "Fibers not supported on this platform"
end
attr_reader :stack_size

def self.new(size=0, &block)
def self.new(**kw, &block)
if block.nil?
raise ArgumentError, "Fiber.new requires a block"
end

create(block)
stack_size = Rubinius::Type.try_convert kw[:stack_size], Fixnum, :to_int

Rubinius.invoke_primitive :fiber_new, stack_size, block, self
end

def self.current
10 changes: 5 additions & 5 deletions core/rbconfig.rb
Original file line number Diff line number Diff line change
@@ -85,9 +85,9 @@ module RbConfig
CONFIG["NROFF"] = "/usr/bin/nroff"
CONFIG["MAKEDIRS"] = "mkdir -p"
# compile tools
CONFIG["CC"] = (ENV["CC"] || Rubinius::BUILD_CONFIG[:cc].sub(/^(gcc|clang).*$/, "cc")).dup
CONFIG["CXX"] = (ENV["CXX"] || Rubinius::BUILD_CONFIG[:cxx].sub(/^(g|clang)\+\+.*$/, "c++")).dup
CONFIG["CPP"] = "#{(ENV["CPP"] || Rubinius::BUILD_CONFIG[:cc].sub(/^(gcc|clang).*$/, "cc"))} -E"
CONFIG["CC"] = (ENV["CC"] || Rubinius::BUILD_CONFIG[:cc].sub(/^((gcc|clang)[-.0-9]*)/, "cc")).dup
CONFIG["CXX"] = (ENV["CXX"] || Rubinius::BUILD_CONFIG[:cxx].sub(/^((g|clang)\+\+[-.0-9]*)/, "c++")).dup
CONFIG["CPP"] = "#{(ENV["CPP"] || Rubinius::BUILD_CONFIG[:cc].sub(/^((gcc|clang)[-.0-9]*)/, "cc"))} -E"
CONFIG["YACC"] = "bison -y"
CONFIG["RANLIB"] = "ranlib"
CONFIG["AR"] = "ar"
@@ -210,8 +210,8 @@ module RbConfig
CONFIG["PACKAGE_STRING"] = ""
CONFIG["PACKAGE_BUGREPORT"] = ""

ldshared = (ENV["LDSHARED"] || Rubinius::LDSHARED.sub(/^(gcc|clang)/, "cc")).dup
ldsharedxx = (ENV["LDSHAREDXX"] || Rubinius::LDSHAREDXX.sub(/^(g|clang)\+\+/, "c++")).dup
ldshared = (ENV["LDSHARED"] || Rubinius::LDSHARED.sub(/^((gcc|clang)[-.0-9]*)/, "cc")).dup
ldsharedxx = (ENV["LDSHAREDXX"] || Rubinius::LDSHAREDXX.sub(/^((g|clang)\+\+[-.0-9]*)/, "c++")).dup

CONFIG["LDSHARED"] = ldshared
CONFIG["LIBRUBY_LDSHARED"] = ldshared
13 changes: 9 additions & 4 deletions core/thread.rb
Original file line number Diff line number Diff line change
@@ -7,9 +7,12 @@ class Thread
attr_reader :recursive_objects
attr_reader :pid
attr_reader :exception
attr_reader :stack_size

def self.new(*args, &block)
thr = Rubinius.invoke_primitive :thread_s_new, args, block, self
def self.new(*args, **kw, &block)
stack_size = Rubinius::Type.try_convert kw[:stack_size], Fixnum, :to_int

thr = Rubinius.invoke_primitive :thread_s_new, args, stack_size, block, self

Rubinius::VariableScope.of_sender.locked!

@@ -20,10 +23,12 @@ def self.new(*args, &block)
return thr
end

def self.start(*args, &block)
def self.start(*args, **kw, &block)
raise ArgumentError.new("no block passed to Thread.start") unless block

Rubinius.invoke_primitive :thread_s_start, args, block, self
stack_size = Rubinius::Type.try_convert kw[:stack_size], Fixnum, :to_int

Rubinius.invoke_primitive :thread_s_start, args, stack_size, block, self
end

class << self
36 changes: 22 additions & 14 deletions library/rubinius/configuration.rb
Original file line number Diff line number Diff line change
@@ -40,14 +40,6 @@
"How many bytes allocated by C extensions til the GC is run"
end

c.section "fiber" do |s|
s.vm_variable "stacks", 10,
"The number of stacks in each Threads stack pool"

s.vm_variable "stack_size", 512 * 1024,
"The size of each stack"
end

c.section "capi" do |s|
s.vm_variable "global_flush", false,
"Flush all CAPI handles at CAPI call boundaries"
@@ -66,19 +58,35 @@
c.vm_variable "allocation_tracking", false,
"Enable allocation tracking for new objects"

c.section "machine" do |s|
s.section "call_site" do |cs|
c.section "machine" do |m|
m.section "fiber" do |f|
f.vm_variable "stacks", 10,
"The number of stacks in each Threads stack pool"

f.vm_variable "stack_size", 512 * 1024,
"The size in bytes of the Fiber's stack"
end

m.section "thread" do |t|
t.vm_variable "stack_size", 4 * 1024 * 1024,
"The size in bytes of the Thread's stack"
end

m.vm_variable "stack_cushion", 4096,
"Size in bytes to reserve when checking stack overflow"

m.section "call_site" do |cs|
cs.vm_variable "cache", true,
"Cache executables at call sites"

cs.vm_variable "limit", 3,
"Maximum number of caches at call sites"
end
end

c.section "jit" do |j|
j.vm_variable "enabled", false,
"Just-in-time compile managed code to native code"
m.section "jit" do |j|
j.vm_variable "enabled", false,
"Just-in-time compile managed code to native code"
end
end

c.section "system" do |s|
13 changes: 9 additions & 4 deletions machine/builtin/fiber.cpp
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ namespace rubinius {
fib->root(true);
fib->status(Fiber::eRunning);

fib->data(state->vm()->new_fiber_data(true));
fib->data(state->vm()->new_fiber_data(true, fib->stack_size()->to_native()));
fib->data()->set_call_frame(state->vm()->call_frame());

state->memory()->needs_finalization(state, fib,
@@ -107,11 +107,16 @@ namespace rubinius {
#endif
}

Fiber* Fiber::create(STATE, Object* self, Object* callable) {
Fiber* Fiber::create(STATE, Object* self, Object* stack_size, Object* callable) {
#ifdef RBX_FIBER_ENABLED
Fiber* fib = state->memory()->new_object<Fiber>(state, as<Class>(self));
fib->starter(state, callable);

if(Fixnum* size = try_as<Fixnum>(stack_size)) {
state->vm()->validate_stack_size(state, size->to_native());
fib->stack_size(state, size);
}

state->vm()->metrics().system.fibers_created++;

state->memory()->needs_finalization(state, fib,
@@ -127,7 +132,7 @@ namespace rubinius {
Object* Fiber::resume(STATE, Arguments& args) {
#ifdef RBX_FIBER_ENABLED
if(!data()) {
data(state->vm()->new_fiber_data());
data(state->vm()->new_fiber_data(stack_size()->to_native()));
}

if(status() == Fiber::eDead || data()->dead_p()) {
@@ -188,7 +193,7 @@ namespace rubinius {
Object* Fiber::transfer(STATE, Arguments& args) {
#ifdef RBX_FIBER_ENABLED
if(!data()) {
data(state->vm()->new_fiber_data());
data(state->vm()->new_fiber_data(stack_size()->to_native()));
}

if(status() == Fiber::eDead || data()->dead_p()) {
16 changes: 3 additions & 13 deletions machine/builtin/fiber.hpp
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ namespace rubinius {
attr_accessor(exception, Exception);
attr_accessor(locals, LookupTable);
attr_accessor(dead, Object);
attr_accessor(stack_size, Fixnum);

private:
attr_field(status, Status);
@@ -69,18 +70,6 @@ namespace rubinius {
return data()->machine();
}

void* stack_address() const {
return data()->stack_address();
}

void* stack_start() const {
return (void*)((uintptr_t)stack_address() + stack_size());
}

int stack_size() const {
return data()->stack_size();
}

memory::VariableRootBuffers& variable_root_buffers() {
return data()->variable_root_buffers();
}
@@ -94,13 +83,14 @@ namespace rubinius {
obj->exception(nil<Exception>());
obj->locals(nil<LookupTable>());
obj->dead(nil<Object>());
obj->stack_size(Fixnum::from(state->shared().config.machine_fiber_stack_size.value));
obj->status(eNotStarted);
obj->root(false);
obj->data(NULL);
}

// Rubinius.primitive :fiber_new
static Fiber* create(STATE, Object* self, Object* callable);
static Fiber* create(STATE, Object* self, Object* stack_size, Object* callable);
static void start_on_stack();

// Rubinius.primitive :fiber_s_current
2 changes: 1 addition & 1 deletion machine/builtin/jit.cpp
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ namespace rubinius {
}

Object* JIT::enabled_p(STATE) {
return RBOOL(state->shared().config.jit_enabled.value);
return RBOOL(state->shared().config.machine_jit_enabled.value);
}

Object* JIT::compile_threshold(STATE) {
22 changes: 2 additions & 20 deletions machine/builtin/native_function.cpp
Original file line number Diff line number Diff line change
@@ -304,24 +304,11 @@ namespace rubinius {
static void invoke_callback(ffi_cif* cif, void* retval,
void** parameters, void* user_data)
{
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
FFIData* stub = reinterpret_cast<FFIData*>(user_data);

bool destroy_vm = false;
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
if(!env) {
// TODO: fix this, the threads should *always* be set up correctly
// Apparently we're running in a new thread here, setup
// everything we need here.
destroy_vm = true;

VM* vm = stub->shared->thread_nexus()->new_vm(stub->shared, "ruby.ffi");

vm->set_stack_bounds(THREAD_STACK_SIZE);

// Setup nativemethod handles into thread local
State state(vm);
NativeMethod::init_thread(&state);
env = NativeMethodEnvironment::get();
rubinius::bug("attempted to run native code from an incorrectly initialized Thread");
}

State* state = env->state();
@@ -557,11 +544,6 @@ namespace rubinius {
}

state->vm()->become_unmanaged();

if(destroy_vm) {
NativeMethod::cleanup_thread(state);
VM::discard(state, state->vm());
}
}


18 changes: 14 additions & 4 deletions machine/builtin/thread.cpp
Original file line number Diff line number Diff line change
@@ -144,10 +144,15 @@ namespace rubinius {
return value;
}

Thread* Thread::s_new(STATE, Object* self, Array* args, Object* block) {
Thread* Thread::s_new(STATE, Object* self, Array* args, Object* stack_size, Object* block) {
Thread* thread = Thread::create(state, self, run_instance);
OnStack<1> os(state, thread);

if(Fixnum* size = try_as<Fixnum>(stack_size)) {
state->vm()->validate_stack_size(state, size->to_native());
thread->stack_size(state, size);
}

CallFrame* call_frame = state->vm()->get_ruby_frame(1);

logger::write("new thread: %s, %s:%d",
@@ -165,10 +170,15 @@ namespace rubinius {
return thread;
}

Thread* Thread::s_start(STATE, Object* self, Array* args, Object* block) {
Thread* Thread::s_start(STATE, Object* self, Array* args, Object* stack_size, Object* block) {
Thread* thread = Thread::create(state, self, run_instance);
OnStack<1> os(state, thread);

if(Fixnum* size = try_as<Fixnum>(stack_size)) {
state->vm()->validate_stack_size(state, size->to_native());
thread->stack_size(state, size);
}

CallFrame* call_frame = state->vm()->get_ruby_frame(1);

logger::write("start thread: %s, %s:%d",
@@ -299,7 +309,7 @@ namespace rubinius {

pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, THREAD_STACK_SIZE);
pthread_attr_setstacksize(&attrs, self->stack_size()->to_native());
pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);

int status = pthread_create(&self->vm()->os_thread(), &attrs,
@@ -360,7 +370,7 @@ namespace rubinius {
VM* vm = reinterpret_cast<VM*>(ptr);
State state_obj(vm), *state = &state_obj;

vm->set_stack_bounds(THREAD_STACK_SIZE);
vm->set_stack_bounds(vm->thread->stack_size()->to_native());
vm->set_current_thread();
vm->set_start_time();

6 changes: 4 additions & 2 deletions machine/builtin/thread.hpp
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@ namespace rubinius {
attr_accessor(priority, Fixnum);
attr_accessor(pid, Fixnum);
attr_accessor(initialized, Object);
attr_accessor(stack_size, Fixnum);

private:
utilities::thread::SpinLock init_lock_;
@@ -74,6 +75,7 @@ namespace rubinius {
obj->priority(Fixnum::from(0));
obj->pid(Fixnum::from(0));
obj->initialized(cFalse);
obj->stack_size(Fixnum::from(state->shared().config.machine_thread_stack_size.value));

obj->init_lock_.init();
obj->join_lock_.init();
@@ -85,10 +87,10 @@ namespace rubinius {
public:

// Rubinius.primitive :thread_s_new
static Thread* s_new(STATE, Object* self, Array* args, Object* block);
static Thread* s_new(STATE, Object* self, Array* args, Object* kw, Object* block);

// Rubinius.primitive :thread_s_start
static Thread* s_start(STATE, Object* self, Array* args, Object* block);
static Thread* s_start(STATE, Object* self, Array* args, Object* kw, Object* block);

/**
* Returns the Thread object for the state.
4 changes: 0 additions & 4 deletions machine/call_frame.hpp
Original file line number Diff line number Diff line change
@@ -197,12 +197,8 @@ namespace rubinius {
Object* find_breakpoint(STATE);
};

#define THREAD_STACK_SIZE 4194304

#define ALLOCA_CALL_FRAME(stack_size) \
reinterpret_cast<CallFrame*>(alloca(sizeof(CallFrame) + (sizeof(Object*) * stack_size)))
};

#define MAX_CALL_FRAMES (THREAD_STACK_SIZE / sizeof(CallFrame))

#endif
2 changes: 1 addition & 1 deletion machine/environment.cpp
Original file line number Diff line number Diff line change
@@ -88,7 +88,7 @@ namespace rubinius {
root_vm->set_main_thread();
shared->set_root_vm(root_vm);

size_t stack_size = THREAD_STACK_SIZE;
size_t stack_size = 0;
struct rlimit rlim;

if(getrlimit(RLIMIT_STACK, &rlim) == 0) {
2 changes: 1 addition & 1 deletion machine/fiber_data.cpp
Original file line number Diff line number Diff line change
@@ -156,7 +156,7 @@ namespace rubinius {

FiberStack* FiberData::allocate_stack(STATE) {
assert(!stack_);
stack_ = state->vm()->allocate_fiber_stack();
stack_ = state->vm()->allocate_fiber_stack(stack_size_);
return stack_;
}

Loading