aboutsummaryrefslogtreecommitdiff
path: root/src/tracing/platform_windows.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/tracing/platform_windows.cc')
-rw-r--r--src/tracing/platform_windows.cc175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/tracing/platform_windows.cc b/src/tracing/platform_windows.cc
new file mode 100644
index 000000000..0f1664c76
--- /dev/null
+++ b/src/tracing/platform_windows.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+#include <Windows.h>
+
+#include "perfetto/ext/base/thread_task_runner.h"
+#include "perfetto/tracing/internal/tracing_tls.h"
+#include "perfetto/tracing/platform.h"
+
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives. So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from chromium's base/threading/thread_local_storage_win.cc
+// which in turn is from http://www.codeproject.com/threads/tls.asp.
+
+#ifdef _WIN64
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:perfetto_thread_callback_base")
+#else
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_perfetto_thread_callback_base")
+#endif
+
+namespace perfetto {
+
+namespace {
+
+class PlatformWindows : public Platform {
+ public:
+ static PlatformWindows* instance;
+ PlatformWindows();
+ ~PlatformWindows() override;
+
+ ThreadLocalObject* GetOrCreateThreadLocalObject() override;
+ std::unique_ptr<base::TaskRunner> CreateTaskRunner(
+ const CreateTaskRunnerArgs&) override;
+ std::string GetCurrentProcessName() override;
+ void OnThreadExit();
+
+ private:
+ DWORD tls_key_{};
+};
+
+using ThreadLocalObject = Platform::ThreadLocalObject;
+
+// static
+PlatformWindows* PlatformWindows::instance = nullptr;
+
+PlatformWindows::PlatformWindows() {
+ instance = this;
+ tls_key_ = ::TlsAlloc();
+ PERFETTO_CHECK(tls_key_ != TLS_OUT_OF_INDEXES);
+}
+
+PlatformWindows::~PlatformWindows() {
+ ::TlsFree(tls_key_);
+ instance = nullptr;
+}
+
+void PlatformWindows::OnThreadExit() {
+ auto tls = static_cast<ThreadLocalObject*>(::TlsGetValue(tls_key_));
+ if (tls) {
+ // At this point we rely on the TLS object to be still set to the TracingTLS
+ // we are deleting. See comments in TracingTLS::~TracingTLS().
+ delete tls;
+ }
+}
+
+ThreadLocalObject* PlatformWindows::GetOrCreateThreadLocalObject() {
+ void* tls_ptr = ::TlsGetValue(tls_key_);
+
+ auto* tls = static_cast<ThreadLocalObject*>(tls_ptr);
+ if (!tls) {
+ tls = ThreadLocalObject::CreateInstance().release();
+ ::TlsSetValue(tls_key_, tls);
+ }
+ return tls;
+}
+
+std::unique_ptr<base::TaskRunner> PlatformWindows::CreateTaskRunner(
+ const CreateTaskRunnerArgs& args) {
+ return std::unique_ptr<base::TaskRunner>(new base::ThreadTaskRunner(
+ base::ThreadTaskRunner::CreateAndStart(args.name_for_debugging)));
+}
+
+std::string PlatformWindows::GetCurrentProcessName() {
+ char buf[MAX_PATH];
+ auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
+ std::string name(buf, static_cast<size_t>(len));
+ size_t sep = name.find_last_of('\\');
+ if (sep != std::string::npos)
+ name = name.substr(sep + 1);
+ return name;
+}
+
+} // namespace
+
+// static
+Platform* Platform::GetDefaultPlatform() {
+ static PlatformWindows* thread_safe_init_instance = new PlatformWindows();
+ return thread_safe_init_instance;
+}
+
+} // namespace perfetto
+
+// -----------------------
+// Thread-local destructor
+// -----------------------
+
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// See VC\crt\src\tlssup.c for reference.
+
+// 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 perfetto_thread_callback_base. (We force a
+// reference to this variable with a linker /INCLUDE:symbol pragma to ensure
+// that.) If this variable is discarded, the OnThreadExit function will never be
+// called.
+
+void NTAPI PerfettoOnThreadExit(PVOID, DWORD, PVOID);
+void NTAPI PerfettoOnThreadExit(PVOID module, DWORD reason, PVOID reserved) {
+ if (reason == DLL_THREAD_DETACH || reason == DLL_PROCESS_DETACH) {
+ if (perfetto::PlatformWindows::instance)
+ perfetto::PlatformWindows::instance->OnThreadExit();
+ }
+}
+
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLP")
+
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base;
+const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
+
+// Reset the default section.
+#pragma const_seg()
+
+#else // _WIN64
+
+#pragma data_seg(".CRT$XLP")
+PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
+// Reset the default section.
+#pragma data_seg()
+
+#endif // _WIN64
+
+} // extern "C"
+
+#endif // OS_WIN