Suspends all threads ensuring that they are not currently in a call to Py_AddPendingCall.
| 201 | |
| 202 | // Suspends all threads ensuring that they are not currently in a call to Py_AddPendingCall. |
| 203 | void SuspendThreads(ThreadMap &suspendedThreads, Py_AddPendingCall* addPendingCall, PyEval_ThreadsInitialized* threadsInited) { |
| 204 | DWORD curThreadId = GetCurrentThreadId(); |
| 205 | DWORD curProcess = GetCurrentProcessId(); |
| 206 | // suspend all the threads in the process so we can do things safely... |
| 207 | bool suspended; |
| 208 | |
| 209 | do { |
| 210 | suspended = false; |
| 211 | HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
| 212 | if (h != INVALID_HANDLE_VALUE) { |
| 213 | |
| 214 | THREADENTRY32 te; |
| 215 | te.dwSize = sizeof(te); |
| 216 | if (Thread32First(h, &te)) { |
| 217 | do { |
| 218 | if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID) && te.th32OwnerProcessID == curProcess) { |
| 219 | |
| 220 | |
| 221 | if (te.th32ThreadID != curThreadId && suspendedThreads.find(te.th32ThreadID) == suspendedThreads.end()) { |
| 222 | auto hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID); |
| 223 | if (hThread != nullptr) { |
| 224 | SuspendThread(hThread); |
| 225 | |
| 226 | bool addingPendingCall = false; |
| 227 | |
| 228 | CONTEXT context; |
| 229 | memset(&context, 0x00, sizeof(CONTEXT)); |
| 230 | context.ContextFlags = CONTEXT_ALL; |
| 231 | GetThreadContext(hThread, &context); |
| 232 | |
| 233 | #if defined(_X86_) |
| 234 | if (context.Eip >= *(reinterpret_cast<DWORD*>(addPendingCall)) && context.Eip <= (*(reinterpret_cast<DWORD*>(addPendingCall))) + 0x100) { |
| 235 | addingPendingCall = true; |
| 236 | } |
| 237 | #elif defined(_AMD64_) |
| 238 | if (context.Rip >= *(reinterpret_cast<DWORD64*>(addPendingCall)) && context.Rip <= *(reinterpret_cast<DWORD64*>(addPendingCall) + 0x100)) { |
| 239 | addingPendingCall = true; |
| 240 | } |
| 241 | #endif |
| 242 | |
| 243 | if (addingPendingCall) { |
| 244 | // we appear to be adding a pending call via this thread - wait for this to finish so we can add our own pending call... |
| 245 | ResumeThread(hThread); |
| 246 | SwitchToThread(); // yield to the resumed thread if it's on our CPU... |
| 247 | CloseHandle(hThread); |
| 248 | } else { |
| 249 | suspendedThreads[te.th32ThreadID] = hThread; |
| 250 | } |
| 251 | suspended = true; |
| 252 | } |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | te.dwSize = sizeof(te); |
| 257 | } while (Thread32Next(h, &te) && !threadsInited()); |
| 258 | } |
| 259 | CloseHandle(h); |
| 260 | } |
no test coverage detected