inline std::pair<T, bool> try_dequeue_in_critical_section() { T elem = T(); // Wait while the queue is empty and this queue is alive if (m_queue.empty() || m_alive == false) { return std::make_pair(elem, false); } else { elem = m_queue.front(); m_queue.pop_front(); if (m_queue.empty() && sleeping_on_empty) { m_empty_conditional.signal(); } return std::make_pair(elem, true); } }
void log_non_empty_queue(char const* const desc, queue_type& queue) { mutex_type::scoped_lock l(mtx_); while (!queue.empty()) { threads::thread_id_type id = queue.front().id_; queue.front().id_ = 0; queue.pop_front(); // we know that the id is actually the pointer to the thread threads::thread_data* thrd = reinterpret_cast<threads::thread_data*>(id); LERR_(info) << "~full_empty_entry: aborting pending thread in " << desc << ": " << get_thread_state_name(thrd->get_state()) << "(" << id << "): " << thrd->get_description(); // forcefully abort thread, do not throw error_code ec(lightweight); threads::set_thread_state(id, threads::pending, threads::wait_abort, threads::thread_priority_normal, ec); if (ec) { LERR_(error) << "~full_empty_entry: could not abort thread" << get_thread_state_name(thrd->get_state()) << "(" << id << "): " << thrd->get_description(); } } }
//! Dequeues log record from the queue, blocks if no log records are ready to be processed bool dequeue_ready(record_view& rec) { unique_lock< mutex_type > lock(m_mutex); while (!m_interruption_requested) { if (!m_queue.empty()) { const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); enqueued_record const& elem = m_queue.top(); const uint64_t difference = (now - elem.m_timestamp).milliseconds(); if (difference >= m_ordering_window) { // We got a new element rec = elem.m_record; m_queue.pop(); return true; } else { // Wait until the element becomes ready to be processed m_cond.timed_wait(lock, posix_time::milliseconds(m_ordering_window - difference)); } } else { // Wait for an element to come m_cond.wait(lock); } } m_interruption_requested = false; return false; }
//! Enqueues a log record void enqueue_unlocked(record_view const& rec) { const bool was_empty = m_queue.empty(); m_queue.push(enqueued_record(rec)); if (was_empty) m_cond.notify_one(); }
void swap(queue_type &q) { m_mutex.lock(); q.swap(m_queue); if (m_queue.empty() && sleeping_on_empty) { m_empty_conditional.signal(); } m_mutex.unlock(); }
boost::optional<T> pop(unsigned int timeout = 5) { boost::unique_lock<boost::shared_mutex> lock(mutex_, boost::get_system_time() + boost::posix_time::seconds(timeout)); if (!lock || queue_.empty()) return boost::optional<T>(); boost::optional<T> ret = queue_.front(); queue_.pop(); return ret; }
/** * Returns an element if the queue has an entry. * returns [item, false] otherwise. */ inline std::pair<T, bool> try_dequeue() { if (m_queue.empty() || m_alive == false) return std::make_pair(T(), false); m_mutex.lock(); T elem = T(); // Wait while the queue is empty and this queue is alive if (m_queue.empty() || m_alive == false) { m_mutex.unlock(); return std::make_pair(elem, false); } else { elem = m_queue.front(); m_queue.pop_front(); } m_mutex.unlock(); return std::make_pair(elem, true); }
inline bool wait_for_data() { m_mutex.lock(); bool success = false; // Wait while the queue is empty and this queue is alive while(m_queue.empty() && m_alive) { sleeping++; fiber_sleep(); sleeping--; } // An element has been added or a signal was raised if(!m_queue.empty()) { success = true; } m_mutex.unlock(); return success; }
/// Returns immediately of queue size is >= immedeiate_size /// Otherwise, it will poll over 'ns' nanoseconds or on a signal /// until queue is not empty. inline bool try_timed_wait_for_data(size_t ns, size_t immediate_size) { m_mutex.lock(); bool success = false; // Wait while the queue is empty and this queue is alive if (m_queue.size() < immediate_size) { if (m_queue.empty() && m_alive) { sleeping++; m_conditional.timedwait_ns(m_mutex, ns); sleeping--; } } // An element has been added or a signal was raised if(!m_queue.empty()) { success = true; } m_mutex.unlock(); return success; }
/** * Blocks until an element is available in the queue * or until stop_blocking() is called. * The return value is a pair of <T value, bool success> * If "success" if set, then "value" is valid and * is an element popped from the queue. * If "success" is false, stop_blocking() was called * and the queue has been destroyed. */ inline std::pair<T, bool> dequeue() { m_mutex.lock(); T elem = T(); bool success = false; // Wait while the queue is empty and this queue is alive while(m_queue.empty() && m_alive) { sleeping++; fiber_sleep(); sleeping--; } // An element has been added or a signal was raised if(!m_queue.empty()) { success = true; elem = m_queue.front(); m_queue.pop_front(); } m_mutex.unlock(); return std::make_pair(elem, success); }
//! Equality operator. bool operator==(const iterator& it)const { if (m_queue.size() != it.m_queue.size()) { // if the queue size is different return false; // the state of the to iterator are different } if (m_queue.empty()) { // if the queue is empty, we have to check if they are valid and return it.m_valid == m_valid and it.m_cst == m_cst; // belong to the same cst } return (it.m_valid == m_valid) // valid status is equal => for end() iterator and (it.m_cst == m_cst) // iterator belongs to the same cst and (it.m_queue.front() == m_queue.front()) // front element and and (it.m_queue.back() == m_queue.back()); // back element are the same. }
//! Attempts to dequeue log record from the queue, does not block. bool try_dequeue(record_view& rec) { lock_guard< mutex_type > lock(m_mutex); if (!m_queue.empty()) { enqueued_record const& elem = m_queue.top(); rec = elem.m_record; m_queue.pop(); return true; } return false; }
/** * The conceptual "reverse" of dequeue(). * This function will block until the queue becomes empty, or * until stop_blocking() is called. * Returns true on success. * Returns false if the queue is no longer alive */ bool wait_until_empty() { m_mutex.lock(); // if the queue still has elements in it while I am still alive, wait while (m_queue.empty() == false && m_alive == true) { sleeping_on_empty++; m_empty_conditional.wait(m_mutex); sleeping_on_empty--; } m_mutex.unlock(); // if I am alive, the queue must be empty. i.e. success // otherwise I am dead return m_alive; }
inline std::pair<T, bool> dequeue_and_begin_critical_section_on_success() { m_mutex.lock(); T elem = T(); bool success = false; // Wait while the queue is empty and this queue is alive while(m_queue.empty() && m_alive) { sleeping++; m_conditional.wait(m_mutex); sleeping--; } // An element has been added or a signal was raised if(!m_queue.empty()) { success = true; elem = m_queue.front(); m_queue.pop_front(); if (m_queue.empty() && sleeping_on_empty) { m_empty_conditional.signal(); } } if (!success) m_mutex.unlock(); return std::make_pair(elem, success); }
void test_pop() { size_t num = 10, count = 0; fill(num); while (!m_queue.empty()) m_queue.pop(); ASSERT_EQ(0, m_queue.size()); for (auto i : m_queue) count++; ASSERT_EQ(0, count); clear(); }
//! Prefix increment of the iterator. iterator& operator++() { if (!m_valid) return *this; if (m_queue.empty()) { m_valid = false; return *this; } value_type v = m_queue.front(); m_queue.pop(); value_type child = m_cst->select_child(v, 1); while (m_cst->root() != child) { m_queue.push(child); child = m_cst->sibling(child); } return *this; }
void process_queue(const Handler& h, const boost::system::error_code& ec, std::chrono::milliseconds repeat, int repeat_count) { // Process up to m_batch_size items waiting on the queue. // For each dequeued item call m_wait_handler int i = 0; // Number of handler invocations T value; while (i < m_batch_size && m_queue.pop(value)) { i++; repeat_count = dec_repeat_count(repeat_count); if (!h(value, boost::system::error_code())) return; } static const auto s_timeout = boost::system::errc::make_error_code(boost::system::errc::timed_out); auto pthis = this->shared_from_this(); // If we reached the batch size and queue has more data // to process - give up the time slice and reschedule the handler if (i == m_batch_size && !m_queue.empty()) { m_io.post([pthis, h, repeat, repeat_count]() { (*pthis)(h, boost::asio::error::operation_aborted, repeat, repeat_count); }); return; } else if (!i && !h(value, s_timeout)) { // If we haven't processed any data and the timer was canceled. // Invoke the callback to see if we need to remove the handler. return; } int n = dec_repeat_count(repeat_count); // If requested repeated timer, schedule new timer invocation if (repeat > std::chrono::milliseconds(0) && n > 0) { m_timer.cancel(); m_timer.expires_from_now(repeat); m_timer.async_wait( [pthis, h, repeat, n] (const boost::system::error_code& ec) { (*pthis)(h, ec, repeat, n); }); } }
//! Attempts to dequeue a log record ready for processing from the queue, does not block if no log records are ready to be processed bool try_dequeue_ready(record_view& rec) { lock_guard< mutex_type > lock(m_mutex); if (!m_queue.empty()) { const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); enqueued_record const& elem = m_queue.top(); if (static_cast< uint64_t >((now - elem.m_timestamp).milliseconds()) >= m_ordering_window) { // We got a new element rec = elem.m_record; m_queue.pop(); return true; } } return false; }
bool empty_unsafe() { return m_queue.empty(); }
static inline void finish (bool output_fired, bd_t bda, bd_t bdb) { if (action_.automaton.get () != 0) { // We were executing an action of this automaton. switch (action_.action->type) { case INPUT: // We were executing an input. Move to the next input. ++input_action_pos_; proceed_to_input (); // -EEE input_action_list_.front ()->output_action.automaton->unlock_execution (); finish_output (); break; case OUTPUT: // We were executing an output ... if (output_fired) { // ... and the output output did something. output_buffer_a_ = action_.automaton->lookup_buffer (bda); // Synchronize the buffers. if (output_buffer_a_.get () != 0) { output_buffer_a_->sync (0, output_buffer_a_->size ()); } output_buffer_b_ = action_.automaton->lookup_buffer (bdb); if (output_buffer_b_.get () != 0) { output_buffer_b_->sync (0, output_buffer_b_->size ()); } // Proceed to execute the inputs. input_action_pos_ = input_action_list_.begin (); // This does not return if there are inputs. proceed_to_input (); } // No input actions to execute. // -EEE action_.automaton->unlock_execution (); finish_output (); break; case INTERNAL: case SYSTEM: // -EEE action_.automaton->unlock_execution (); break; } } // We are done with the current action. action_.automaton = shared_ptr<automaton> (); for (;;) { irq_handler::process_interrupts (); while (!ready_queue_.empty ()) { // Get the automaton context and remove it from the ready queue. automaton_context* c = ready_queue_.front (); ready_queue_.pop_front (); // Load the action. action_ = c->front (); c->pop_front (); // The automaton exists. Continue loading and execute. switch (action_.action->type) { case INPUT: // Error. Not a local action. kpanic ("Non-local action on execution queue"); break; case OUTPUT: { kassert (input_action_list_.empty ()); // Copy the bindings. action_.automaton->copy_bound_inputs (action_, back_inserter (input_action_list_)); // Sort the bindings by input automaton. sort (input_action_list_.begin (), input_action_list_.end (), sort_bindings_by_input ()); // We lock the automata in order. This is called Havender's Principle. bool output_locked = false; for (input_action_list_type::const_iterator pos = input_action_list_.begin (); pos != input_action_list_.end (); ++pos) { shared_ptr<automaton> input_automaton = (*pos)->input_action.automaton; if (!output_locked && action_.automaton->aid () < input_automaton->aid ()) { // +EEE action_.automaton->lock_execution (); output_locked = true; } // +FFF input_automaton->lock_execution (); } if (!output_locked) { // +EEE action_.automaton->lock_execution (); output_locked = true; } input_action_pos_ = input_action_list_.begin (); } break; case INTERNAL: case SYSTEM: // +EEE action_.automaton->lock_execution (); break; } if (!c->empty ()) { // Automaton has more actions, return to ready queue. ready_queue_.push_back (c); } action_.automaton->execute (*action_.action, action_.parameter, output_buffer_a_, output_buffer_b_); } // Out of actions. action_.automaton = shared_ptr<automaton> (); irq_handler::wait_for_interrupt (); } }
/// Check if there is any data in the outgoing_queue to be sent over the socket bool outgoing_not_empty() const { return !m_outgoing_queue.empty(); }
/// Check if there is any data in the incoming_queue bool incoming_not_empty() const { return !m_incoming_queue.empty(); }
bool empty_() const { return queue_.empty(); }
//! Returns true if the queue is empty inline bool empty() { m_mutex.lock(); bool res = m_queue.empty(); m_mutex.unlock(); return res; }
bool empty(unsigned int timeout = 5) { boost::shared_lock<boost::shared_mutex> lock(mutex_, boost::get_system_time() + boost::posix_time::seconds(timeout)); if (!lock.owns_lock()) return false; return queue_.empty(); }
std::size_t size(unsigned int timeout = 5) { boost::shared_lock<boost::shared_mutex> lock(mutex_, boost::get_system_time() + boost::posix_time::seconds(timeout)); if (!lock || queue_.empty()) return 0; return queue_.size(); }