// atomically sets m_stack back and enqueues all elements to the cache bool fetch_new_data(pointer end_ptr) { CPPA_REQUIRE(m_head == nullptr); CPPA_REQUIRE(!end_ptr || end_ptr == stack_empty_dummy()); pointer e = m_stack.load(); // must not be called on a closed queue CPPA_REQUIRE(e != nullptr); // 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 (m_stack.compare_exchange_weak(e, end_ptr)) { if (is_dummy(e)) { // only use-case for this is closing a queue CPPA_REQUIRE(end_ptr == nullptr); return false; } while (e) { CPPA_REQUIRE(!is_dummy(e)); auto next = e->next; e->next = m_head; m_head = e; e = next; } return true; } // next iteration } return false; }
// 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; }
void state_print_label(State *s, LmnWord _fp, LmnWord _owner) { Automata a; FILE *f; StateSpace owner; owner = (StateSpace)_owner; if (!statespace_has_property(owner) || (is_dummy(s) && is_encoded(s))) { return; } a = statespace_automata(owner); f = (FILE *)_fp; switch (lmn_env.mc_dump_format) { case Dir_DOT: { if (state_is_accept(a, s) || state_is_end(a, s)) { fprintf(f, " %lu [peripheries = 2]\n", state_format_id(s, owner->is_formated)); } break; } case LaViT: fprintf(f, "%lu::", state_format_id(s, owner->is_formated)); fprintf(f, "%s\n", automata_state_name(a, state_property_state(s))); case FSM: case CUI: /* 状態のグローバルルート膜の膜名としてdump済 */ break; default: lmn_fatal("unexpected"); break; } }
/// Queries whether there is new data to read, i.e., whether the next /// call to {@link try_pop} would succeeed. /// @pre !closed() bool can_fetch_more() { if (head_ != nullptr) { return true; } auto ptr = stack_.load(); CAF_ASSERT(ptr != nullptr); return ! is_dummy(ptr); }
// 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 } }
/* TODO: 美しさ */ void state_print_transition(State *s, LmnWord _fp, LmnWord _owner) { FILE *f; StateSpace owner; unsigned int i; BOOL need_id_foreach_trans; char *state_separator, *trans_separator, *label_begin, *label_end; BOOL formated; /* Rehashが発生している場合, * サクセッサへの情報は, RehashしたオリジナルのStateオブジェクトが保持しているため, * dummyフラグが真かつエンコード済みの状態には遷移情報は載っていない. * (エンコード済のバイナリストリングしか載っていない) */ if ((is_dummy(s) && is_encoded(s))) return; f = (FILE *)_fp; owner = (StateSpace)_owner; need_id_foreach_trans = TRUE; switch (lmn_env.mc_dump_format) { case DOT: state_separator = " -> "; trans_separator = NULL; label_begin = " [ label = \""; label_end = "\" ];"; break; case FSM: state_separator = " "; trans_separator = NULL; label_begin = " \""; label_end = "\""; break; case LaViT: /* FALLTHROUGH: CUIモードと共通 */ case CUI: state_separator = "::"; /* なぜかspaceが混ざるとlavitは読み込むことができない */ trans_separator = ","; label_begin = "("; label_end = ")"; need_id_foreach_trans = FALSE; break; default: lmn_fatal("unexpected"); break; } formated = owner ? owner->is_formated : FALSE; if (!need_id_foreach_trans) { fprintf(f, "%lu%s", state_format_id(s, formated), state_separator); } if (s->successors) { for (i = 0; i < state_succ_num(s); i++) { /* dump dst state's IDs */ if (need_id_foreach_trans) { fprintf(f, "%lu%s", state_format_id(s, formated), state_separator); } else if (i > 0) { LMN_ASSERT(trans_separator); fprintf(f, "%s", trans_separator); } /* MEMO: rehashが発生していても, successorポインタを辿る先は, オリジナル */ fprintf(f, "%lu", state_format_id(state_succ_state(s, i), formated)); if (has_trans_obj(s)) { Transition t; unsigned int j; fprintf(f, "%s", label_begin); t = transition(s, i); for (j = 0; j < transition_rule_num(t); j++) { if (j > 0) fprintf(f, " "); /* ルール名の区切りは半角スペース1文字 */ fprintf(f, "%s", lmn_id_to_name(transition_rule(t, j))); } fprintf(f, "%s", label_end); } if (i + 1 < state_succ_num(s) && need_id_foreach_trans) { fprintf(f,"\n"); } } fprintf(f, "\n"); } else if (!need_id_foreach_trans){ fprintf(f, "\n"); } }
/** Printer * ownerはNULLでもok */ void dump_state_data(State *s, LmnWord _fp, LmnWord _owner) { FILE *f; StateSpace owner; unsigned long print_id; #ifdef KWBT_OPT LmnCost cost = lmn_env.opt_mode != OPT_NONE ? state_cost(s) : 0UL; #endif /* Rehashが発生している場合, * dummyフラグが真かつエンコード済みフラグが偽のStateオブジェクトが存在する. * このようなStateオブジェクトのバイナリストリングは * Rehashされた側のテーブルに存在するStateオブジェクトに登録されているためcontinueする. */ if (is_dummy(s) && !is_encoded(s)) return; f = (FILE *)_fp; owner = (StateSpace)_owner; { /* この時点で状態は, ノーマル || (dummyフラグが立っている && エンコード済)である. * dummyならば, バイナリストリング以外のデータはオリジナル側(parent)に記録している. */ State *target = !is_dummy(s) ? s : state_get_parent(s); if (owner) { print_id = state_format_id(target, owner->is_formated); } else { print_id = state_format_id(target, FALSE); } } switch (lmn_env.mc_dump_format) { case LaViT: fprintf(f, "%lu::", print_id); state_print_mem(s, _fp); break; case FSM: /* under constructions.. */ fprintf(f, "1\n"); break; case Dir_DOT: if (state_succ_num(s) == 0) { fprintf(f, " %lu [style=filled, fillcolor = \"#C71585\", shape = Msquare];\n", print_id); } break; case CUI: { BOOL has_property = owner && statespace_has_property(owner); #ifdef KWBT_OPT fprintf(f, "%lu::%lu::%s" , print_id, cost , has_property ? automata_state_name(statespace_automata(owner), state_property_state(s)) : ""); #else fprintf(f, "%lu::%s" , print_id , has_property ? automata_state_name(statespace_automata(owner), state_property_state(s)) : ""); #endif state_print_mem(s, _fp); break; } default: lmn_fatal("unexpected"); break; } }
MonoLockFreeQueueNode* mono_lock_free_queue_dequeue (MonoLockFreeQueue *q) { MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); MonoLockFreeQueueNode *head; retry: for (;;) { MonoLockFreeQueueNode *tail, *next; head = (MonoLockFreeQueueNode *) get_hazardous_pointer ((gpointer volatile*)&q->head, hp, 0); tail = (MonoLockFreeQueueNode*)q->tail; mono_memory_read_barrier (); next = head->next; mono_memory_read_barrier (); /* Are head, tail and next consistent? */ if (head == q->head) { g_assert (next != INVALID_NEXT && next != FREE_NEXT); g_assert (next != head); /* Is queue empty or tail behind? */ if (head == tail) { if (next == END_MARKER) { /* Queue is empty */ mono_hazard_pointer_clear (hp, 0); /* * We only continue if we * reenqueue the dummy * ourselves, so as not to * wait for threads that might * not actually run. */ if (!is_dummy (q, head) && try_reenqueue_dummy (q)) continue; return NULL; } /* Try to advance tail */ InterlockedCompareExchangePointer ((gpointer volatile*)&q->tail, next, tail); } else { g_assert (next != END_MARKER); /* Try to dequeue head */ if (InterlockedCompareExchangePointer ((gpointer volatile*)&q->head, next, head) == head) break; } } mono_memory_write_barrier (); mono_hazard_pointer_clear (hp, 0); } /* * The head is dequeued now, so we know it's this thread's * responsibility to free it - no other thread can. */ mono_memory_write_barrier (); mono_hazard_pointer_clear (hp, 0); g_assert (head->next); /* * Setting next here isn't necessary for correctness, but we * do it to make sure that we catch dereferencing next in a * node that's not in the queue anymore. */ head->next = INVALID_NEXT; #if QUEUE_DEBUG g_assert (head->in_queue); head->in_queue = FALSE; mono_memory_write_barrier (); #endif if (is_dummy (q, head)) { g_assert (q->has_dummy); q->has_dummy = 0; mono_memory_write_barrier (); mono_thread_hazardous_free_or_queue (head, free_dummy, FALSE, TRUE); if (try_reenqueue_dummy (q)) goto retry; return NULL; } /* The caller must hazardously free the node. */ return head; }
/** * @warning call only from the reader (owner) */ inline bool empty() { CPPA_REQUIRE(m_stack.load() != nullptr); return (!m_head && is_dummy(m_stack.load())); }
/** * @brief Queries whether there is new data to read. * @pre m_stack.load() != reader_blocked_dummy() */ inline bool can_fetch_more() { auto ptr = m_stack.load(); CPPA_REQUIRE(ptr != nullptr); return !is_dummy(ptr); }
/// Queries whether this queue is empty. /// @warning Call only from the reader (owner). bool empty() { CAF_ASSERT(! closed()); return cache_.empty() && head_ == nullptr && is_dummy(stack_.load()); }