void FinalizerHandler::perform(STATE) { GCTokenImpl gct; utilities::thread::Thread::set_os_name("rbx.finalizer"); state->vm()->thread->hard_unlock(state, gct); while(!exit_) { if(!process_list_) first_process_item(); if(!process_list_) { utilities::thread::Mutex::LockGuard lg(worker_lock_); if(finishing_) supervisor_signal(); // exit_ might have been set in the mean while after // we grabbed the worker_lock if(!exit_) { GCIndependent indy(state); worker_wait(); } continue; } finalize(state); next_process_item(); } }
void FinalizerHandler::finish(STATE, GCToken gct) { if(!self_) { if(process_list_ || !lists_->empty() || !live_list_->empty()) { rubinius::bug("FinalizerHandler worker thread dead during halt"); } else { return; } } finishing_ = true; while(true) { { StopTheWorld stw(state, gct, 0); if(!process_list_) { if(live_list_->empty() && lists_->empty()) break; // Everything is garbage when halting so keep adding live objects to // finalize queue until done. if(!live_list_->empty()) { for(FinalizeObjects::iterator i = live_list_->begin(); i != live_list_->end(); ++i) { i->queued(); } queue_objects(); } first_process_item(); if(!process_list_) break; } } worker_signal(); { utilities::thread::Mutex::LockGuard lg(supervisor_lock_); state->vm()->set_call_frame(0); GCIndependent indy(state); if(process_list_) supervisor_wait(); } } if(!lists_->empty() || !live_list_->empty() || process_list_ != NULL) rubinius::bug("FinalizerHandler exiting with pending finalizers"); stop_thread(state); }
void SignalHandler::perform(STATE) { #ifndef RBX_WINDOWS sigset_t set; sigfillset(&set); pthread_sigmask(SIG_BLOCK, &set, NULL); #endif GCTokenImpl gct; utilities::thread::Thread::set_os_name("rbx.signal-dispatch"); state->vm()->thread->hard_unlock(state, gct); for(;;) { fd_set fds; FD_ZERO(&fds); FD_SET((int_fd_t)read_fd_, &fds); int n; { GCIndependent indy(state, 0); n = select(read_fd_ + 1, &fds, NULL, NULL, NULL); } if(n == 1) { // drain a bunch char buf[512]; if(read(read_fd_, buf, sizeof(buf)) < 0) { perror("SignalHandler::perform failed to read"); } if(exit_) { self_ = 0; return; } { target_->check_local_interrupts = true; target_->wakeup(state, gct); } } } }
void ObjectMemory::in_finalizer_thread(STATE) { CallFrame* call_frame = 0; utilities::thread::Thread::set_os_name("rbx.finalizer"); GCTokenImpl gct; state->vm()->thread->hard_unlock(state, gct); // Forever for(;;) { FinalizeObject* fi; // Take the lock, remove the first one from the list, // then process it. { SCOPE_LOCK(state->vm(), finalizer_lock_); state->vm()->set_call_frame(0); while(to_finalize_.empty()) { GCIndependent indy(state); finalizer_var_.wait(finalizer_lock_); } fi = to_finalize_.front(); to_finalize_.pop_front(); } 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(capi::Handle* handle = fi->object->handle(state)) { handle->forget_object(); fi->object->clear_handle(state); } // 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 cTrue, then // send the object the finalize message if(fi->ruby_finalizer == cTrue) { fi->object->send(state, call_frame, state->symbol("__finalize__")); } 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, G(sym_call), ary); } } else { std::cerr << "Unsupported object to be finalized: " << fi->object->to_s(state)->c_str(state) << std::endl; } fi->status = FinalizeObject::eFinalized; } state->checkpoint(gct, 0); }