libstdc++: Give std::memory_order a fixed underlying type [PR89624]
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_stoptheworld_win.cpp
blobf114acea79c9c6bac8e924ea7618623eea02c9a0
1 //===-- sanitizer_stoptheworld_win.cpp ------------------------------------===//
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 // See sanitizer_stoptheworld.h for details.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_platform.h"
15 #if SANITIZER_WINDOWS
17 # define WIN32_LEAN_AND_MEAN
18 # include <windows.h>
19 // windows.h needs to be included before tlhelp32.h
20 # include <tlhelp32.h>
22 # include "sanitizer_stoptheworld.h"
24 namespace __sanitizer {
26 namespace {
28 struct SuspendedThreadsListWindows final : public SuspendedThreadsList {
29 InternalMmapVector<HANDLE> threadHandles;
30 InternalMmapVector<DWORD> threadIds;
32 SuspendedThreadsListWindows() {
33 threadIds.reserve(1024);
34 threadHandles.reserve(1024);
37 PtraceRegistersStatus GetRegistersAndSP(uptr index,
38 InternalMmapVector<uptr> *buffer,
39 uptr *sp) const override;
41 tid_t GetThreadID(uptr index) const override;
42 uptr ThreadCount() const override;
45 // Stack Pointer register names on different architectures
46 # if SANITIZER_X64
47 # define SP_REG Rsp
48 # elif SANITIZER_I386
49 # define SP_REG Esp
50 # elif SANITIZER_ARM | SANITIZER_ARM64
51 # define SP_REG Sp
52 # else
53 # error Architecture not supported!
54 # endif
56 PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP(
57 uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
58 CHECK_LT(index, threadHandles.size());
60 buffer->resize(RoundUpTo(sizeof(CONTEXT), sizeof(uptr)) / sizeof(uptr));
61 CONTEXT *thread_context = reinterpret_cast<CONTEXT *>(buffer->data());
62 thread_context->ContextFlags = CONTEXT_ALL;
63 CHECK(GetThreadContext(threadHandles[index], thread_context));
64 *sp = thread_context->SP_REG;
66 return REGISTERS_AVAILABLE;
69 tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const {
70 CHECK_LT(index, threadIds.size());
71 return threadIds[index];
74 uptr SuspendedThreadsListWindows::ThreadCount() const {
75 return threadIds.size();
78 struct RunThreadArgs {
79 StopTheWorldCallback callback;
80 void *argument;
83 DWORD WINAPI RunThread(void *argument) {
84 RunThreadArgs *run_args = (RunThreadArgs *)argument;
86 const DWORD this_thread = GetCurrentThreadId();
87 const DWORD this_process = GetCurrentProcessId();
89 SuspendedThreadsListWindows suspended_threads_list;
90 bool new_thread_found;
92 do {
93 // Take a snapshot of all Threads
94 const HANDLE threads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
95 CHECK(threads != INVALID_HANDLE_VALUE);
97 THREADENTRY32 thread_entry;
98 thread_entry.dwSize = sizeof(thread_entry);
99 new_thread_found = false;
101 if (!Thread32First(threads, &thread_entry))
102 break;
104 do {
105 if (thread_entry.th32ThreadID == this_thread ||
106 thread_entry.th32OwnerProcessID != this_process)
107 continue;
109 bool suspended_thread = false;
110 for (const auto thread_id : suspended_threads_list.threadIds) {
111 if (thread_id == thread_entry.th32ThreadID) {
112 suspended_thread = true;
113 break;
117 // Skip the Thread if it was already suspended
118 if (suspended_thread)
119 continue;
121 const HANDLE thread =
122 OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
123 CHECK(thread);
125 if (SuspendThread(thread) == (DWORD)-1) {
126 DWORD last_error = GetLastError();
128 VPrintf(1, "Could not suspend thread %lu (error %lu)",
129 thread_entry.th32ThreadID, last_error);
130 continue;
133 suspended_threads_list.threadIds.push_back(thread_entry.th32ThreadID);
134 suspended_threads_list.threadHandles.push_back(thread);
135 new_thread_found = true;
136 } while (Thread32Next(threads, &thread_entry));
138 CloseHandle(threads);
140 // Between the call to `CreateToolhelp32Snapshot` and suspending the
141 // relevant Threads, new Threads could have potentially been created. So
142 // continue to find and suspend new Threads until we don't find any.
143 } while (new_thread_found);
145 // Now all Threads of this Process except of this Thread should be suspended.
146 // Execute the callback function.
147 run_args->callback(suspended_threads_list, run_args->argument);
149 // Resume all Threads
150 for (const auto suspended_thread_handle :
151 suspended_threads_list.threadHandles) {
152 CHECK_NE(ResumeThread(suspended_thread_handle), -1);
153 CloseHandle(suspended_thread_handle);
156 return 0;
159 } // namespace
161 void StopTheWorld(StopTheWorldCallback callback, void *argument) {
162 struct RunThreadArgs arg = {callback, argument};
163 DWORD trace_thread_id;
165 auto trace_thread =
166 CreateThread(nullptr, 0, RunThread, &arg, 0, &trace_thread_id);
167 CHECK(trace_thread);
169 WaitForSingleObject(trace_thread, INFINITE);
170 CloseHandle(trace_thread);
173 } // namespace __sanitizer
175 #endif // SANITIZER_WINDOWS