Beispiel #1
0
void mutex_lock(mutex_t *lock)
{
    XEDGE(trylock, loop_out);
    int expected;
    do {
        expected = 0;
    } while (!L(trylock, lock->locked.compare_exchange_weak(expected, 1)));
    LPOST(loop_out);
}
Beispiel #2
0
 void lock() {
     XEDGE(lock, out);
     Node::Ptr unlocked(nullptr, 0);
     if (!L(lock,
            tail_.compare_exchange_strong(unlocked, Node::Ptr(nullptr, 1)))){
         LS(lock, slowpathLock(unlocked));
     }
     LPOST(out);
 }
Beispiel #3
0
void mutex2_lock(mutex2_t *lock)
{
    //XEDGE(take, check); // I /think/ maybe we don't need this depending.
    XEDGE(check, loop_out);

    int ticket = L(take, lock->next.fetch_add(1));
    while (ticket != L(check, lock->owner))
        continue;
    LPOST(loop_out);
}
rmc_noinline
optional<T> MSQueue<T>::dequeue() {
    auto guard = Epoch::pin();

    // Core message passing: reading the data out of the node comes
    // after getting the pointer to it.
    XEDGE(get_next, node_use);
    // Make sure we see at least head's init
    XEDGE(get_head, get_next);
    // Need to make sure anything visible through the next pointer
    // stays visible when it gets republished at the head or tail
    VEDGE(get_next, dequeue);

    lf_ptr<MSQueueNode> head, next;

    for (;;) {
        head = L(get_head, this->head_);
        next = L(get_next, head->next_);

        // Consistency check; see note above
        if (head != this->head_) continue;

        // Is the queue empty?
        if (next == nullptr) {
            return optional<T> {};
        } else {
            // OK, now we try to actually read the thing out.
            if (L(dequeue, this->head_.compare_exchange_weak(head, next))) {
                break;
            }
        }
    }

    LPOST(node_use);

    // OK, everything set up.
    // next contains the value we are reading
    // head can be freed
    guard.unlinked(head);
    optional<T> ret(std::move(next->data_));
    next->data_ = optional<T> {}; // destroy the object

    return ret;
}
Beispiel #5
0
    void lock() {
        XEDGE(acquire, out);

        uintptr_t locked;
        for (;;) {
            locked = locked_;
            if (!writeLocked(locked)) {
                if (L(acquire, locked_.compare_exchange_weak(
                          locked, locked|kWriterLocked))) {
                    break;
                }
            }
        }
        while (readLocked(locked)) {
            locked = L(acquire, locked_);
        }

        LPOST(out);
    }
rmc_noinline
optional<T> MSQueue<T>::dequeue() {
    // Core message passing: reading the data out of the node comes
    // after getting the pointer to it.
    XEDGE(get_next, node_use);
    // Make sure we see at least head's init
    XEDGE(get_head, get_next);
    // XXX: another part of maintaining the awful head != tail ->
    // next != null invariant that causes like a billion constraints.
    // Think about it a bit more to make sure this is right.
    // This is awful, so many barriers.
    XEDGE(get_head, get_tail);
    // If we see an updated tail (so that head != tail), make sure that
    // we see update to head->next.
    XEDGE(get_tail, get_next);

    // Need to make sure anything visible through the next pointer
    // stays visible when it gets republished at the head or tail
    VEDGE(get_next, catchup_swing);
    VEDGE(get_next, dequeue);

    // Make sure the read out of next executes before the verification
    // that it read from a sensible place:
    XEDGE(get_next, verify_head);


    NodePtr head, tail, next;

    universal data;

    for (;;) {
        head = L(get_head, this->head_);
        tail = L(get_tail, this->tail_); // XXX: really?
        next = L(get_next, head->next_);

        // Consistency check; see note above
        if (head != L(verify_head, this->head_)) continue;

        // Check if the queue *might* be empty
        // XXX: is it necessary to have the empty check under this
        if (head == tail) {
            // Ok, so, the queue might be empty, but it also might
            // be that the tail pointer has just fallen behind.
            // If the next pointer is null, then it is actually empty
            if (next == nullptr) {
                return optional<T> {};
            } else {
                // not empty: tail falling behind; since it is super
                // not ok for the head to advance past the tail,
                // try advancing the tail
                // XXX weak v strong?
                L(catchup_swing,
                  this->tail_.compare_exchange_strong_gen(tail, next));
            }
        } else {
            // OK, now we try to actually read the thing out.
            assert_ne(next.ptr(), nullptr);

            // We need to read the data out of the node
            // *before* we try to dequeue it or else it could get
            // reused before we read it out.
            data = L(node_use, next->data_);
            if (L(dequeue, this->head_.compare_exchange_weak_gen(head, next))) {
                break;
            }
        }
    }

    LPOST(node_use);

    // OK, everything set up.
    // head can be freed
    MSQueueNode::freelist.unlinked(head);
    optional<T> ret(data.extract<T>());

    return ret;
}