1 //===-- sanitizer_stoptheworld_win.cpp ------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // See sanitizer_stoptheworld.h for details.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_platform.h"
17 # define WIN32_LEAN_AND_MEAN
19 // windows.h needs to be included before tlhelp32.h
20 # include <tlhelp32.h>
22 # include "sanitizer_stoptheworld.h"
24 namespace __sanitizer
{
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
50 # elif SANITIZER_ARM | SANITIZER_ARM64
53 # error Architecture not supported!
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
;
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
;
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
))
105 if (thread_entry
.th32ThreadID
== this_thread
||
106 thread_entry
.th32OwnerProcessID
!= this_process
)
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;
117 // Skip the Thread if it was already suspended
118 if (suspended_thread
)
121 const HANDLE thread
=
122 OpenThread(THREAD_ALL_ACCESS
, FALSE
, thread_entry
.th32ThreadID
);
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
);
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
);
161 void StopTheWorld(StopTheWorldCallback callback
, void *argument
) {
162 struct RunThreadArgs arg
= {callback
, argument
};
163 DWORD trace_thread_id
;
166 CreateThread(nullptr, 0, RunThread
, &arg
, 0, &trace_thread_id
);
169 WaitForSingleObject(trace_thread
, INFINITE
);
170 CloseHandle(trace_thread
);
173 } // namespace __sanitizer
175 #endif // SANITIZER_WINDOWS