// Called after a fork(), when we know we're alone again, to get // everything back in the proper order. void reinit() { mutex_.init(); waiting_to_stop_.init(); waiting_to_run_.init(); pending_threads_ = 1; should_stop_ = false; }
void wait_to_run() { pending_threads_--; waiting_to_stop_.signal(); while(should_stop_) { waiting_to_run_.wait(mutex_); } pending_threads_++; }
void restart() { mutex_.init(); condition_.init(); pause_condition_.init(); state = cUnknown; stop_ = false; pause_ = false; paused_ = false; run(); }
void become_dependent(THREAD) { thread::Mutex::LockGuard guard(mutex_); switch(state->run_state()) { case ManagedThread::eAlone: // Running alone, ignore. return; case ManagedThread::eRunning: // Ignore this, a running thread is already dependent. return; case ManagedThread::eSuspended: // Again, bad, don't allow this. rubinius::bug("Trying to make a suspended thread dependent"); break; case ManagedThread::eIndependent: // If the GC is running, wait here... while(should_stop_) { waiting_to_run_.wait(mutex_); } // Ok, we're running again. state->run_state_ = ManagedThread::eRunning; pending_threads_++; } }
void stop() { { thread::Mutex::LockGuard guard(mutex_); stop_ = true; if(state == cIdle) { condition_.signal(); } else if(state == cPaused) { // TODO refactor common from unpause pause_ = false; condition_.signal(); } } join(); }
void wait_til_alone(THREAD) { thread::Mutex::LockGuard guard(mutex_); should_stop_ = true; if(cDebugThreading) { std::cerr << "[" << VM::current() << " WORLD waiting until alone]\n"; } if(state->run_state_ != ManagedThread::eRunning) { rubinius::bug("A non-running thread is trying to wait till alone"); } // For ourself.. pending_threads_--; timer::Running<> timer(time_waiting_); while(pending_threads_ > 0) { if(cDebugThreading) { std::cerr << "[" << VM::current() << " WORLD waiting on condvar: " << pending_threads_ << "]\n"; } waiting_to_stop_.wait(mutex_); } state->run_state_ = ManagedThread::eAlone; if(cDebugThreading) { std::cerr << "[" << VM::current() << " WORLD o/~ I think we're alone now.. o/~]\n"; } }
void unpark() { thread::Mutex::LockGuard lg(mutex_); if(!sleeping_) return; wake_ = true; cond_.signal(); }
void become_dependent() { thread::Mutex::LockGuard guard(mutex_); // If the GC is running, wait here... while(should_stop_) { waiting_to_run_.wait(mutex_); } pending_threads_++; }
void wake_all_waiters() { thread::Mutex::LockGuard guard(mutex_); should_stop_ = false; // For ourself.. pending_threads_++; waiting_to_run_.broadcast(); }
void unpause() { thread::Mutex::LockGuard guard(mutex_); // idle, just waiting for more work, ok, thats fine. if(state != cPaused) return; pause_ = false; condition_.signal(); }
void pause() { thread::Mutex::LockGuard guard(mutex_); // it's idle, ie paused. if(state == cIdle || state == cPaused) return; pause_ = true; while(!paused_) { pause_condition_.wait(mutex_); } }
void wait_til_alone() { thread::Mutex::LockGuard guard(mutex_); should_stop_ = true; // For ourself.. pending_threads_--; timer::Running timer(time_waiting_); while(pending_threads_ > 0) { waiting_to_stop_.wait(mutex_); } }
void wait_to_run(THREAD) { if(cDebugThreading) { std::cerr << "[" << VM::current() << " WORLD stopping, waiting to be restarted]\n"; } if(state->run_state_ != ManagedThread::eRunning) { rubinius::bug("Suspending a non running thread!"); } state->run_state_ = ManagedThread::eSuspended; pending_threads_--; waiting_to_stop_.signal(); while(should_stop_) { waiting_to_run_.wait(mutex_); } pending_threads_++; state->run_state_ = ManagedThread::eRunning; if(cDebugThreading) { std::cerr << "[" << VM::current() << " WORLD restarted]\n"; } }
void wake_all_waiters(THREAD) { thread::Mutex::LockGuard guard(mutex_); should_stop_ = false; if(cDebugThreading) { std::cerr << "[" << VM::current() << " WORLD waking all threads]\n"; } if(state->run_state_ != ManagedThread::eAlone) { rubinius::bug("A non-alone thread is trying to wake all"); } // For ourself.. pending_threads_++; waiting_to_run_.broadcast(); state->run_state_ = ManagedThread::eRunning; }
virtual void perform() { for(;;) { // forever BackgroundCompileRequest* req = 0; // Lock, wait, get a request, unlock { thread::Mutex::LockGuard guard(mutex_); if(pause_) { state = cPaused; paused_ = true; pause_condition_.signal(); while(pause_) { condition_.wait(mutex_); } state = cUnknown; paused_ = false; } // If we've been asked to stop, do so now. if(stop_) return; while(pending_requests_.size() == 0) { state = cIdle; // unlock and wait... condition_.wait(mutex_); if(stop_) return; } // now locked again, shift a request req = pending_requests_.front(); pending_requests_.pop_front(); state = cRunning; } // mutex now unlock, allowing others to push more requests // LLVMCompiler* jit = new LLVMCompiler(); { timer::Running timer(ls_->time_spent); jit->compile(ls_, req->vmmethod(), req->is_block()); jit->generate_function(ls_); } if(show_machine_code_) { jit->show_machine_code(); } // Ok, compiled, generated machine code, now update MachineMethod // Ok, now we are manipulating managed memory, so make // sure the GC doesn't run. ls_->shared().gc_dependent(); req->vmmethod()->set_jitted(jit->llvm_function(), jit->code_bytes(), jit->function_pointer()); if(req->is_block()) { BlockEnvironment* be = req->block_env(); if(!be) { llvm::outs() << "Fatal error in JIT. Expected a BlockEnvironment.\n"; } else { be->set_native_function(jit->function_pointer()); } } else { MachineMethod* mm = req->machine_method(); if(!mm) { llvm::outs() << "Fatal error in JIT. Expected a MachineMethod.\n"; } else { mm->update(req->vmmethod(), jit); mm->activate(); } } int which = ls_->add_jitted_method(); if(ls_->config().jit_show_compiling) { llvm::outs() << "[[[ JIT finished background compiling " << which << (req->is_block() ? " (block)" : " (method)") << " ]]]\n"; } delete req; // We don't depend on the GC here, so let it run independent // of us. ls_->shared().gc_independent(); } }
void add(BackgroundCompileRequest* req) { thread::Mutex::LockGuard guard(mutex_); pending_requests_.push_back(req); condition_.signal(); }
virtual void perform() { set_name("rbx.jit"); ManagedThread::set_current(ls_); #ifndef RBX_WINDOWS sigset_t set; sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); #endif for(;;) { // forever BackgroundCompileRequest* req = 0; // Lock, wait, get a request, unlock { thread::Mutex::LockGuard guard(mutex_); if(pause_) { state = cPaused; paused_ = true; pause_condition_.broadcast(); while(pause_) { condition_.wait(mutex_); } state = cUnknown; paused_ = false; } // If we've been asked to stop, do so now. if(stop_) return; while(pending_requests_.empty()) { state = cIdle; // unlock and wait... condition_.wait(mutex_); if(stop_) return; } // now locked again, shift a request req = pending_requests_.front(); state = cRunning; } // This isn't ideal, but it's the safest. Keep the GC from // running while we're building the IR. ls_->shared().gc_dependent(ls_); // mutex now unlock, allowing others to push more requests // current_req_ = req; jit::Compiler jit(ls_); current_compiler_ = &jit; int spec_id = 0; if(Class* cls = req->receiver_class()) { spec_id = cls->class_id(); } void* func = 0; { timer::Running<1000000> timer(ls_->shared().stats.jit_time_spent); jit.compile(ls_, req); func = jit.generate_function(ls_); } // We were unable to compile this function, likely // because it's got something we don't support. if(!func) { if(ls_->config().jit_show_compiling) { llvm::outs() << "[[[ JIT error in background compiling ]]]\n"; } // If someone was waiting on this, wake them up. if(thread::Condition* cond = req->waiter()) { cond->signal(); } current_req_ = 0; current_compiler_ = 0; pending_requests_.pop_front(); delete req; // We don't depend on the GC here, so let it run independent // of us. ls_->shared().gc_independent(ls_); continue; } if(show_machine_code_) { jit.show_machine_code(); } // If the method has had jit'ing request disabled since we started // JIT'ing it, discard our work. if(!req->vmmethod()->jit_disabled()) { jit::RuntimeDataHolder* rd = jit.context().runtime_data_holder(); ls_->start_method_update(); if(!req->is_block()) { if(spec_id) { req->method()->add_specialized(spec_id, reinterpret_cast<executor>(func), rd); } else { req->method()->set_unspecialized(reinterpret_cast<executor>(func), rd); } } else { req->method()->set_unspecialized(reinterpret_cast<executor>(func), rd); } assert(req->method()->jit_data()); ls_->end_method_update(); rd->run_write_barrier(ls_->write_barrier(), req->method()); ls_->shared().stats.jitted_methods++; if(ls_->config().jit_show_compiling) { llvm::outs() << "[[[ JIT finished background compiling " << (req->is_block() ? " (block)" : " (method)") << " ]]]\n"; } } // If someone was waiting on this, wake them up. if(thread::Condition* cond = req->waiter()) { cond->signal(); } current_req_ = 0; current_compiler_ = 0; pending_requests_.pop_front(); delete req; // We don't depend on the GC here, so let it run independent // of us. ls_->shared().gc_independent(ls_); } }
virtual void perform() { sigset_t set; sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); for(;;) { // forever BackgroundCompileRequest* req = 0; // Lock, wait, get a request, unlock { thread::Mutex::LockGuard guard(mutex_); if(pause_) { state = cPaused; paused_ = true; pause_condition_.signal(); while(pause_) { condition_.wait(mutex_); } state = cUnknown; paused_ = false; } // If we've been asked to stop, do so now. if(stop_) return; while(pending_requests_.size() == 0) { state = cIdle; // unlock and wait... condition_.wait(mutex_); if(stop_) return; } // now locked again, shift a request req = pending_requests_.front(); pending_requests_.pop_front(); state = cRunning; } // This isn't ideal, but it's the safest. Keep the GC from // running while we're building the IR. ls_->shared().gc_dependent(); // mutex now unlock, allowing others to push more requests // jit::Compiler jit; void* func = 0; { timer::Running<size_t, 1000000> timer(ls_->shared().stats.jit_time_spent); if(req->is_block()) { jit.compile_block(ls_, req->method(), req->vmmethod()); } else { jit.compile_method(ls_, req->method(), req->vmmethod()); } func = jit.generate_function(ls_); } // We were unable to compile this function, likely // because it's got something we don't support. if(!func) { if(ls_->config().jit_show_compiling) { llvm::outs() << "[[[ JIT error in background compiling ]]]\n"; } // If someone was waiting on this, wake them up. if(thread::Condition* cond = req->waiter()) { cond->signal(); } delete req; // We don't depend on the GC here, so let it run independent // of us. ls_->shared().gc_independent(); continue; } if(show_machine_code_) { jit.show_machine_code(); } req->vmmethod()->set_jitted(jit.llvm_function(), jit.code_bytes(), func); if(!req->is_block()) { req->method()->execute = reinterpret_cast<executor>(func); } assert(req->method()->jit_data()); req->method()->jit_data()->run_write_barrier(ls_->write_barrier(), req->method()); ls_->shared().stats.jitted_methods++; if(ls_->config().jit_show_compiling) { llvm::outs() << "[[[ JIT finished background compiling " << (req->is_block() ? " (block)" : " (method)") << " ]]]\n"; } // If someone was waiting on this, wake them up. if(thread::Condition* cond = req->waiter()) { cond->signal(); } delete req; // We don't depend on the GC here, so let it run independent // of us. ls_->shared().gc_independent(); } }