Fix evalwaiter logic.
authorMikhail Kurinnoi <m.kurinnoi@samsung.com>
Mon, 3 Apr 2023 09:41:54 +0000 (12:41 +0300)
committerGleb Balykov/Advanced System SW Lab /SRR/Staff Engineer/Samsung Electronics <g.balykov@samsung.com>
Tue, 25 Apr 2023 18:28:08 +0000 (21:28 +0300)
Will care about managed code execution stop during evaluation for delegates, reverse pinvokes and managed threads now.
Current logic stop only managed threads (threads that was created with CreateThread() callback) and don't stop delegates and reverse pinvokes called from native threads.

src/debugger/evalwaiter.cpp
src/debugger/evalwaiter.h
src/debugger/manageddebugger.cpp

index 1cc511a771c996f327f9affbb3cb00636f1345f0..0260bdb953c2d85fdc63d7a7a4f56738156f8f54 100644 (file)
@@ -3,7 +3,6 @@
 // See the LICENSE file in the project root for more information.\r
 \r
 #include "debugger/evalwaiter.h"\r
-#include "debugger/threads.h"\r
 \r
 namespace netcoredbg\r
 {\r
@@ -115,30 +114,31 @@ HRESULT EvalWaiter::WaitEvalResult(ICorDebugThread *pThread,
     IfFailRet(pThread->GetProcess(&iCorProcess));\r
     if (!iCorProcess)\r
         return E_FAIL;\r
-    std::vector<ThreadId> userThreadIds;\r
-    IfFailRet(m_sharedThreads->GetThreadIds(userThreadIds));\r
-    ThreadId threadId(getThreadId(pThread));\r
-    if (!threadId)\r
-        return E_FAIL;\r
+    DWORD evalThreadId = 0;\r
+    IfFailRet(pThread->GetID(&evalThreadId));\r
 \r
-    // Note, we need suspend during eval only user's threads, that not used for eval.\r
+    // Note, we need suspend during eval all managed threads, that not used for eval (delegates, reverse pinvokes, managed threads).\r
     auto ChangeThreadsState = [&](CorDebugThreadState state)\r
     {\r
-        for (const auto &userThreadId : userThreadIds)\r
+        ToRelease<ICorDebugThreadEnum> iCorThreadEnum;\r
+        iCorProcess->EnumerateThreads(&iCorThreadEnum);\r
+        ULONG fetched = 0;\r
+        ToRelease<ICorDebugThread> iCorThread;\r
+        while (SUCCEEDED(iCorThreadEnum->Next(1, &iCorThread, &fetched)) && fetched == 1)\r
         {\r
-            if (threadId == userThreadId)\r
-                continue;\r
-\r
-            ToRelease<ICorDebugThread> iCorThread;\r
-            if (FAILED(iCorProcess->GetThread(int(userThreadId), &iCorThread)) ||\r
-                FAILED(iCorThread->SetDebugState(state)))\r
+            DWORD tid = 0;\r
+            if (SUCCEEDED(iCorThread->GetID(&tid)) && evalThreadId != tid)\r
             {\r
-                if (state == THREAD_SUSPEND)\r
-                    LOGW("%s %s", "SetDebugState(THREAD_SUSPEND) during eval setup failed.",\r
-                         "This may change the state of the process and any breakpoints and exceptions encountered will be skipped.");\r
-                else\r
-                    LOGW("SetDebugState(THREAD_RUN) during eval failed. Process state was not restored.");\r
+                if (FAILED(iCorThread->SetDebugState(state)))\r
+                {\r
+                    if (state == THREAD_SUSPEND)\r
+                        LOGW("%s %s", "SetDebugState(THREAD_SUSPEND) during eval setup failed.",\r
+                            "This may change the state of the process and any breakpoints and exceptions encountered will be skipped.");\r
+                    else\r
+                        LOGW("SetDebugState(THREAD_RUN) during eval failed. Process state was not restored.");\r
+                }\r
             }\r
+            iCorThread.Free();\r
         }\r
     };\r
 \r
@@ -175,7 +175,7 @@ HRESULT EvalWaiter::WaitEvalResult(ICorDebugThread *pThread,
                 // All CoreCLR releases at least till version 3.1.3, don't have proper x86 implementation for ICorDebugEval::Abort().\r
                 // This issue looks like CoreCLR terminate managed process execution instead of abort evaluation.\r
 \r
-                // In this case we have same behaviour as MS vsdbg and MSVS C# debugger - run all user threads and try to abort eval by any cost.\r
+                // In this case we have same behaviour as MS vsdbg and MSVS C# debugger - run all managed threads and try to abort eval by any cost.\r
                 // Ignore errors here, this our last chance prevent debugger hangs.\r
                 iCorProcess->Stop(0);\r
                 ChangeThreadsState(THREAD_RUN);\r
index 1372f22d611336422c3bc0361633cea138388e54..1919ab3f78c9a5b6d9ecd7076bfb9daa047544b2 100644 (file)
 namespace netcoredbg\r
 {\r
 \r
-class Threads;\r
-\r
 class EvalWaiter\r
 {\r
 public:\r
 \r
     typedef std::function<HRESULT(ICorDebugEval*)> WaitEvalResultCallback;\r
 \r
-    EvalWaiter(std::shared_ptr<Threads> &sharedThreads) : m_sharedThreads(sharedThreads), m_evalCanceled(false), m_evalCrossThreadDependency(false) {}\r
+    EvalWaiter() : m_evalCanceled(false), m_evalCrossThreadDependency(false) {}\r
 \r
     bool IsEvalRunning();\r
     void CancelEvalRunning();\r
@@ -38,7 +36,6 @@ public:
 \r
 private:\r
 \r
-    std::shared_ptr<Threads> m_sharedThreads;\r
     bool m_evalCanceled;\r
     bool m_evalCrossThreadDependency;\r
 \r
index dfa2993abca9b76aff5026352d6a9fd9f3c26194..0fa94c8b7a4ad272054bbeb779e88afb2016c21d 100644 (file)
@@ -175,7 +175,7 @@ ManagedDebugger::ManagedDebugger() :
     m_isConfigurationDone(false),
     m_sharedThreads(new Threads),
     m_sharedModules(new Modules),
-    m_sharedEvalWaiter(new EvalWaiter(m_sharedThreads)),
+    m_sharedEvalWaiter(new EvalWaiter),
     m_sharedEvalHelpers(new EvalHelpers(m_sharedModules, m_sharedEvalWaiter)),
     m_sharedEvalStackMachine(new EvalStackMachine),
     m_sharedEvaluator(new Evaluator(m_sharedModules, m_sharedEvalHelpers, m_sharedEvalStackMachine)),