1//===-- scudo_tsd_exclusive.cpp ---------------------------------*- 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/// Scudo exclusive TSD implementation.
10///
11//===----------------------------------------------------------------------===//
12
13#include "scudo_tsd.h"
14
15#if SCUDO_TSD_EXCLUSIVE
16
17namespace __scudo {
18
19static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT;
20static pthread_key_t PThreadKey;
21
22__attribute__((tls_model("initial-exec")))
23THREADLOCAL ThreadState ScudoThreadState = ThreadNotInitialized;
24__attribute__((tls_model("initial-exec")))
25THREADLOCAL ScudoTSD TSD;
26
27// Fallback TSD for when the thread isn't initialized yet or is torn down. It
28// can be shared between multiple threads and as such must be locked.
29ScudoTSD FallbackTSD;
30
31static void teardownThread(void *Ptr) {
32  uptr I = reinterpret_cast<uptr>(Ptr);
33  // The glibc POSIX thread-local-storage deallocation routine calls user
34  // provided destructors in a loop of PTHREAD_DESTRUCTOR_ITERATIONS.
35  // We want to be called last since other destructors might call free and the
36  // like, so we wait until PTHREAD_DESTRUCTOR_ITERATIONS before draining the
37  // quarantine and swallowing the cache.
38  if (I > 1) {
39    // If pthread_setspecific fails, we will go ahead with the teardown.
40    if (LIKELY(pthread_setspecific(PThreadKey,
41                                   reinterpret_cast<void *>(I - 1)) == 0))
42      return;
43  }
44  TSD.commitBack();
45  ScudoThreadState = ThreadTornDown;
46}
47
48
49static void initOnce() {
50  CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread), 0);
51  initScudo();
52  FallbackTSD.init();
53}
54
55void initThread(bool MinimalInit) {
56  CHECK_EQ(pthread_once(&GlobalInitialized, initOnce), 0);
57  if (UNLIKELY(MinimalInit))
58    return;
59  CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast<void *>(
60      GetPthreadDestructorIterations())), 0);
61  TSD.init();
62  ScudoThreadState = ThreadInitialized;
63}
64
65}  // namespace __scudo
66
67#endif  // SCUDO_TSD_EXCLUSIVE
68