1//===-- tsd.h ---------------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef SCUDO_TSD_H_
10#define SCUDO_TSD_H_
11
12#include "atomic_helpers.h"
13#include "common.h"
14#include "mutex.h"
15
16#include <limits.h> // for PTHREAD_DESTRUCTOR_ITERATIONS
17#include <pthread.h>
18
19// With some build setups, this might still not be defined.
20#ifndef PTHREAD_DESTRUCTOR_ITERATIONS
21#define PTHREAD_DESTRUCTOR_ITERATIONS 4
22#endif
23
24namespace scudo {
25
26template <class Allocator> struct alignas(SCUDO_CACHE_LINE_SIZE) TSD {
27  typename Allocator::CacheT Cache;
28  typename Allocator::QuarantineCacheT QuarantineCache;
29  using ThisT = TSD<Allocator>;
30  u8 DestructorIterations = 0;
31
32  void init(Allocator *Instance) {
33    DCHECK_EQ(DestructorIterations, 0U);
34    DCHECK(isAligned(reinterpret_cast<uptr>(this), alignof(ThisT)));
35    Instance->initCache(&Cache);
36    DestructorIterations = PTHREAD_DESTRUCTOR_ITERATIONS;
37  }
38
39  void commitBack(Allocator *Instance) { Instance->commitBack(this); }
40
41  inline bool tryLock() {
42    if (Mutex.tryLock()) {
43      atomic_store_relaxed(&Precedence, 0);
44      return true;
45    }
46    if (atomic_load_relaxed(&Precedence) == 0)
47      atomic_store_relaxed(
48          &Precedence,
49          static_cast<uptr>(getMonotonicTime() >> FIRST_32_SECOND_64(16, 0)));
50    return false;
51  }
52  inline void lock() {
53    atomic_store_relaxed(&Precedence, 0);
54    Mutex.lock();
55  }
56  inline void unlock() { Mutex.unlock(); }
57  inline uptr getPrecedence() { return atomic_load_relaxed(&Precedence); }
58
59private:
60  HybridMutex Mutex;
61  atomic_uptr Precedence = {};
62};
63
64} // namespace scudo
65
66#endif // SCUDO_TSD_H_
67