rt: Remove lock_free_queue. Unused. Issue #2701

This commit is contained in:
Brian Anderson 2012-06-25 15:39:59 -07:00
parent 216105fc55
commit 3d0826b5fc
2 changed files with 0 additions and 266 deletions

View File

@ -1,54 +0,0 @@
/*
* Interrupt transparent queue, Schoen et. al, "On Interrupt-Transparent
* Synchronization in an Embedded Object-Oriented Operating System", 2000.
* enqueue() is allowed to interrupt enqueue() and dequeue(), however,
* dequeue() is not allowed to interrupt itself.
*/
#include "../rust_globals.h"
#include "lock_free_queue.h"
lock_free_queue_node::lock_free_queue_node() : next(NULL) {
}
lock_free_queue::lock_free_queue() : _tail(this) {
}
void
lock_free_queue::enqueue(lock_free_queue_node *item) {
lock.lock();
item->next = (lock_free_queue_node *) NULL;
lock_free_queue_node *last = _tail;
_tail = item;
while (last->next) {
last = last->next;
}
last->next = item;
lock.unlock();
}
lock_free_queue_node *
lock_free_queue::dequeue() {
lock.lock();
lock_free_queue_node *item = next;
if (item && !(next = item->next)) {
_tail = (lock_free_queue_node *) this;
if (item->next) {
lock_free_queue_node *lost = item->next;
lock_free_queue_node *help;
do {
help = lost->next;
enqueue(lost);
} while ((lost = help) != (lock_free_queue_node *) NULL);
}
}
lock.unlock();
return item;
}
bool
lock_free_queue::is_empty() {
return next == NULL;
}

View File

@ -1,212 +0,0 @@
#ifndef LOCK_FREE_QUEUE_H
#define LOCK_FREE_QUEUE_H
/**
* How and why this lock free queue works:
*
* Adapted from the paper titled "Simple, Fast, and Practical Non-Blocking
* and Blocking Concurrent Queue Algorithms" by Maged M. Michael,
* Michael L. Scott.
*
* Safety Properties:
*
* 1. The linked list is always connected.
* 2. Nodes are only inserted after the last node in the linked list.
* 3. Nodes are only deleted from the beginning of the linked list.
* 4. Head always points to the first node in the linked list.
* 5. Tail always points to a node in the linked list.
*
*
* 1. The linked list is always connected because the next pointer is not set
* to null before the node is freed, and no node is freed until deleted
* from the linked list.
*
* 2. Nodes are only inserted at the end of the linked list because they are
* linked through the tail pointer which always points to a node in the
* linked list (5) and an inserted node is only linked to a node that has
* a null next pointer, and the only such node is the last one (1).
*
* 3. Nodes are deleted from the beginning of the list because they are
* deleted only when they are pointed to by head which always points to the
* first node (4).
*
* 4. Head always points to the first node in the list because it only changes
* its value to the next node atomically. The new value of head cannot be
* null because if there is only one node in the list the dequeue operation
* returns without deleting any nodes.
*
* 5. Tail always points to a node in the linked list because it never lags
* behind head, so it can never point to a deleted node. Also, when tail
* changes its value it always swings to the next node in the list and it
* never tires to change its value if the next pointer is NULL.
*/
#include <assert.h>
template <class T>
class lock_free_queue {
struct node_t;
struct pointer_t {
node_t *node;
uint32_t count;
pointer_t() : node(NULL), count(0) {
}
pointer_t(node_t *node, uint32_t count) {
this->node = node;
this->count = count;
}
bool equals(pointer_t &other) {
return node == other.node && count == other.count;
}
};
struct node_t {
T value;
pointer_t next;
node_t() {
next.node = NULL;
next.count = 0;
}
node_t(pointer_t next, T value) {
this->next = next;
this->value = value;
}
};
// Always points to the first node in the list.
pointer_t head;
// Always points to a node in the list, (not necessarily the last).
pointer_t tail;
// Compare and swap counted pointers, we can only do this if pointr_t is
// 8 bytes or less since that the maximum size CAS can handle.
bool compare_and_swap(pointer_t *address,
pointer_t *oldValue,
pointer_t newValue) {
// FIXME (#2701) this is requiring us to pass -fno-strict-aliasing
// to GCC (possibly there are other, similar problems)
if (sync::compare_and_swap(
(uint64_t*) address,
*(uint64_t*) oldValue,
*(uint64_t*) &newValue)) {
return true;
}
return false;
}
public:
lock_free_queue() {
// We can only handle 64bit CAS for counted pointers, so this will
// not work with 64bit pointers.
assert (sizeof(pointer_t) == sizeof(uint64_t));
// Allocate a dummy node to be used as the first node in the list.
node_t *node = new node_t();
// Head and tail both start out pointing to the dummy node.
head.node = node;
tail.node = node;
}
virtual ~lock_free_queue() {
// Delete dummy node.
delete head.node;
}
bool is_empty() {
return head.node == tail.node;
}
virtual void enqueue(T value) {
// Create a new node to be inserted in the linked list, and set the
// next node to NULL.
node_t *node = new node_t();
node->value = value;
node->next.node = NULL;
pointer_t tail;
// Keep trying until enqueue is done.
while (true) {
// Read the current tail which may either point to the last node
// or to the second to last node (not sure why second to last,
// and not any other node).
tail = this->tail;
// Reads the next node after the tail which will be the last node
// if null.
pointer_t next;
if (tail.node != NULL) {
next = tail.node->next;
}
// Loop if another thread changed the tail since we last read it.
if (tail.equals(this->tail) == false) {
continue;
}
// If next is not pointing to the last node try to swing tail to
// the last node and loop.
if (next.node != NULL) {
compare_and_swap(&this->tail, &tail,
pointer_t(next.node, tail.count + 1));
continue;
}
// Try to link node at the end of the linked list.
if (compare_and_swap(&tail.node->next, &next,
pointer_t(node, next.count + 1))) {
// Enqueueing is done.
break;
}
}
// Enqueue is done, try to swing tail to the inserted node.
compare_and_swap(&this->tail, &tail,
pointer_t(node, tail.count + 1));
}
bool dequeue(T *value) {
pointer_t head;
// Keep trying until dequeue is done.
while(true) {
head = this->head;
pointer_t tail = this->tail;
pointer_t next = head.node->next;
if (head.equals(this->head) == false) {
continue;
}
// If queue is empty, or if tail is falling behind.
if (head.node == tail.node) {
// If queue is empty.
if (next.node == NULL) {
return false;
}
// Tail is falling behind, advance it.
compare_and_swap(&this->tail,
&tail,
pointer_t(next.node, tail.count + 1));
} else {
// Read value before CAS, otherwise another
// dequeue might advance it.
*value = next.node->value;
if (compare_and_swap(&this->head, &head,
pointer_t(next.node, head.count + 1))) {
break;
}
}
}
delete head.node;
return true;
}
};
#endif /* LOCK_FREE_QUEUE_H */