[tsan] add intrusive list to be used in tsan allocator, etc

llvm-svn: 159812
This commit is contained in:
Kostya Serebryany 2012-07-06 09:03:45 +00:00
parent 39602781f6
commit ff13537a94
2 changed files with 270 additions and 0 deletions

View File

@ -0,0 +1,120 @@
//===-- sanitizer_list.h ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains implementation of a list class to be used by
// ThreadSanitizer, etc run-times.
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_LIST_H
#define SANITIZER_LIST_H
#include "sanitizer_internal_defs.h"
namespace __sanitizer {
// Intrusive singly-linked list with size(), push_back(), push_front()
// pop_front(), append_front() and append_back().
// This class should be a POD (so that it can be put into TLS)
// and an object with all zero fields should represent a valid empty list.
// This class does not have a CTOR, so clear() should be called on all
// non-zero-initialized objects before using.
template<class Item>
struct IntrusiveList {
void clear() {
first_ = last_ = 0;
size_ = 0;
}
bool empty() const { return size_ == 0; }
uptr size() const { return size_; }
void push_back(Item *x) {
if (empty()) {
x->next = 0;
first_ = last_ = x;
size_ = 1;
} else {
x->next = 0;
last_->next = x;
last_ = x;
size_++;
}
}
void push_front(Item *x) {
if (empty()) {
x->next = 0;
first_ = last_ = x;
size_ = 1;
} else {
x->next = first_;
first_ = x;
size_++;
}
}
void pop_front() {
CHECK(!empty());
first_ = first_->next;
if (first_ == 0)
last_ = 0;
size_--;
}
Item *front() { return first_; }
Item *back() { return last_; }
void append_front(IntrusiveList<Item> *l) {
CHECK_NE(this, l);
if (empty()) {
*this = *l;
} else {
l->last_ = first_;
first_ = l->first_;
size_ += l->size();
}
l->clear();
}
void append_back(IntrusiveList<Item> *l) {
CHECK_NE(this, l);
if (empty()) {
*this = *l;
} else {
last_->next = l->first_;
last_ = l->last_;
size_ += l->size();
}
l->clear();
}
void CheckConsistency() {
if (size_ == 0) {
CHECK_EQ(first_, 0);
CHECK_EQ(last_, 0);
} else {
uptr count = 0;
for (Item *i = first_; ; i = i->next) {
count++;
if (i == last_) break;
}
CHECK_EQ(size(), count);
CHECK_EQ(last_->next, 0);
}
}
// private, don't use directly.
uptr size_;
Item *first_;
Item *last_;
};
} // namespace __sanitizer
#endif // SANITIZER_LIST_H

View File

@ -0,0 +1,150 @@
//===-- sanitizer_list_test.cc --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_list.h"
#include "gtest/gtest.h"
namespace __sanitizer {
struct ListItem {
ListItem *next;
};
typedef IntrusiveList<ListItem> List;
// Check that IntrusiveList can be made thread-local.
static THREADLOCAL List static_list;
static void SetList(List *l, ListItem *x, ListItem *y = 0, ListItem *z = 0) {
l->clear();
l->push_back(x);
if (y) l->push_back(y);
if (z) l->push_back(z);
}
static void CheckList(List *l, ListItem *i1, ListItem *i2 = 0, ListItem *i3 = 0,
ListItem *i4 = 0, ListItem *i5 = 0, ListItem *i6 = 0) {
if (i1) {
CHECK_EQ(l->front(), i1);
l->pop_front();
}
if (i2) {
CHECK_EQ(l->front(), i2);
l->pop_front();
}
if (i3) {
CHECK_EQ(l->front(), i3);
l->pop_front();
}
if (i4) {
CHECK_EQ(l->front(), i4);
l->pop_front();
}
if (i5) {
CHECK_EQ(l->front(), i5);
l->pop_front();
}
if (i6) {
CHECK_EQ(l->front(), i6);
l->pop_front();
}
CHECK(l->empty());
}
TEST(SanitizerCommon, IntrusiveList) {
ListItem items[6];
CHECK_EQ(static_list.size(), 0);
List l;
l.clear();
ListItem *x = &items[0];
ListItem *y = &items[1];
ListItem *z = &items[2];
ListItem *a = &items[3];
ListItem *b = &items[4];
ListItem *c = &items[5];
CHECK_EQ(l.size(), 0);
l.push_back(x);
CHECK_EQ(l.size(), 1);
CHECK_EQ(l.back(), x);
CHECK_EQ(l.front(), x);
l.pop_front();
CHECK(l.empty());
l.CheckConsistency();
l.push_front(x);
CHECK_EQ(l.size(), 1);
CHECK_EQ(l.back(), x);
CHECK_EQ(l.front(), x);
l.pop_front();
CHECK(l.empty());
l.CheckConsistency();
l.push_front(x);
l.push_front(y);
l.push_front(z);
CHECK_EQ(l.size(), 3);
CHECK_EQ(l.front(), z);
CHECK_EQ(l.back(), x);
l.CheckConsistency();
l.pop_front();
CHECK_EQ(l.size(), 2);
CHECK_EQ(l.front(), y);
CHECK_EQ(l.back(), x);
l.pop_front();
l.pop_front();
CHECK(l.empty());
l.CheckConsistency();
l.push_back(x);
l.push_back(y);
l.push_back(z);
CHECK_EQ(l.size(), 3);
CHECK_EQ(l.front(), x);
CHECK_EQ(l.back(), z);
l.CheckConsistency();
l.pop_front();
CHECK_EQ(l.size(), 2);
CHECK_EQ(l.front(), y);
CHECK_EQ(l.back(), z);
l.pop_front();
l.pop_front();
CHECK(l.empty());
l.CheckConsistency();
List l1, l2;
l1.clear();
l2.clear();
l1.append_front(&l2);
CHECK(l1.empty());
CHECK(l2.empty());
l1.append_back(&l2);
CHECK(l1.empty());
CHECK(l2.empty());
SetList(&l1, x);
CheckList(&l1, x);
SetList(&l1, x, y, z);
SetList(&l2, a, b, c);
l1.append_back(&l2);
CheckList(&l1, x, y, z, a, b, c);
CHECK(l2.empty());
}
} // namespace __sanitizer