ipc/chromium/src/base/thread_local_storage_win.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/thread_local_storage.h"
michael@0 6
michael@0 7 #include <windows.h>
michael@0 8
michael@0 9 #include "base/logging.h"
michael@0 10
michael@0 11 // In order to make TLS destructors work, we need to keep function
michael@0 12 // pointers to the destructor for each TLS that we allocate.
michael@0 13 // We make this work by allocating a single OS-level TLS, which
michael@0 14 // contains an array of slots for the application to use. In
michael@0 15 // parallel, we also allocate an array of destructors, which we
michael@0 16 // keep track of and call when threads terminate.
michael@0 17
michael@0 18 // tls_key_ is the one native TLS that we use. It stores our
michael@0 19 // table.
michael@0 20 long ThreadLocalStorage::tls_key_ = TLS_OUT_OF_INDEXES;
michael@0 21
michael@0 22 // tls_max_ is the high-water-mark of allocated thread local storage.
michael@0 23 // We intentionally skip 0 so that it is not confused with an
michael@0 24 // unallocated TLS slot.
michael@0 25 long ThreadLocalStorage::tls_max_ = 1;
michael@0 26
michael@0 27 // An array of destructor function pointers for the slots. If
michael@0 28 // a slot has a destructor, it will be stored in its corresponding
michael@0 29 // entry in this array.
michael@0 30 ThreadLocalStorage::TLSDestructorFunc
michael@0 31 ThreadLocalStorage::tls_destructors_[kThreadLocalStorageSize];
michael@0 32
michael@0 33 void** ThreadLocalStorage::Initialize() {
michael@0 34 if (tls_key_ == TLS_OUT_OF_INDEXES) {
michael@0 35 long value = TlsAlloc();
michael@0 36 DCHECK(value != TLS_OUT_OF_INDEXES);
michael@0 37
michael@0 38 // Atomically test-and-set the tls_key. If the key is TLS_OUT_OF_INDEXES,
michael@0 39 // go ahead and set it. Otherwise, do nothing, as another
michael@0 40 // thread already did our dirty work.
michael@0 41 if (InterlockedCompareExchange(&tls_key_, value, TLS_OUT_OF_INDEXES) !=
michael@0 42 TLS_OUT_OF_INDEXES) {
michael@0 43 // We've been shortcut. Another thread replaced tls_key_ first so we need
michael@0 44 // to destroy our index and use the one the other thread got first.
michael@0 45 TlsFree(value);
michael@0 46 }
michael@0 47 }
michael@0 48 DCHECK(TlsGetValue(tls_key_) == NULL);
michael@0 49
michael@0 50 // Create an array to store our data.
michael@0 51 void** tls_data = new void*[kThreadLocalStorageSize];
michael@0 52 memset(tls_data, 0, sizeof(void*[kThreadLocalStorageSize]));
michael@0 53 TlsSetValue(tls_key_, tls_data);
michael@0 54 return tls_data;
michael@0 55 }
michael@0 56
michael@0 57 ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor)
michael@0 58 : initialized_(false) {
michael@0 59 Initialize(destructor);
michael@0 60 }
michael@0 61
michael@0 62 bool ThreadLocalStorage::Slot::Initialize(TLSDestructorFunc destructor) {
michael@0 63 if (tls_key_ == TLS_OUT_OF_INDEXES || !TlsGetValue(tls_key_))
michael@0 64 ThreadLocalStorage::Initialize();
michael@0 65
michael@0 66 // Grab a new slot.
michael@0 67 slot_ = InterlockedIncrement(&tls_max_) - 1;
michael@0 68 if (slot_ >= kThreadLocalStorageSize) {
michael@0 69 NOTREACHED();
michael@0 70 return false;
michael@0 71 }
michael@0 72
michael@0 73 // Setup our destructor.
michael@0 74 tls_destructors_[slot_] = destructor;
michael@0 75 initialized_ = true;
michael@0 76 return true;
michael@0 77 }
michael@0 78
michael@0 79 void ThreadLocalStorage::Slot::Free() {
michael@0 80 // At this time, we don't reclaim old indices for TLS slots.
michael@0 81 // So all we need to do is wipe the destructor.
michael@0 82 tls_destructors_[slot_] = NULL;
michael@0 83 initialized_ = false;
michael@0 84 }
michael@0 85
michael@0 86 void* ThreadLocalStorage::Slot::Get() const {
michael@0 87 void** tls_data = static_cast<void**>(TlsGetValue(tls_key_));
michael@0 88 if (!tls_data)
michael@0 89 tls_data = ThreadLocalStorage::Initialize();
michael@0 90 DCHECK(slot_ >= 0 && slot_ < kThreadLocalStorageSize);
michael@0 91 return tls_data[slot_];
michael@0 92 }
michael@0 93
michael@0 94 void ThreadLocalStorage::Slot::Set(void* value) {
michael@0 95 void** tls_data = static_cast<void**>(TlsGetValue(tls_key_));
michael@0 96 if (!tls_data)
michael@0 97 tls_data = ThreadLocalStorage::Initialize();
michael@0 98 DCHECK(slot_ >= 0 && slot_ < kThreadLocalStorageSize);
michael@0 99 tls_data[slot_] = value;
michael@0 100 }
michael@0 101
michael@0 102 void ThreadLocalStorage::ThreadExit() {
michael@0 103 if (tls_key_ == TLS_OUT_OF_INDEXES)
michael@0 104 return;
michael@0 105
michael@0 106 void** tls_data = static_cast<void**>(TlsGetValue(tls_key_));
michael@0 107
michael@0 108 // Maybe we have never initialized TLS for this thread.
michael@0 109 if (!tls_data)
michael@0 110 return;
michael@0 111
michael@0 112 for (int slot = 0; slot < tls_max_; slot++) {
michael@0 113 if (tls_destructors_[slot] != NULL) {
michael@0 114 void* value = tls_data[slot];
michael@0 115 tls_destructors_[slot](value);
michael@0 116 }
michael@0 117 }
michael@0 118
michael@0 119 delete[] tls_data;
michael@0 120
michael@0 121 // In case there are other "onexit" handlers...
michael@0 122 TlsSetValue(tls_key_, NULL);
michael@0 123 }
michael@0 124
michael@0 125 // Thread Termination Callbacks.
michael@0 126 // Windows doesn't support a per-thread destructor with its
michael@0 127 // TLS primitives. So, we build it manually by inserting a
michael@0 128 // function to be called on each thread's exit.
michael@0 129 // This magic is from http://www.codeproject.com/threads/tls.asp
michael@0 130 // and it works for VC++ 7.0 and later.
michael@0 131
michael@0 132 #ifdef _WIN64
michael@0 133
michael@0 134 // This makes the linker create the TLS directory if it's not already
michael@0 135 // there. (e.g. if __declspec(thread) is not used).
michael@0 136 #pragma comment(linker, "/INCLUDE:_tls_used")
michael@0 137
michael@0 138 #else // _WIN64
michael@0 139
michael@0 140 // This makes the linker create the TLS directory if it's not already
michael@0 141 // there. (e.g. if __declspec(thread) is not used).
michael@0 142 #pragma comment(linker, "/INCLUDE:__tls_used")
michael@0 143
michael@0 144 #endif // _WIN64
michael@0 145
michael@0 146 // Static callback function to call with each thread termination.
michael@0 147 void NTAPI OnThreadExit(PVOID module, DWORD reason, PVOID reserved)
michael@0 148 {
michael@0 149 // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+
michael@0 150 // and on W2K and W2K3. So don't assume it is sent.
michael@0 151 if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason)
michael@0 152 ThreadLocalStorage::ThreadExit();
michael@0 153 }
michael@0 154
michael@0 155 // .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
michael@0 156 // called automatically by the OS loader code (not the CRT) when the module is
michael@0 157 // loaded and on thread creation. They are NOT called if the module has been
michael@0 158 // loaded by a LoadLibrary() call. It must have implicitly been loaded at
michael@0 159 // process startup.
michael@0 160 // By implicitly loaded, I mean that it is directly referenced by the main EXE
michael@0 161 // or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
michael@0 162 // implicitly loaded.
michael@0 163 //
michael@0 164 // See VC\crt\src\tlssup.c for reference.
michael@0 165 #ifdef _WIN64
michael@0 166
michael@0 167 // .CRT section is merged with .rdata on x64 so it must be constant data.
michael@0 168 #pragma const_seg(".CRT$XLB")
michael@0 169 // When defining a const variable, it must have external linkage to be sure the
michael@0 170 // linker doesn't discard it. If this value is discarded, the OnThreadExit
michael@0 171 // function will never be called.
michael@0 172 extern const PIMAGE_TLS_CALLBACK p_thread_callback;
michael@0 173 const PIMAGE_TLS_CALLBACK p_thread_callback = OnThreadExit;
michael@0 174
michael@0 175 // Reset the default section.
michael@0 176 #pragma const_seg()
michael@0 177
michael@0 178 #else // _WIN64
michael@0 179
michael@0 180 #pragma data_seg(".CRT$XLB")
michael@0 181 PIMAGE_TLS_CALLBACK p_thread_callback = OnThreadExit;
michael@0 182
michael@0 183 // Reset the default section.
michael@0 184 #pragma data_seg()
michael@0 185
michael@0 186 #endif // _WIN64

mercurial