forked from OSchip/llvm-project
[tsan] add intrusive list to be used in tsan allocator, etc
llvm-svn: 159812
This commit is contained in:
parent
39602781f6
commit
ff13537a94
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue