Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Use a locking strategy only when needed.

Since this locking has a significant overhead, we only set it up when
requested. Currently we explicit request this when we start a new thread
for the sending scope and when we create a Proc, since that might be
passed to another thread.
  • Loading branch information...
commit 2fec8460384bc53c8edf07205271802578043454 1 parent 322cc1e
@dbussink dbussink authored
View
2  kernel/bootstrap/thread.rb
@@ -107,6 +107,8 @@ def inspect
def self.new(*args)
thr = Rubinius.invoke_primitive :thread_allocate, self
+ Rubinius::VariableScope.of_sender.locked!
+
Rubinius.asm(args, thr) do |args, obj|
run obj
dup
View
10 kernel/bootstrap/variable_scope.rb
@@ -37,6 +37,16 @@ def script?
raise PrimitiveFailure, "Rubinius::VariableScope#script primitive failed"
end
+ def locked?
+ Rubinius.primitive :variable_scope_locked
+ raise PrimitiveFailure, "Rubinius::VariableScope#locked primitive failed"
+ end
+
+ def locked!
+ Rubinius.primitive :variable_scope_set_locked
+ raise PrimitiveFailure, "Rubinius::VariableScope#set_locked primitive failed"
+ end
+
# To handle Module#private, protected
attr_accessor :method_visibility
end
View
8 vm/builtin/block_environment.cpp
@@ -58,6 +58,14 @@ namespace rubinius {
state->symbol("block_call_under"));
}
+ void BlockEnvironment::lock_scope(STATE) {
+ if(scope_ && !scope_->nil_p()) {
+ scope_->set_locked(state);
+ }
+ if(top_scope_ && !top_scope_->nil_p()) {
+ top_scope_->set_locked(state);
+ }
+ }
BlockEnvironment* BlockEnvironment::allocate(STATE) {
BlockEnvironment* env = state->new_object<BlockEnvironment>(G(blokenv));
View
2  vm/builtin/block_environment.hpp
@@ -83,6 +83,8 @@ namespace rubinius {
// Rubinius.primitive :block_env_of_sender
static Object* of_sender(STATE, CallFrame* calling_environment);
+ void lock_scope(STATE);
+
BlockEnvironment* dup(STATE);
class Info : public TypeInfo {
View
1  vm/builtin/proc.cpp
@@ -40,6 +40,7 @@ namespace rubinius {
if(BlockEnvironment* be = try_as<BlockEnvironment>(env)) {
Proc* proc = Proc::create(state, self);
proc->block(state, be);
+ be->lock_scope(state);
return proc;
}
View
68 vm/builtin/variable_scope.cpp
@@ -98,12 +98,34 @@ namespace rubinius {
return cNil;
}
+ Object* VariableScope::locked(STATE) {
+ return RBOOL(locked_p());
+ }
+
+ Object* VariableScope::set_locked(STATE) {
+ flags_ |= CallFrame::cScopeLocked;
+ VariableScope* parent = parent_;
+ while(parent && !parent->nil_p()) {
+ parent->set_locked(state);
+ parent = parent->parent();
+ }
+ return cNil;
+ }
+
+ void VariableScope::set_local_internal(STATE, int pos, Object* val) {
+ if(isolated_) {
+ heap_locals_->put(state, pos, val);
+ } else {
+ set_local(pos, val);
+ }
+ }
+
void VariableScope::set_local(STATE, int pos, Object* val) {
- utilities::thread::SpinLock::LockGuard guard(lock_);
- if(isolated_) {
- heap_locals_->put(state, pos, val);
+ if(unlikely(locked_p())) {
+ utilities::thread::SpinLock::LockGuard guard(lock_);
+ set_local_internal(state, pos, val);
} else {
- set_local(pos, val);
+ set_local_internal(state, pos, val);
}
}
@@ -123,12 +145,20 @@ namespace rubinius {
ary[pos] = val;
}
+ Object* VariableScope::get_local_internal(STATE, int pos) {
+ if(isolated_) {
+ return heap_locals_->at(pos);
+ } else {
+ return get_local(pos);
+ }
+ }
+
Object* VariableScope::get_local(STATE, int pos) {
- utilities::thread::SpinLock::LockGuard guard(lock_);
- if(isolated_) {
- return heap_locals_->at(pos);
+ if(unlikely(locked_p())) {
+ utilities::thread::SpinLock::LockGuard guard(lock_);
+ return get_local_internal(state, pos);
} else {
- return get_local(pos);
+ return get_local_internal(state, pos);
}
}
@@ -155,18 +185,26 @@ namespace rubinius {
return RBOOL(script_p());
}
- void VariableScope::flush_to_heap(STATE) {
- utilities::thread::SpinLock::LockGuard guard(lock_);
+ void VariableScope::flush_to_heap_internal(STATE) {
if(isolated_) return;
- Tuple* new_locals = Tuple::create(state, number_of_locals_);
- for(int i = 0; i < number_of_locals_; i++) {
- new_locals->put(state, i, locals_[i]);
- }
+ Tuple* new_locals = Tuple::create(state, number_of_locals_);
+ for(int i = 0; i < number_of_locals_; i++) {
+ new_locals->put(state, i, locals_[i]);
+ }
heap_locals(state, new_locals);
- atomic::memory_barrier();
isolated_ = 1;
}
+ void VariableScope::flush_to_heap(STATE) {
+ if(unlikely(locked_p())) {
+ utilities::thread::SpinLock::LockGuard guard(lock_);
+ flush_to_heap_internal(state);
+ flags_ &= ~CallFrame::cScopeLocked;
+ } else {
+ flush_to_heap_internal(state);
+ }
+ }
+
void VariableScope::Info::mark(Object* obj, ObjectMark& mark) {
auto_mark(obj, mark);
View
14 vm/builtin/variable_scope.hpp
@@ -35,6 +35,10 @@ namespace rubinius {
// The Fiber that the scope was created on
Fiber* fiber_; // slot
+ void set_local_internal(STATE, int pos, Object* val);
+ Object* get_local_internal(STATE, int pos);
+ void flush_to_heap_internal(STATE);
+
public:
Object* self_; // slot
@@ -74,6 +78,10 @@ namespace rubinius {
return flags_ & CallFrame::cScript;
}
+ bool locked_p() {
+ return flags_ & CallFrame::cScopeLocked;
+ }
+
void set_local(int pos, Object* val);
void set_local(STATE, int pos, Object* val);
@@ -112,6 +120,12 @@ namespace rubinius {
// Rubinius.primitive :variable_scope_script
Object* script(STATE);
+ // Rubinius.primitive :variable_scope_locked
+ Object* locked(STATE);
+
+ // Rubinius.primitive :variable_scope_set_locked
+ Object* set_locked(STATE);
+
public: // Rubinius Type stuff
class Info : public TypeInfo {
public:
View
3  vm/call_frame.hpp
@@ -39,7 +39,8 @@ namespace rubinius {
cInlineBlock = 1 << 8,
cNativeMethod = 1 << 9,
cTopLevelVisibility = 1 << 10,
- cScript = 1 << 11
+ cScript = 1 << 11,
+ cScopeLocked = 1 << 12
};
CallFrame* previous;
Please sign in to comment.
Something went wrong with that request. Please try again.