34 #ifndef ABSL_LOW_LEVEL_ALLOC_MISSING 47 namespace synchronization_internal {
55 static base_internal::LowLevelAlloc::Arena*
arena;
57 static void InitArenaIfNecessary() {
59 if (arena ==
nullptr) {
67 static const uint32_t kInline = 8;
83 bool empty()
const {
return size_ == 0; }
87 const T& operator[](uint32_t
i)
const {
return ptr_[
i]; }
88 T& operator[](uint32_t
i) {
return ptr_[
i]; }
89 const T& back()
const {
return ptr_[
size_-1]; }
90 void pop_back() {
size_--; }
92 void push_back(
const T&
v) {
98 void resize(uint32_t
n) {
103 void fill(
const T& val) {
104 for (uint32_t
i = 0;
i <
size();
i++) {
111 void MoveFrom(Vec<T>* src) {
112 if (src->ptr_ == src->space_) {
115 std::copy(src->ptr_, src->ptr_ + src->size_,
ptr_);
142 void Grow(uint32_t n) {
143 while (capacity_ < n) {
146 size_t request =
static_cast<size_t>(
capacity_) *
sizeof(T);
147 T* copy =
static_cast<T*
>(
149 std::copy(ptr_, ptr_ + size_, copy);
154 Vec(
const Vec&) =
delete;
155 Vec& operator=(
const Vec&) =
delete;
161 NodeSet() { Init(); }
163 void clear() { Init(); }
164 bool contains(int32_t v)
const {
return table_[FindIndex(v)] ==
v; }
166 bool insert(int32_t v) {
167 uint32_t
i = FindIndex(v);
171 if (
table_[i] == kEmpty) {
182 void erase(uint32_t v) {
183 uint32_t
i = FindIndex(v);
184 if (static_cast<uint32_t>(
table_[i]) == v) {
192 #define HASH_FOR_EACH(elem, eset) \ 193 for (int32_t elem, _cursor = 0; (eset).Next(&_cursor, &elem); ) 194 bool Next(int32_t* cursor, int32_t* elem) {
195 while (static_cast<uint32_t>(*cursor) <
table_.size()) {
196 int32_t v =
table_[*cursor];
207 enum : int32_t { kEmpty = -1, kDel = -2 };
211 static uint32_t
Hash(uint32_t
a) {
return a * 41; }
214 int FindIndex(int32_t v)
const {
216 const uint32_t mask = table_.size() - 1;
217 uint32_t
i =
Hash(v) & mask;
218 int deleted_index = -1;
220 int32_t e = table_[
i];
223 }
else if (e == kEmpty) {
225 return (deleted_index >= 0) ? deleted_index :
i;
226 }
else if (e == kDel && deleted_index < 0) {
236 table_.resize(kInline);
243 copy.MoveFrom(&table_);
245 table_.resize(copy.size() * 2);
248 for (
const auto& e : copy) {
249 if (e >= 0) insert(e);
253 NodeSet(
const NodeSet&) =
delete;
254 NodeSet& operator=(
const NodeSet&) =
delete;
261 inline GraphId MakeId(int32_t index, uint32_t
version) {
264 (
static_cast<uint64_t
>(
version) << 32) |
static_cast<uint32_t
>(index);
268 inline int32_t NodeIndex(GraphId
id) {
269 return static_cast<uint32_t
>(
id.handle & 0xfffffffful);
272 inline uint32_t NodeVersion(GraphId
id) {
273 return static_cast<uint32_t
>(
id.handle >> 32);
292 explicit PointerMap(
const Vec<Node*>* nodes) :
nodes_(nodes) {
299 Node* n = (*nodes_)[
i];
300 if (n->masked_ptr == masked)
return i;
306 void Add(
void* ptr, int32_t
i) {
308 (*nodes_)[
i]->next_hash = *head;
312 int32_t Remove(
void* ptr) {
316 for (int32_t* slot = &
table_[
Hash(ptr)]; *slot != -1; ) {
317 int32_t index = *slot;
318 Node* n = (*nodes_)[index];
319 if (n->masked_ptr == masked) {
320 *slot = n->next_hash;
324 slot = &n->next_hash;
334 std::array<int32_t, kHashTableSize>
table_;
336 static uint32_t
Hash(
void* ptr) {
337 return reinterpret_cast<uintptr_t
>(
ptr) % kHashTableSize;
355 Rep() : ptrmap_(&nodes_) {}
359 Node* n = rep->
nodes_[NodeIndex(
id)];
360 return (n->version == NodeVersion(
id)) ? n :
nullptr;
364 InitArenaIfNecessary();
370 for (
auto* node : rep_->nodes_) {
381 for (uint32_t x = 0; x < r->
nodes_.size(); x++) {
383 void*
ptr = base_internal::UnhidePtr<void>(nx->masked_ptr);
384 if (ptr !=
nullptr && static_cast<uint32_t>(r->
ptrmap_.Find(ptr)) != x) {
385 ABSL_RAW_LOG(FATAL,
"Did not find live node in hash table %u %p", x, ptr);
388 ABSL_RAW_LOG(FATAL,
"Did not clear visited marker on node %u", x);
390 if (!ranks.insert(nx->rank)) {
391 ABSL_RAW_LOG(FATAL,
"Duplicate occurrence of rank %d", nx->rank);
395 if (nx->rank >= ny->rank) {
396 ABSL_RAW_LOG(FATAL,
"Edge %u->%d has bad rank assignment %d->%d", x, y,
405 int32_t
i = rep_->ptrmap_.Find(ptr);
407 return MakeId(i, rep_->nodes_[i]->version);
408 }
else if (rep_->free_nodes_.empty()) {
414 n->rank = rep_->nodes_.size();
418 rep_->nodes_.push_back(n);
419 rep_->ptrmap_.Add(ptr, n->rank);
420 return MakeId(n->rank, n->version);
424 int32_t r = rep_->free_nodes_.back();
425 rep_->free_nodes_.pop_back();
426 Node* n = rep_->nodes_[r];
430 rep_->ptrmap_.Add(ptr, r);
431 return MakeId(r, n->version);
436 int32_t
i = rep_->ptrmap_.Remove(ptr);
440 Node* x = rep_->nodes_[
i];
442 rep_->nodes_[y]->in.erase(i);
445 rep_->nodes_[y]->out.erase(i);
449 x->masked_ptr = base_internal::HidePtr<void>(
nullptr);
450 if (x->version == std::numeric_limits<uint32_t>::max()) {
454 rep_->free_nodes_.push_back(i);
460 return n ==
nullptr ?
nullptr 461 : base_internal::UnhidePtr<void>(n->masked_ptr);
465 return FindNode(rep_, node) !=
nullptr;
470 return xn &&
FindNode(rep_, y) && xn->out.contains(NodeIndex(y));
477 xn->out.erase(NodeIndex(y));
478 yn->in.erase(NodeIndex(x));
487 static void Sort(
const Vec<Node*>&, Vec<int32_t>* delta);
493 const int32_t x = NodeIndex(idx);
494 const int32_t y = NodeIndex(idy);
497 if (nx ==
nullptr || ny ==
nullptr)
return true;
499 if (nx == ny)
return false;
500 if (!nx->out.insert(y)) {
507 if (nx->rank <= ny->rank) {
520 for (
const auto& d : r->
deltaf_) {
521 r->
nodes_[d]->visited =
false;
536 while (!r->
stack_.empty()) {
540 if (nn->visited)
continue;
547 if (nw->rank == upper_bound) {
550 if (!nw->visited && nw->rank < upper_bound) {
562 while (!r->
stack_.empty()) {
566 if (nn->visited)
continue;
573 if (!nw->visited && lower_bound < nw->
rank) {
596 for (uint32_t
i = 0;
i < r->
list_.size();
i++) {
601 static void Sort(
const Vec<Node*>& nodes, Vec<int32_t>* delta) {
603 const Vec<Node*>* nodes;
604 bool operator()(int32_t
a, int32_t
b)
const {
605 return (*nodes)[
a]->rank < (*nodes)[
b]->rank;
610 std::sort(delta->begin(), delta->end(), cmp);
615 for (
auto& v : *src) {
618 r->
nodes_[w]->visited =
false;
627 const int32_t x = NodeIndex(idx);
628 const int32_t y = NodeIndex(idy);
638 while (!r->
stack_.empty()) {
639 int32_t n = r->
stack_.back();
647 if (path_len < max_path_len) {
648 path[path_len] = MakeId(n, rep_->nodes_[n]->version);
658 if (seen.insert(w)) {
668 return FindPath(x, y, 0,
nullptr) > 0;
672 int (*get_stack_trace)(
void**
stack,
int)) {
674 if (n ==
nullptr || n->priority >= priority) {
677 n->nstack = (*get_stack_trace)(n->stack,
ABSL_ARRAYSIZE(n->stack));
695 #endif // ABSL_LOW_LEVEL_ALLOC_MISSING
static void MoveToList(GraphCycles::Rep *r, Vec< int32_t > *src, Vec< int32_t > *dst)
constexpr size_t Find(Needle, Needle, Ts...)
int FindPath(GraphId source, GraphId dest, int max_path_len, GraphId path[]) const
static AllocList * Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena)
#define ABSL_RAW_LOG(severity,...)
bool IsReachable(GraphId source_node, GraphId dest_node) const
bool InsertEdge(GraphId source_node, GraphId dest_node)
static void BackwardDFS(GraphCycles::Rep *r, int32_t n, int32_t lower_bound)
void RemoveEdge(GraphId source_node, GraphId dest_node)
static Node * FindNode(GraphCycles::Rep *rep, GraphId id)
Vec< int32_t > free_nodes_
GraphId path[kMaxDeadlockPathLen]
void UpdateStackTrace(GraphId id, int priority, int(*get_stack_trace)(void **, int))
static void Sort(const Vec< Node * > &, Vec< int32_t > *delta)
uintptr_t HidePtr(T *ptr)
bool HasNode(GraphId node)
bool HasEdge(GraphId source_node, GraphId dest_node) const
static bool ForwardDFS(GraphCycles::Rep *r, int32_t n, int32_t upper_bound)
static void Reorder(GraphCycles::Rep *r)
const Vec< Node * > * nodes_
LowLevelAlloc::Arena * arena
#define ABSL_ARRAYSIZE(array)
static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook)
static void * AllocWithArena(size_t request, Arena *arena) ABSL_ATTRIBUTE_SECTION(malloc_hook)
bool CheckInvariants() const
#define HASH_FOR_EACH(elem, eset)
void RemoveNode(void *ptr)
static Arena * NewArena(int32_t flags)
absl::hash_internal::Hash< T > Hash
static constexpr uint32_t kHashTableSize
int GetStackTrace(GraphId id, void ***ptr)