123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/allocator/partition_allocator/partition_tls.h"
- #include <windows.h>
- namespace partition_alloc::internal {
- namespace {
- // Store the key as the thread destruction callback doesn't get it.
- PartitionTlsKey g_key;
- void (*g_destructor)(void*) = nullptr;
- void (*g_on_dll_process_detach)() = nullptr;
- // Static callback function to call with each thread termination.
- void NTAPI PartitionTlsOnThreadExit(PVOID module,
- DWORD reason,
- PVOID reserved) {
- if (reason != DLL_THREAD_DETACH && reason != DLL_PROCESS_DETACH)
- return;
- if (reason == DLL_PROCESS_DETACH && g_on_dll_process_detach)
- g_on_dll_process_detach();
- if (g_destructor) {
- void* per_thread_data = PartitionTlsGet(g_key);
- if (per_thread_data)
- g_destructor(per_thread_data);
- }
- }
- } // namespace
- bool PartitionTlsCreate(PartitionTlsKey* key, void (*destructor)(void*)) {
- PA_CHECK(g_destructor == nullptr); // Only one TLS key supported at a time.
- PartitionTlsKey value = TlsAlloc();
- if (value != TLS_OUT_OF_INDEXES) {
- *key = value;
- g_key = value;
- g_destructor = destructor;
- return true;
- }
- return false;
- }
- void PartitionTlsSetOnDllProcessDetach(void (*callback)()) {
- g_on_dll_process_detach = callback;
- }
- } // namespace partition_alloc::internal
- // See thread_local_storage_win.cc for details and reference.
- //
- // The callback has to be in any section between .CRT$XLA and .CRT$XLZ, as these
- // are sentinels used by the TLS code to find the callback array bounds. As we
- // don't particularly care about where we are called but would prefer to be
- // deinitialized towards the end (in particular after Chromium's TLS), we locate
- // ourselves in .CRT$XLY.
- // Force a reference to _tls_used to make the linker create the TLS directory if
- // it's not already there. (e.g. if __declspec(thread) is not used). Force a
- // reference to partition_tls_thread_exit_callback to prevent whole program
- // optimization from discarding the variable.
- #ifdef _WIN64
- #pragma comment(linker, "/INCLUDE:_tls_used")
- #pragma comment(linker, "/INCLUDE:partition_tls_thread_exit_callback")
- #else // _WIN64
- #pragma comment(linker, "/INCLUDE:__tls_used")
- #pragma comment(linker, "/INCLUDE:_partition_tls_thread_exit_callback")
- #endif // _WIN64
- // extern "C" suppresses C++ name mangling so we know the symbol name for the
- // linker /INCLUDE:symbol pragma above.
- extern "C" {
- // The linker must not discard partition_tls_thread_exit_callback. (We force a
- // reference to this variable with a linker /INCLUDE:symbol pragma to ensure
- // that.) If this variable is discarded, PartitionTlsOnThreadExit will never be
- // called.
- #ifdef _WIN64
- // .CRT section is merged with .rdata on x64 so it must be constant data.
- #pragma const_seg(".CRT$XLY")
- // When defining a const variable, it must have external linkage to be sure the
- // linker doesn't discard it.
- extern const PIMAGE_TLS_CALLBACK partition_tls_thread_exit_callback;
- const PIMAGE_TLS_CALLBACK partition_tls_thread_exit_callback =
- partition_alloc::internal::PartitionTlsOnThreadExit;
- // Reset the default section.
- #pragma const_seg()
- #else // _WIN64
- #pragma data_seg(".CRT$XLY")
- PIMAGE_TLS_CALLBACK partition_tls_thread_exit_callback =
- partition_alloc::internal::PartitionTlsOnThreadExit;
- // Reset the default section.
- #pragma data_seg()
- #endif // _WIN64
- } // extern "C"
|