Skip to content

Commit

Permalink
Return of tracking the fiber data explicitly
Browse files Browse the repository at this point in the history
This mostly reverts 1e19933 and
introduces a separate mechanism for marking fiber data's. This marking
is used so we can clean up inactive fibers that are unreachable.

The reason for reverting the original change is not because it's wrong,
but because it makes concurrent gc much harder. The problem is that it
was scanning stacks inside the fiber marking, which is a problem with
concurrent marking.

Therefore we now use a mechanism where we can scan the not running but
still active fibers in the final phase of the mature GC, so we can do
that in the stop the world phases of concurrent GC.

The downside of this approach compared to the previous one is that
inactive young fibers will be scanned during young gc cycles and kept
active until promoted. Only after that will they be cleaned up. This
only happens for fibers that haven't finished and are not reachable
anymore, so this is not a huge issue.
  • Loading branch information
dbussink committed Jun 3, 2013
1 parent 5c16d39 commit b3579cf
Show file tree
Hide file tree
Showing 13 changed files with 145 additions and 35 deletions.
20 changes: 5 additions & 15 deletions vm/builtin/fiber.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ namespace rubinius {
fib->locals(state, nil<LookupTable>()); fib->locals(state, nil<LookupTable>());
fib->root_ = true; fib->root_ = true;
fib->status_ = Fiber::eRunning; fib->status_ = Fiber::eRunning;
fib->data_ = new FiberData(state->vm(), true);
fib->data_ = state->vm()->new_fiber_data(true);


state->memory()->needs_finalization(fib, (FinalizerFunction)&Fiber::finalize); state->memory()->needs_finalization(fib, (FinalizerFunction)&Fiber::finalize);


Expand Down Expand Up @@ -120,7 +121,7 @@ namespace rubinius {
Object* Fiber::resume(STATE, Arguments& args, CallFrame* calling_environment) { Object* Fiber::resume(STATE, Arguments& args, CallFrame* calling_environment) {
#ifdef RBX_FIBER_ENABLED #ifdef RBX_FIBER_ENABLED
if(!data_) { if(!data_) {
data_ = new FiberData(state->vm()); data_ = state->vm()->new_fiber_data();
} }


if(status_ == Fiber::eDead || data_->dead_p()) { if(status_ == Fiber::eDead || data_->dead_p()) {
Expand Down Expand Up @@ -178,7 +179,7 @@ namespace rubinius {
Object* Fiber::transfer(STATE, Arguments& args, CallFrame* calling_environment) { Object* Fiber::transfer(STATE, Arguments& args, CallFrame* calling_environment) {
#ifdef RBX_FIBER_ENABLED #ifdef RBX_FIBER_ENABLED
if(!data_) { if(!data_) {
data_ = new FiberData(state->vm()); data_ = state->vm()->new_fiber_data();
} }


if(status_ == Fiber::eDead || data_->dead_p()) { if(status_ == Fiber::eDead || data_->dead_p()) {
Expand Down Expand Up @@ -290,20 +291,9 @@ namespace rubinius {
void Fiber::Info::mark(Object* obj, ObjectMark& mark) { void Fiber::Info::mark(Object* obj, ObjectMark& mark) {
auto_mark(obj, mark); auto_mark(obj, mark);
Fiber* fib = force_as<Fiber>(obj); Fiber* fib = force_as<Fiber>(obj);

FiberData* data = fib->data_; FiberData* data = fib->data_;
if(!data || data->dead_p()) return; if(!data || data->dead_p()) return;

data->set_mark();
AddressDisplacement dis(data->data_offset(),
data->data_lower_bound(),
data->data_upper_bound());

if(CallFrame* cf = data->call_frame()) {
mark.gc->walk_call_frame(cf, &dis);
}

mark.gc->scan(data->variable_root_buffers(), false, &dis);

} }
} }


2 changes: 2 additions & 0 deletions vm/fiber_data.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ namespace rubinius {


FiberData::~FiberData() { FiberData::~FiberData() {
if(heap_) free(heap_); if(heap_) free(heap_);
if(!thread_) return;
thread_->remove_fiber_data(this);
} }


void FiberData::take_stack(STATE) { void FiberData::take_stack(STATE) {
Expand Down
21 changes: 20 additions & 1 deletion vm/fiber_data.hpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ namespace rubinius {
eDead eDead
} status_; } status_;


bool mark_;

VM* thread_; VM* thread_;
FiberStack* stack_; FiberStack* stack_;


Expand All @@ -62,9 +64,11 @@ namespace rubinius {


CallFrame* call_frame_; CallFrame* call_frame_;


public: // Private constructor so only FiberStack can use it.

FiberData(VM* thread, bool root=false) FiberData(VM* thread, bool root=false)
: status_(root ? eOnStack : eInitial) : status_(root ? eOnStack : eInitial)
, mark_(true)
, thread_(thread) , thread_(thread)
, stack_(0) , stack_(0)
, heap_(0) , heap_(0)
Expand All @@ -73,12 +77,27 @@ namespace rubinius {
, call_frame_(0) , call_frame_(0)
{} {}


friend class FiberStacks;

public:
~FiberData(); ~FiberData();


bool dead_p() const { bool dead_p() const {
return status_ == eDead; return status_ == eDead;
} }


bool marked_p() const {
return mark_;
}

void set_mark() {
mark_ = true;
}

void clear_mark() {
mark_ = false;
}

CallFrame* call_frame() const { CallFrame* call_frame() const {
return call_frame_; return call_frame_;
} }
Expand Down
56 changes: 50 additions & 6 deletions vm/fiber_stack.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -57,21 +57,58 @@ namespace rubinius {
dec_ref(); dec_ref();
} }


FiberStacks::FiberStacks(SharedState& shared) FiberStacks::FiberStacks(VM* thread, SharedState& shared)
: max_stacks_(shared.config.fiber_stacks) : max_stacks_(shared.config.fiber_stacks)
, stack_size_(shared.config.fiber_stack_size) , stack_size_(shared.config.fiber_stack_size)
, thread_(thread)
, trampoline_(0) , trampoline_(0)
{} {
lock_.init();
}


FiberStacks::~FiberStacks() { FiberStacks::~FiberStacks() {
for(Stacks::iterator i = stacks_.begin(); for(Datas::iterator i = datas_.begin(); i != datas_.end(); ++i) {
i != stacks_.end(); (*i)->die();
++i) }
{
for(Stacks::iterator i = stacks_.begin(); i != stacks_.end(); ++i) {
i->free(); i->free();
} }
} }


void FiberStacks::gc_scan(GarbageCollector* gc, bool marked_only) {
for(Datas::iterator i = datas_.begin(); i != datas_.end(); ++i) {
FiberData* data = *i;
if(data->dead_p()) continue;
if(marked_only && !data->marked_p()) {
data->status_ = FiberData::eDead;
continue;
}

AddressDisplacement dis(data->data_offset(),
data->data_lower_bound(),
data->data_upper_bound());

if(CallFrame* cf = data->call_frame()) {
gc->walk_call_frame(cf, &dis);
}

gc->scan(data->variable_root_buffers(), false, &dis);
}
}

FiberData* FiberStacks::new_data(bool root) {
utilities::thread::SpinLock::LockGuard guard(lock_);
FiberData* data = new FiberData(thread_, root);
datas_.insert(data);
return data;
}

void FiberStacks::remove_data(FiberData* data) {
utilities::thread::SpinLock::LockGuard guard(lock_);
datas_.erase(data);
}

FiberStack* FiberStacks::allocate() { FiberStack* FiberStacks::allocate() {
for(Stacks::iterator i = stacks_.begin(); for(Stacks::iterator i = stacks_.begin();
i != stacks_.end(); i != stacks_.end();
Expand Down Expand Up @@ -115,4 +152,11 @@ namespace rubinius {


return trampoline_; return trampoline_;
} }

void FiberStacks::gc_clear_mark() {
utilities::thread::SpinLock::LockGuard guard(lock_);
for(Datas::iterator i = datas_.begin(); i != datas_.end(); ++i) {
(*i)->clear_mark();
}
}
} }
14 changes: 13 additions & 1 deletion vm/fiber_stack.hpp
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef RBX_VM_FIBER_STACK_HPP #ifndef RBX_VM_FIBER_STACK_HPP
#define RBX_VM_FIBER_STACK_HPP #define RBX_VM_FIBER_STACK_HPP


#include <tr1/unordered_set>
#include "util/thread.hpp" #include "util/thread.hpp"


namespace rubinius { namespace rubinius {
Expand Down Expand Up @@ -71,20 +72,31 @@ namespace rubinius {


private: private:
typedef std::list<FiberStack> Stacks; typedef std::list<FiberStack> Stacks;
typedef std::tr1::unordered_set<FiberData*> Datas;


size_t max_stacks_; size_t max_stacks_;
size_t stack_size_; size_t stack_size_;


VM* thread_;
Stacks stacks_; Stacks stacks_;
Datas datas_;
void* trampoline_; void* trampoline_;
utilities::thread::SpinLock lock_;


public: public:
FiberStacks(SharedState& shared); FiberStacks(VM* thread, SharedState& shared);
~FiberStacks(); ~FiberStacks();


FiberStack* allocate(); FiberStack* allocate();


void remove_data(FiberData* data);

FiberData* new_data(bool root=false);

void* trampoline(); void* trampoline();

void gc_clear_mark();
void gc_scan(GarbageCollector* gc, bool marked_only = true);
}; };
} }


Expand Down
17 changes: 8 additions & 9 deletions vm/gc/baker.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -235,15 +235,14 @@ namespace rubinius {
// objects kept alive for finalization through weakrefs. // objects kept alive for finalization through weakrefs.
clean_weakrefs(true); clean_weakrefs(true);


// Objects with finalizers must be kept alive until the finalizers have do {
// run. // Objects with finalizers must be kept alive until the finalizers have
walk_finalizers(); // run.

walk_finalizers();
// Process possible promotions from processing objects with finalizers. // Scan any fibers that aren't running but still active
handle_promotions(); scan_fibers(data, false);

handle_promotions();
if(!promoted_stack_.empty()) rubinius::bug("promote stack has elements!"); } while(!promoted_stack_.empty() && !fully_scanned_p());
if(!fully_scanned_p()) rubinius::bug("more young refs");


// Remove unreachable locked objects still in the list // Remove unreachable locked objects still in the list
if(data.threads()) { if(data.threads()) {
Expand Down
12 changes: 12 additions & 0 deletions vm/gc/gc.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -396,6 +396,18 @@ namespace rubinius {
} }
} }


void GarbageCollector::scan_fibers(GCData& data, bool marked_only) {
if(data.threads()) {
for(std::list<ManagedThread*>::iterator i = data.threads()->begin();
i != data.threads()->end();
++i) {
if(VM* vm = (*i)->as_vm()) {
vm->gc_fiber_scan(this, marked_only);
}
}
}
}

void GarbageCollector::clean_weakrefs(bool check_forwards) { void GarbageCollector::clean_weakrefs(bool check_forwards) {
if(!weak_refs_) return; if(!weak_refs_) return;


Expand Down
1 change: 1 addition & 0 deletions vm/gc/gc.hpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ namespace rubinius {
return obj; return obj;
} }


void scan_fibers(GCData& data, bool marked_only = true);
void clean_weakrefs(bool check_forwards=false); void clean_weakrefs(bool check_forwards=false);
void clean_locked_objects(ManagedThread* thr, bool young_only); void clean_locked_objects(ManagedThread* thr, bool young_only);


Expand Down
3 changes: 1 addition & 2 deletions vm/gc/immix.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ namespace rubinius {


gc_.process_mark_stack(allocator_); gc_.process_mark_stack(allocator_);


// We've now finished marking the entire object graph.
// Clean weakrefs before keeping additional objects alive // Clean weakrefs before keeping additional objects alive
// for finalization, so people don't get a hold of finalized // for finalization, so people don't get a hold of finalized
// objects through weakrefs. // objects through weakrefs.
Expand All @@ -199,9 +198,9 @@ namespace rubinius {
// live, so we must check the mark_stack again. // live, so we must check the mark_stack again.
do { do {
walk_finalizers(); walk_finalizers();
scan_fibers(data, true);
} while(gc_.process_mark_stack(allocator_)); } while(gc_.process_mark_stack(allocator_));



// Remove unreachable locked objects still in the list // Remove unreachable locked objects still in the list
if(data.threads()) { if(data.threads()) {
for(std::list<ManagedThread*>::iterator i = data.threads()->begin(); for(std::list<ManagedThread*>::iterator i = data.threads()->begin();
Expand Down
13 changes: 13 additions & 0 deletions vm/objectmemory.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ namespace rubinius {
#endif #endif


code_manager_.clear_marks(); code_manager_.clear_marks();
clear_fiber_marks(data.threads());


immix_->reset_stats(); immix_->reset_stats();


Expand Down Expand Up @@ -721,6 +722,18 @@ namespace rubinius {
handles->deallocate_handles(cached, mark(), young); handles->deallocate_handles(cached, mark(), young);
} }


void ObjectMemory::clear_fiber_marks(std::list<ManagedThread*>* threads) {
if(threads) {
for(std::list<ManagedThread*>::iterator i = threads->begin();
i != threads->end();
++i) {
if(VM* vm = (*i)->as_vm()) {
vm->gc_fiber_clear_mark();
}
}
}
}

size_t ObjectMemory::mature_bytes_allocated() { size_t ObjectMemory::mature_bytes_allocated() {
return immix_->bytes_allocated() + mark_sweep_->allocated_bytes; return immix_->bytes_allocated() + mark_sweep_->allocated_bytes;
} }
Expand Down
1 change: 1 addition & 0 deletions vm/objectmemory.hpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ namespace rubinius {


void validate_handles(capi::Handles* handles); void validate_handles(capi::Handles* handles);
void prune_handles(capi::Handles* handles, std::list<capi::Handle*>* cached, BakerGC* young); void prune_handles(capi::Handles* handles, std::list<capi::Handle*>* cached, BakerGC* young);
void clear_fiber_marks(std::list<ManagedThread*>* threads);


ObjectPosition validate_object(Object* obj); ObjectPosition validate_object(Object* obj);
bool valid_young_object_p(Object* obj); bool valid_young_object_p(Object* obj);
Expand Down
10 changes: 9 additions & 1 deletion vm/vm.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ namespace rubinius {
: ManagedThread(id, shared, ManagedThread::eRuby) : ManagedThread(id, shared, ManagedThread::eRuby)
, saved_call_frame_(0) , saved_call_frame_(0)
, saved_call_site_information_(0) , saved_call_site_information_(0)
, fiber_stacks_(shared) , fiber_stacks_(this, shared)
, park_(new Park) , park_(new Park)
, run_signals_(false) , run_signals_(false)
, shared(shared) , shared(shared)
Expand Down Expand Up @@ -450,6 +450,14 @@ namespace rubinius {
shared.tool_broker()->at_gc(&ls); shared.tool_broker()->at_gc(&ls);
} }


void VM::gc_fiber_clear_mark() {
fiber_stacks_.gc_clear_mark();
}

void VM::gc_fiber_scan(GarbageCollector* gc, bool only_marked) {
fiber_stacks_.gc_scan(gc, only_marked);
}

void VM::gc_verify(GarbageCollector* gc) { void VM::gc_verify(GarbageCollector* gc) {
if(CallFrame* cf = saved_call_frame()) { if(CallFrame* cf = saved_call_frame()) {
gc->verify_call_frame(cf); gc->verify_call_frame(cf);
Expand Down
10 changes: 10 additions & 0 deletions vm/vm.hpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@ namespace rubinius {
return fiber_stacks_.trampoline(); return fiber_stacks_.trampoline();
} }


FiberData* new_fiber_data(bool root=false) {
return fiber_stacks_.new_data(root);
}

void remove_fiber_data(FiberData* data) {
fiber_stacks_.remove_data(data);
}

VariableRootBuffers& current_root_buffers(); VariableRootBuffers& current_root_buffers();


public: public:
Expand Down Expand Up @@ -434,6 +442,8 @@ namespace rubinius {
void register_kill(STATE); void register_kill(STATE);


void gc_scan(GarbageCollector* gc); void gc_scan(GarbageCollector* gc);
void gc_fiber_clear_mark();
void gc_fiber_scan(GarbageCollector* gc, bool only_marked = true);
void gc_verify(GarbageCollector* gc); void gc_verify(GarbageCollector* gc);
}; };


Expand Down

0 comments on commit b3579cf

Please sign in to comment.