internal void SwitchProcess(PythonProcess process, bool verbose) { var newEvaluator = _evaluators[process.Id]; if (newEvaluator != _activeEvaluator) { _activeEvaluator = newEvaluator; ActiveProcessChanged(); if (verbose) { CurrentWindow.WriteLine(Strings.DebugReplSwitchProcessOutput.FormatUI(process.Id)); } } }
internal void SwitchProcess(PythonProcess process, bool verbose) { var newEvaluator = _evaluators[process.Id]; if (newEvaluator != _activeEvaluator) { _activeEvaluator = newEvaluator; ActiveProcessChanged(); if (verbose) { _window.WriteLine(String.Format("Current process changed to {0}", process.Id)); } } }
internal void SwitchProcess(PythonProcess process, bool verbose) { var newEvaluator = _evaluators[process.Id]; if (newEvaluator != _activeEvaluator) { _activeEvaluator = newEvaluator; ActiveProcessChanged(); if (verbose) { CurrentWindow.WriteLine(Strings.DebugReplSwitchProcessOutput.FormatUI(process.Id)); } } else if (CustomDebugAdapterProtocolExtension.CanUseExperimental()) { NotSupported(); } }
internal void DetachProcess(PythonProcess process) { int id = process.Id; PythonDebugProcessReplEvaluator evaluator; if (_evaluators.TryGetValue(id, out evaluator)) { evaluator.AvailableScopesChanged -= new EventHandler <EventArgs>(evaluator_AvailableScopesChanged); evaluator.MultipleScopeSupportChanged -= new EventHandler <EventArgs>(evaluator_MultipleScopeSupportChanged); process.DisconnectRepl(); _evaluators.Remove(id); if (_activeEvaluator == evaluator) { _activeEvaluator = null; } ActiveProcessChanged(); } }
internal void AttachProcess(PythonProcess process, IThreadIdMapper threadIdMapper) { if (_evaluators.ContainsKey(process.Id)) { // Process is already attached, so just switch to it if needed SwitchProcess(process, false); return; } process.ProcessExited += new EventHandler <ProcessExitedEventArgs>(OnProcessExited); var evaluator = new PythonDebugProcessReplEvaluator(_serviceProvider, process, _pyService, threadIdMapper); evaluator.Window = _window; evaluator.AvailableScopesChanged += new EventHandler <EventArgs>(evaluator_AvailableScopesChanged); evaluator.MultipleScopeSupportChanged += new EventHandler <EventArgs>(evaluator_MultipleScopeSupportChanged); _evaluators.Add(process.Id, evaluator); _activeEvaluator = evaluator; }
internal async Task DetachProcessAsync(PythonProcess process) { _serviceProvider.GetUIThread().MustBeCalledFromUIThread(); int id = process.Id; PythonDebugProcessReplEvaluator evaluator; if (_evaluators.TryGetValue(id, out evaluator)) { evaluator.AvailableScopesChanged -= new EventHandler <EventArgs>(evaluator_AvailableScopesChanged); evaluator.MultipleScopeSupportChanged -= new EventHandler <EventArgs>(evaluator_MultipleScopeSupportChanged); _evaluators.Remove(id); if (_activeEvaluator == evaluator) { _activeEvaluator = null; } ActiveProcessChanged(); } }
internal async Task AttachProcessAsync(PythonProcess process, IThreadIdMapper threadIdMapper) { _serviceProvider.GetUIThread().MustBeCalledFromUIThread(); if (_evaluators.ContainsKey(process.Id)) { // Process is already attached, so just switch to it if needed SwitchProcess(process, false); return; } process.ProcessExited += new EventHandler <ProcessExitedEventArgs>(OnProcessExited); var evaluator = new PythonDebugProcessReplEvaluator(_serviceProvider, process, threadIdMapper); evaluator.CurrentWindow = CurrentWindow; await evaluator.InitializeAsync(); evaluator.AvailableScopesChanged += new EventHandler <EventArgs>(evaluator_AvailableScopesChanged); evaluator.MultipleScopeSupportChanged += new EventHandler <EventArgs>(evaluator_MultipleScopeSupportChanged); _evaluators.Add(process.Id, evaluator); _activeEvaluator = evaluator; }
internal async Task AttachProcessAsync(PythonProcess process, IThreadIdMapper threadIdMapper) { // The fact that this is only called from UI thread is no guarantee // that there won't be more than one "instance" of this method in // progress at any time (though only one is executing while others are paused). // It's possible because this is an async method with await(s), and // UI thread execution will temporarily continue somewhere else when // await is used, and that somewhere else can be code that calls // into this method with the same process id! // The more relevant trigger for this cooperative multitasking is // the await on evaluator.InitializeAsync, and when that happens // the evaluator is not in the _evaluators dictionary yet. // If a second caller comes in (on the same UI thread) during that // await, it gets past the first check because it's not in _evaluators, // and then checks the _attachingTasks dictionary and know to wait // for that instead of creating a new evaluator. // Note that adding the uninitialized evaluator to the _evaluators // dictionary would be a potentially bug prone solution, as other // code may try to use it before it's fully initialized. _serviceProvider.GetUIThread().MustBeCalledFromUIThread(); if (_evaluators.ContainsKey(process.Id)) { // Process is already attached, so just switch to it if needed SwitchProcess(process, false); return; } // Keep track of evaluators that are in progress of attaching, and if // we are getting called to attach for one that is already in progress, // just wait for it to finish before returning. // Important: dictionary must be checked (and updated) before any // await call to avoid race condition. Task attachingTask; TaskCompletionSource <object> attachingTcs = null; if (_attachingTasks.TryGetValue(process.Id, out attachingTask)) { await attachingTask; return; } else { attachingTcs = new TaskCompletionSource <object>(); _attachingTasks.Add(process.Id, attachingTcs.Task); } process.ProcessExited += new EventHandler <ProcessExitedEventArgs>(OnProcessExited); var evaluator = new PythonDebugProcessReplEvaluator(_serviceProvider, process, threadIdMapper) { CurrentWindow = CurrentWindow }; evaluator.AvailableScopesChanged += new EventHandler <EventArgs>(evaluator_AvailableScopesChanged); evaluator.MultipleScopeSupportChanged += new EventHandler <EventArgs>(evaluator_MultipleScopeSupportChanged); await evaluator.InitializeAsync(); _evaluators.Add(process.Id, evaluator); _activeEvaluator = evaluator; // Only refresh available scopes after the active evaluator has // been changed, because that's where the UI will look. await evaluator.RefreshAvailableScopes(); attachingTcs.SetResult(null); _attachingTasks.Remove(process.Id); }
internal void DetachProcess(PythonProcess process) { int id = process.Id; PythonDebugProcessReplEvaluator evaluator; if (_evaluators.TryGetValue(id, out evaluator)) { evaluator.AvailableScopesChanged -= new EventHandler<EventArgs>(evaluator_AvailableScopesChanged); evaluator.MultipleScopeSupportChanged -= new EventHandler<EventArgs>(evaluator_MultipleScopeSupportChanged); process.DisconnectRepl(); _evaluators.Remove(id); if (_activeEvaluator == evaluator) { _activeEvaluator = null; } ActiveProcessChanged(); } }
internal void AttachProcess(PythonProcess process, IThreadIdMapper threadIdMapper) { if (_evaluators.ContainsKey(process.Id)) { // Process is already attached, so just switch to it if needed SwitchProcess(process, false); return; } process.ProcessExited += new EventHandler<ProcessExitedEventArgs>(OnProcessExited); var evaluator = new PythonDebugProcessReplEvaluator(_serviceProvider, process, _pyService, threadIdMapper); evaluator.Window = _window; evaluator.InitializeAsync().WaitAndUnwrapExceptions(); evaluator.AvailableScopesChanged += new EventHandler<EventArgs>(evaluator_AvailableScopesChanged); evaluator.MultipleScopeSupportChanged += new EventHandler<EventArgs>(evaluator_MultipleScopeSupportChanged); _evaluators.Add(process.Id, evaluator); _activeEvaluator = evaluator; }
internal void SwitchProcess(PythonProcess process, bool verbose) { var newEvaluator = _evaluators[process.Id]; if (newEvaluator != _activeEvaluator) { _activeEvaluator = newEvaluator; ActiveProcessChanged(); if (verbose) { _window.WriteLine(String.Format("Current process changed to {0}", process.Id)); } } }