void ObjectMemory::inflate_for_handle(STATE, ObjectHeader* obj, capi::Handle* handle) { utilities::thread::SpinLock::LockGuard guard(inflation_lock_); HeaderWord orig = obj->header; if(orig.f.meaning == eAuxWordInflated) { obj->inflated_header(state)->set_handle(state, handle); return; } uint32_t ih_index = 0; InflatedHeader* ih = inflated_headers_->allocate(obj, &ih_index); ih->update(state, orig); ih->set_handle(state, handle); ih->mark(this, mark_); while(!obj->set_inflated_header(state, ih_index, orig)) { orig = obj->header; if(orig.f.meaning == eAuxWordInflated) { obj->inflated_header(state)->set_handle(state, handle); ih->clear(); return; } ih->update(state, orig); ih->set_handle(state, handle); } }
void ObjectMemory::inflate_for_handle(STATE, ObjectHeader* obj, capi::Handle* handle) { utilities::thread::SpinLock::LockGuard guard(inflation_lock_); HeaderWord orig = obj->header; if(orig.f.inflated) { obj->inflated_header()->set_handle(state, handle); return; } InflatedHeader* header = inflated_headers_->allocate(obj); header->update(state, orig); header->set_handle(state, handle); while(!obj->set_inflated_header(state, header, orig)) { orig = obj->header; if(orig.f.inflated) { obj->inflated_header()->set_handle(state, handle); return; } header->update(state, orig); header->set_handle(state, handle); } }
VALUE NativeMethodFrame::get_handle(STATE, Object* obj) { InflatedHeader* ih = state->om->inflate_header(obj); capi::Handle* handle = ih->handle(); if(handle) { // ref() ONLY if it's not already in there! // otherwise the refcount is wrong and we leak handles. capi::HandleSet::iterator pos = handles_.find(handle); if(pos == handles_.end()) { // We're seeing this object for the first time in this function. // Be sure that it's updated. handle->ref(); handles_.insert(handle); handle->update(NativeMethodEnvironment::get()); } } else { handle = new capi::Handle(state, obj); ih->set_handle(handle); state->shared.global_handles()->add(handle); handle->ref(); handles_.insert(handle); } return handle->as_value(); }
Data* Data::create(STATE, void* data_ptr, Data::MarkFunctor mark, Data::FreeFunctor free) { Data* data; data = state->new_object<Data>(G(data)); // Data is just a heap alias for the handle, so go ahead and create // the handle and populate it as an RData now. InflatedHeader* ih = state->om->inflate_header(data); capi::Handle* handle = ih->handle(); assert(!handle && "can't already have a handle, it's brand new!"); handle = new capi::Handle(state, data); ih->set_handle(handle); // Don't call ->ref() on handle! We don't want the handle to keep the object // alive by default. The handle needs to have the lifetime of the object. state->shared.global_handles()->add(handle); RDataShadow* rdata = reinterpret_cast<RDataShadow*>(handle->as_rdata(0)); rdata->data = data_ptr; rdata->dmark = mark; rdata->dfree = free; // If this Data requires a free function, register this object // as needing finalization. if(free) { state->om->needs_finalization(data, (FinalizerFunction)&Data::finalize); } return data; }
bool ObjectMemory::inflate_for_contention(STATE, ObjectHeader* obj) { utilities::thread::SpinLock::LockGuard guard(inflation_lock_); for(;;) { HeaderWord orig = obj->header; InflatedHeader* ih = 0; uint32_t ih_header = 0; switch(orig.f.meaning) { case eAuxWordEmpty: ih = inflated_headers_->allocate(obj, &ih_header); break; case eAuxWordObjID: // We could be have made a header before trying again, so // keep using the original one. ih = inflated_headers_->allocate(obj, &ih_header); ih->set_object_id(orig.f.aux_word); break; case eAuxWordHandle: ih = inflated_headers_->allocate(obj, &ih_header); ih->set_handle(state, obj->handle(state)); break; case eAuxWordLock: // We have to be locking the object to inflate it, thats the law. if(orig.f.aux_word >> cAuxLockTIDShift != state->vm()->thread_id()) { if(cDebugThreading) { std::cerr << "[LOCK " << state->vm()->thread_id() << " object locked by another thread while inflating for contention]" << std::endl; } return false; } if(cDebugThreading) { std::cerr << "[LOCK " << state->vm()->thread_id() << " being unlocked and inflated atomicly]" << std::endl; } ih = inflated_headers_->allocate(obj, &ih_header); break; case eAuxWordInflated: if(cDebugThreading) { std::cerr << "[LOCK " << state->vm()->thread_id() << " asked to inflated already inflated lock]" << std::endl; } return false; } // Try it all over again if it fails. if(!obj->set_inflated_header(state, ih_header, orig)) { ih->clear(); continue; } obj->clear_lock_contended(); if(cDebugThreading) { std::cerr << "[LOCK " << state->vm()->thread_id() << " inflated lock for contention.]" << std::endl; } // Now inflated but not locked, which is what we want. return true; } }
VALUE NativeMethodFrame::get_handle(STATE, Object* obj) { InflatedHeader* ih = state->om->inflate_header(obj); capi::Handle* handle = ih->handle(); if(handle) { // ref() ONLY if it's not already in there! // otherwise the refcount is wrong and we leak handles. capi::HandleSet::iterator pos = handles_.find(handle); if(pos == handles_.end()) { handle->ref(); handles_.insert(handle); } } else { handle = new capi::Handle(state, obj); ih->set_handle(handle); state->shared.global_handles()->add(handle); handle->ref(); handles_.insert(handle); } return handle->as_value(); }
Handle::~Handle() { InflatedHeader* ih = object_->inflated_header(); assert(ih); ih->set_handle(0); free_data(); invalidate(); }
void ObjectMemory::run_finalizers(STATE, CallFrame* call_frame) { if(running_finalizers_) return; running_finalizers_ = true; for(std::list<FinalizeObject*>::iterator i = to_finalize_.begin(); i != to_finalize_.end(); ) { FinalizeObject* fi = *i; if(fi->finalizer) { (*fi->finalizer)(state, fi->object); // Unhook any handle used by fi->object so that we don't accidentally // try and mark it later (after we've finalized it) if(fi->object->inflated_header_p()) { InflatedHeader* ih = fi->object->inflated_header(); if(capi::Handle* handle = ih->handle()) { handle->forget_object(); ih->set_handle(0); } } // If the object was remembered, unremember it. if(fi->object->remembered_p()) { unremember_object(fi->object); } } else if(fi->ruby_finalizer) { // Rubinius specific code. If the finalizer is Qtrue, then // send the object the finalize message if(fi->ruby_finalizer == Qtrue) { fi->object->send(state, call_frame, state->symbol("__finalize__"), true); } else { Array* ary = Array::create(state, 1); ary->set(state, 0, fi->object->id(state)); OnStack<1> os(state, ary); fi->ruby_finalizer->send(state, call_frame, state->symbol("call"), ary, Qnil, true); } } else { std::cerr << "Unsupported object to be finalized: " << fi->object->to_s(state)->c_str() << "\n"; } fi->status = FinalizeObject::eFinalized; i = to_finalize_.erase(i); } running_finalizers_ = false; }
VALUE NativeMethodFrame::get_handle(STATE, Object* obj) { InflatedHeader* ih = state->memory()->inflate_header(state, obj); capi::Handle* handle = ih->handle(); if(handle) { if(handles_.add_if_absent(handle)) { // We're seeing this object for the first time in this function. // Be sure that it's updated. handle->update(NativeMethodEnvironment::get()); } } else { handle = new capi::Handle(state, obj); ih->set_handle(handle); state->shared().add_global_handle(state, handle); handles_.add_if_absent(handle); } return handle->as_value(); }
void ObjectMemory::inflate_for_handle(STATE, ObjectHeader* obj, capi::Handle* handle) { utilities::thread::SpinLock::LockGuard guard(inflation_lock_); HeaderWord orig = obj->header; if(orig.f.inflated) { rubinius::bug("Massive header state confusion detected. Call a doctor."); } InflatedHeader* header = inflated_headers_->allocate(obj); header->set_handle(state, handle); header->set_object_id(obj->object_id()); if(!obj->set_inflated_header(state, header)) { if(obj->inflated_header_p()) { obj->inflated_header()->set_handle(state, handle); return; } // Now things are really in a weird state, just abort. rubinius::bug("Massive header state confusion detected. Call a doctor."); } }
bool ObjectMemory::inflate_and_lock(STATE, ObjectHeader* obj) { utilities::thread::SpinLock::LockGuard guard(inflation_lock_); InflatedHeader* ih = 0; uint32_t ih_index = 0; int initial_count = 0; HeaderWord orig = obj->header; switch(orig.f.meaning) { case eAuxWordEmpty: // ERROR, we can not be here because it's empty. This is only to // be called when the header is already in use. return false; case eAuxWordObjID: // We could be have made a header before trying again, so // keep using the original one. ih = inflated_headers_->allocate(state, obj, &ih_index); ih->set_object_id(orig.f.aux_word); break; case eAuxWordLock: // We have to locking the object to inflate it, thats the law. if(orig.f.aux_word >> cAuxLockTIDShift != state->vm()->thread_id()) { return false; } ih = inflated_headers_->allocate(state, obj, &ih_index); initial_count = orig.f.aux_word & cAuxLockRecCountMask; break; case eAuxWordHandle: // Handle in use so inflate and update handle ih = inflated_headers_->allocate(state, obj, &ih_index); ih->set_handle(state, obj->handle(state)); break; case eAuxWordInflated: // Already inflated. ERROR, let the caller sort it out. if(cDebugThreading) { std::cerr << "[LOCK " << state->vm()->thread_id() << " asked to inflated already inflated lock]" << std::endl; } return false; } ih->initialize_mutex(state->vm()->thread_id(), initial_count); ih->mark(this, mark_); while(!obj->set_inflated_header(state, ih_index, orig)) { // The header can't have been inflated by another thread, the // inflation process holds the OM lock. // // So some other bits must have changed, so lets just spin and // keep trying to update it. // Sanity check that the meaning is still the same, if not, then // something is really wrong. if(orig.f.meaning != obj->header.f.meaning) { if(cDebugThreading) { std::cerr << "[LOCK object header consistence error detected.]" << std::endl; } return false; } orig = obj->header; if(orig.f.meaning == eAuxWordInflated) { return false; } } return true; }