// atomically sets stack_ back and enqueues all elements to the cache bool fetch_new_data(pointer end_ptr) { CAF_ASSERT(end_ptr == nullptr || end_ptr == stack_empty_dummy()); pointer e = stack_.load(); // must not be called on a closed queue CAF_ASSERT(e != nullptr); // fetching data while blocked is an error CAF_ASSERT(e != reader_blocked_dummy()); // it's enough to check this once, since only the owner is allowed // to close the queue and only the owner is allowed to call this // member function while (e != end_ptr) { if (stack_.compare_exchange_weak(e, end_ptr)) { // fetching data while blocked is an error CAF_ASSERT(e != reader_blocked_dummy()); if (is_dummy(e)) { // only use-case for this is closing a queue CAF_ASSERT(end_ptr == nullptr); return false; } while (e) { CAF_ASSERT(! is_dummy(e)); auto next = e->next; e->next = head_; head_ = e; e = next; } return true; } // next iteration } return false; }
/// Tries to set this queue from state `empty` to state `blocked`. bool try_block() { auto e = stack_empty_dummy(); bool res = stack_.compare_exchange_strong(e, reader_blocked_dummy()); CAF_ASSERT(e != nullptr); // return true in case queue was already blocked return res || e == reader_blocked_dummy(); }
// returns true if the queue was empty enqueue_result enqueue(pointer new_element) { pointer e = m_stack.load(); for (;;) { if (!e) { // if tail is nullptr, the queue has been closed m_delete(new_element); return enqueue_result::queue_closed; } new_element->next = is_dummy(e) ? nullptr : e; if (m_stack.compare_exchange_weak(e, new_element)) { return (e == reader_blocked_dummy()) ? enqueue_result::unblocked_reader : enqueue_result::success; } } }
/// Tries to enqueue a new element to the mailbox. /// @warning Call only from the reader (owner). enqueue_result enqueue(pointer new_element) { CAF_ASSERT(new_element != nullptr); pointer e = stack_.load(); for (;;) { if (! e) { // if tail is nullptr, the queue has been closed delete_(new_element); return enqueue_result::queue_closed; } // a dummy is never part of a non-empty list new_element->next = is_dummy(e) ? nullptr : e; if (stack_.compare_exchange_strong(e, new_element)) { return (e == reader_blocked_dummy()) ? enqueue_result::unblocked_reader : enqueue_result::success; } // continue with new value of e } }
inline bool is_dummy(pointer ptr) { return ptr == stack_empty_dummy() || ptr == reader_blocked_dummy(); }
/** * @brief Tries to set this queue from state @p blocked to state @p empty. * @returns @p true if the state change was successful, otherwise @p false. * @note This function does never fail spuriously. */ inline bool try_unblock() { auto e = reader_blocked_dummy(); return m_stack.compare_exchange_strong(e, stack_empty_dummy()); }
/** * @brief Tries to set this queue from state @p empty to state @p blocked. * @returns @p true if the state change was successful or if the mailbox * was already blocked, otherwise @p false. * @note This function does never fail spuriously. */ inline bool try_block() { auto e = stack_empty_dummy(); bool res = m_stack.compare_exchange_strong(e, reader_blocked_dummy()); // return true in case queue was already blocked return res || e == reader_blocked_dummy(); }
inline bool blocked() { return m_stack == reader_blocked_dummy(); }
/// Queries whether this has been marked as blocked, i.e., /// the owner of the list is waiting for new data. bool blocked() { return stack_.load() == reader_blocked_dummy(); }