std::cv_status s4u::ConditionVariable::wait_for(std::unique_lock<Mutex>& lock, double timeout) { try { simcall_cond_wait_timeout(cond_, lock.mutex()->mutex_, timeout); return std::cv_status::timeout; } catch (xbt_ex& e) { // If the exception was a timeout, we have to take the lock again: if (e.category == timeout_error) { try { lock.mutex()->lock(); return std::cv_status::timeout; } catch (...) { std::terminate(); } } // Another exception: should we reaquire the lock? std::terminate(); } catch (...) { std::terminate(); } }
virtual void erase (std::unique_lock <std::mutex>& guard, std::shared_ptr <Resource> resource) noexcept { assert (guard.mutex () == &m_mutex); resource_iterator ii = m_resources.find (resource->getId ()); if (ii != resource_end ()) m_resources.erase (ii); }
void Solver::proceed(std::unique_lock<std::mutex>& lock) { assert(lock.mutex() == &workerMutex && lock.owns_lock()); wakeMainThreadRequested = true; wakeMainThread.notify_one(); wakeWorkerThread.wait(lock, [&]() { return wakeWorkerThreadRequested; }); wakeWorkerThreadRequested = false; }
void FunctionScheduler::addFunctionToHeap( const std::unique_lock<std::mutex>& lock, RepeatFunc&& func) { // This function should only be called with mutex_ already locked. DCHECK(lock.mutex() == &mutex_); DCHECK(lock.owns_lock()); functions_.emplace_back(std::move(func)); if (running_) { functions_.back().resetNextRunTime(steady_clock::now()); std::push_heap(functions_.begin(), functions_.end(), fnCmp_); // Signal the running thread to wake up and see if it needs to change // its current scheduling decision. runningCondvar_.notify_one(); } }
void signal(std::unique_lock<mutex_type> l, std::int64_t count) { HPX_ASSERT_OWNS_LOCK(l); mutex_type* mtx = l.mutex(); // release no more threads than we get resources value_ += count; for (std::int64_t i = 0; value_ >= 0 && i < count; ++i) { // notify_one() returns false if no more threads are // waiting if (!cond_.notify_one(std::move(l))) break; l = std::unique_lock<mutex_type>(*mtx); } }
void FunctionScheduler::cancelFunction(const std::unique_lock<std::mutex>& l, FunctionHeap::iterator it) { // This function should only be called with mutex_ already locked. DCHECK(l.mutex() == &mutex_); DCHECK(l.owns_lock()); if (running_) { // Internally gcc has an __adjust_heap() function to fill in a hole in the // heap. Unfortunately it isn't part of the standard API. // // For now we just leave the RepeatFunc in our heap, but mark it as unused. // When its nextTimeInterval comes up, the runner thread will pop it from // the heap and simply throw it away. it->cancel(); } else { // We're not running, so functions_ doesn't need to be maintained in heap // order. functions_.erase(it); } }
resource_iterator erase (std::unique_lock <std::mutex>& guard, resource_iterator ii) noexcept { assert (guard.mutex () == &m_mutex); return m_resources.erase (ii); }
virtual void insert (std::unique_lock <std::mutex>& guard, std::shared_ptr <Resource> resource) noexcept { assert (guard.mutex () == &m_mutex); m_resources.insert (std::make_pair (resource->getId (), resource)); }
void FunctionScheduler::runOneFunction(std::unique_lock<std::mutex>& lock, steady_clock::time_point now) { DCHECK(lock.mutex() == &mutex_); DCHECK(lock.owns_lock()); // The function to run will be at the end of functions_ already. // // Fully remove it from functions_ now. // We need to release mutex_ while we invoke this function, and we need to // maintain the heap property on functions_ while mutex_ is unlocked. RepeatFunc func(std::move(functions_.back())); functions_.pop_back(); if (!func.cb) { VLOG(5) << func.name << "function has been canceled while waiting"; return; } currentFunction_ = &func; // Update the function's next run time. if (steady_) { // This allows scheduler to catch up func.setNextRunTimeSteady(); } else { // Note that we set nextRunTime based on the current time where we started // the function call, rather than the time when the function finishes. // This ensures that we call the function once every time interval, as // opposed to waiting time interval seconds between calls. (These can be // different if the function takes a significant amount of time to run.) func.setNextRunTimeStrict(now); } // Release the lock while we invoke the user's function lock.unlock(); // Invoke the function try { VLOG(5) << "Now running " << func.name; func.cb(); } catch (const std::exception& ex) { LOG(ERROR) << "Error running the scheduled function <" << func.name << ">: " << exceptionStr(ex); } // Re-acquire the lock lock.lock(); if (!currentFunction_) { // The function was cancelled while we were running it. // We shouldn't reschedule it; return; } // Clear currentFunction_ CHECK_EQ(currentFunction_, &func); currentFunction_ = nullptr; // Re-insert the function into our functions_ heap. // We only maintain the heap property while running_ is set. (running_ may // have been cleared while we were invoking the user's function.) functions_.push_back(std::move(func)); if (running_) { std::push_heap(functions_.begin(), functions_.end(), fnCmp_); } }
/** * Wait functions */ void s4u::ConditionVariable::wait(std::unique_lock<Mutex>& lock) { simcall_cond_wait(cond_, lock.mutex()->mutex_); }