From eee8458f4398969b8423ef27dc49c53a5d417ac9 Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Wed, 20 Jan 2021 16:12:41 -0800 Subject: [PATCH] Convert to Task --- src/OpenDebugAD7/AD7DebugSession.cs | 316 +++++++++++++++------------- 1 file changed, 173 insertions(+), 143 deletions(-) diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index 1b6ab7232..4a978448c 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -1415,208 +1415,238 @@ protected override void HandleGotoTargetsRequestAsync(IRequestResponder responder) + protected override async void HandleStackTraceRequestAsync(IRequestResponder responder) { - int threadReference = responder.Arguments.ThreadId; - int startFrame = responder.Arguments.StartFrame.GetValueOrDefault(0); - int levels = responder.Arguments.Levels.GetValueOrDefault(0); - - StackTraceResponse response = new StackTraceResponse() + try { - TotalFrames = 0 - }; + int threadReference = responder.Arguments.ThreadId; + int startFrame = responder.Arguments.StartFrame.GetValueOrDefault(0); + int levels = responder.Arguments.Levels.GetValueOrDefault(0); + + var response = new StackTraceResponse() + { + TotalFrames = 0 + }; + + // Make sure we are stopped and receiving valid input or else return an empty stack trace + if (!m_isStopped || startFrame < 0 || levels < 0) + { + responder.SetResponse(response); + return; + } - // Make sure we are stopped and receiving valid input or else return an empty stack trace - if (m_isStopped && startFrame >= 0 && levels >= 0) - { ThreadFrameEnumInfo frameEnumInfo = null; IDebugThread2 thread; lock (m_threads) { - if (m_threads.TryGetValue(threadReference, out thread)) + if (!m_threads.TryGetValue(threadReference, out thread)) { - enum_FRAMEINFO_FLAGS flags = enum_FRAMEINFO_FLAGS.FIF_FUNCNAME | // need a function name - enum_FRAMEINFO_FLAGS.FIF_FRAME | // need a frame object - enum_FRAMEINFO_FLAGS.FIF_FLAGS | - enum_FRAMEINFO_FLAGS.FIF_DEBUG_MODULEP; - - uint radix = Constants.EvaluationRadix; - - if (responder.Arguments.Format != null) - { - StackFrameFormat format = responder.Arguments.Format; - - if (format.Hex == true) - { - radix = 16; - } - - if (format.Line == true) - { - flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_LINES; - } + // Invalid thread specified + responder.SetError(new ProtocolException(String.Format(CultureInfo.CurrentCulture, AD7Resources.Error_PropertyInvalid, StackTraceRequest.RequestType, "threadId"))); + return; + } - if (format.Module == true) - { - flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE; - } + enum_FRAMEINFO_FLAGS flags = enum_FRAMEINFO_FLAGS.FIF_FUNCNAME | // need a function name + enum_FRAMEINFO_FLAGS.FIF_FRAME | // need a frame object + enum_FRAMEINFO_FLAGS.FIF_FLAGS | + enum_FRAMEINFO_FLAGS.FIF_DEBUG_MODULEP; - if (format.Parameters == true) - { - flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS; - } + uint radix = Constants.EvaluationRadix; - if (format.ParameterNames == true) - { - flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES; - } - - if (format.ParameterTypes == true) - { - flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES; - } + if (responder.Arguments.Format != null) + { + StackFrameFormat format = responder.Arguments.Format; - if (format.ParameterValues == true) - { - flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_VALUES; - } + if (format.Hex == true) + { + radix = 16; } - else + + if (format.Line == true) { - // No formatting flags provided in the request - use the default format, which includes the module name and argument names / types - flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE | - enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS | - enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES | - enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES; + flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_LINES; } - if (m_settingsCallback != null) + if (format.Module == true) { - // MIEngine generally gets the radix from IDebugSettingsCallback110 rather than using the radix passed - m_settingsCallback.Radix = radix; + flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE; } - ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_Scenario_StackTrace); + if (format.Parameters == true) + { + flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS; + } - try + if (format.ParameterNames == true) { - eb.CheckHR(thread.EnumFrameInfo(flags, radix, out IEnumDebugFrameInfo2 frameEnum)); - eb.CheckHR(frameEnum.GetCount(out uint totalFrames)); + flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES; + } - frameEnumInfo = new ThreadFrameEnumInfo(frameEnum, totalFrames); + if (format.ParameterTypes == true) + { + flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES; } - catch (AD7Exception ex) + + if (format.ParameterValues == true) { - responder.SetError(new ProtocolException(ex.Message, ex)); - return; + flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_VALUES; } } else { - // Invalid thread specified - responder.SetError(new ProtocolException(String.Format(CultureInfo.CurrentCulture, AD7Resources.Error_PropertyInvalid, StackTraceRequest.RequestType, "threadId"))); - return; + // No formatting flags provided in the request - use the default format, which includes the module name and argument names / types + flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE | + enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS | + enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES | + enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES; } - } - if (startFrame < frameEnumInfo.TotalFrames) - { - if (startFrame != frameEnumInfo.CurrentPosition) + if (m_settingsCallback != null) { - frameEnumInfo.FrameEnum.Reset(); - frameEnumInfo.CurrentPosition = (uint)startFrame; - - if (startFrame > 0) - { - frameEnumInfo.FrameEnum.Skip((uint)startFrame); - } + // MIEngine generally gets the radix from IDebugSettingsCallback110 rather than using the radix passed + m_settingsCallback.Radix = radix; } - if (levels == 0) + ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_Scenario_StackTrace); + + try { - // take the rest of the stack frames - levels = (int)frameEnumInfo.TotalFrames - startFrame; + eb.CheckHR(thread.EnumFrameInfo(flags, radix, out IEnumDebugFrameInfo2 frameEnum)); + eb.CheckHR(frameEnum.GetCount(out uint totalFrames)); + + frameEnumInfo = new ThreadFrameEnumInfo(frameEnum, totalFrames); } - else + catch (AD7Exception ex) { - levels = Math.Min((int)frameEnumInfo.TotalFrames - startFrame, levels); + responder.SetError(new ProtocolException(ex.Message, ex)); + return; } + } + + if (startFrame >= frameEnumInfo.TotalFrames) + { + responder.SetResponse(response); + return; + } - var frameInfoArray = new FRAMEINFO[levels]; - uint framesFetched = 0; - frameEnumInfo.FrameEnum.Next((uint)frameInfoArray.Length, frameInfoArray, ref framesFetched); - frameEnumInfo.CurrentPosition += framesFetched; + if (startFrame != frameEnumInfo.CurrentPosition) + { + frameEnumInfo.FrameEnum.Reset(); + frameEnumInfo.CurrentPosition = (uint)startFrame; - for (int i = 0; i < framesFetched; i++) + if (startFrame > 0) { - // TODO: annotated frames? - var frameInfo = frameInfoArray[i]; - IDebugStackFrame2 frame = frameInfo.m_pFrame; + frameEnumInfo.FrameEnum.Skip((uint)startFrame); + } + } - int frameReference = 0; - TextPositionTuple textPosition = TextPositionTuple.Nil; - IDebugCodeContext2 memoryAddress = null; + if (levels == 0) + { + // take the rest of the stack frames + levels = (int)frameEnumInfo.TotalFrames - startFrame; + } + else + { + levels = Math.Min((int)frameEnumInfo.TotalFrames - startFrame, levels); + } - if (frame != null) - { - frameReference = m_frameHandles.Create(frame); - textPosition = TextPositionTuple.GetTextPositionOfFrame(m_pathConverter, frame) ?? TextPositionTuple.Nil; - frame.GetCodeContext(out memoryAddress); - } + var frameInfoArray = new FRAMEINFO[levels]; + uint framesFetched = 0; + frameEnumInfo.FrameEnum.Next((uint)frameInfoArray.Length, frameInfoArray, ref framesFetched); + frameEnumInfo.CurrentPosition += framesFetched; - int? moduleId = null; - IDebugModule2 module = frameInfo.m_pModule; - if (module != null) + for (int i = 0; i < framesFetched; i++) + { + // TODO: annotated frames? + var frameInfo = frameInfoArray[i]; + IDebugStackFrame2 frame = frameInfo.m_pFrame; + + int frameReference = 0; + TextPositionTuple textPosition = TextPositionTuple.Nil; + IDebugCodeContext2 memoryAddress = null; + + if (frame != null) + { + frameReference = m_frameHandles.Create(frame); + textPosition = TextPositionTuple.GetTextPositionOfFrame(m_pathConverter, frame) ?? TextPositionTuple.Nil; + frame.GetCodeContext(out memoryAddress); + } + + int? moduleId = null; + IDebugModule2 module = frameInfo.m_pModule; + if (module != null) + { + lock (m_moduleMap) { - lock (m_moduleMap) + if (m_moduleMap.TryGetValue(module, out int mapModuleId)) { - if (m_moduleMap.TryGetValue(module, out int mapModuleId)) - { - moduleId = mapModuleId; - } + moduleId = mapModuleId; } } + } - string instructionPointerReference = null; - var contextInfo = new CONTEXT_INFO[1]; - if (memoryAddress?.GetInfo(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS, contextInfo) == HRConstants.S_OK && contextInfo[0].dwFields.HasFlag(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS)) - { - instructionPointerReference = contextInfo[0].bstrAddress; - } - - response.StackFrames.Add(new ProtocolMessages.StackFrame() - { - Id = frameReference, - Name = frameInfo.m_bstrFuncName, - Source = textPosition.Source, - Line = textPosition.Line, - Column = textPosition.Column, - ModuleId = moduleId, - InstructionPointerReference = instructionPointerReference - }); + string instructionPointerReference = null; + var contextInfo = new CONTEXT_INFO[1]; + if (memoryAddress?.GetInfo(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS, contextInfo) == HRConstants.S_OK && contextInfo[0].dwFields.HasFlag(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS)) + { + instructionPointerReference = contextInfo[0].bstrAddress; } - if (!IsClientVS) + response.StackFrames.Add(new ProtocolMessages.StackFrame() { - Parallel.ForEach(response.StackFrames, frame => + Id = frameReference, + Name = frameInfo.m_bstrFuncName, + Source = textPosition.Source, + Line = textPosition.Line, + Column = textPosition.Column, + ModuleId = moduleId, + InstructionPointerReference = instructionPointerReference + }); + } + + if (!IsClientVS) + { + var cancellationTokenSource = new CancellationTokenSource(); + try + { + CancellationToken cancellationToken = cancellationTokenSource.Token; + var frameTasks = response.StackFrames.Select(frame => Task.Run(() => { - if (frame.Source == null) - return; - var task = new Task(() => File.Exists(frame.Source.Path)); - task.Start(); - if (task.Wait(500) && !task.Result) + cancellationToken.ThrowIfCancellationRequested(); + if (frame.Source != null && !File.Exists(frame.Source.Path)) { + cancellationToken.ThrowIfCancellationRequested(); // mark the stack frame to be skipped by default frame.Source.PresentationHint = Source.PresentationHintValue.Deemphasize; } - }); - } + })); - response.TotalFrames = (int)frameEnumInfo.TotalFrames; + Task allFramesComplete = Task.WhenAll(frameTasks); + Task timeoutTask = Task.Delay(1000, cancellationToken); + try + { + await Task.WhenAny(allFramesComplete, timeoutTask); + } + catch (Exception e) + { + Debug.Fail("Ignoring exception computing frame state: " + e.ToString()); + } + } + finally + { + cancellationTokenSource.Cancel(); + cancellationTokenSource.Dispose(); + } } - } - responder.SetResponse(response); + response.TotalFrames = (int)frameEnumInfo.TotalFrames; + + responder.SetResponse(response); + } + catch (Exception e) + { + responder.SetError(new ProtocolException(e.Message)); + } } protected override void HandleScopesRequestAsync(IRequestResponder responder)