public virtual async Task AttachSingleThreadedSleeper() { // http://pytools.codeplex.com/discussions/285741 1/12/2012 6:20 PM Process p = Process.Start(Version.InterpreterPath, "\"" + TestData.GetPath(@"TestData\DebuggerProject\AttachSingleThreadedSleeper.py") + "\""); try { Thread.Sleep(1000); var attached = new TaskCompletionSource <bool>(); var proc = PythonProcess.Attach(p.Id); try { proc.ProcessLoaded += (sender, args) => { attached.SetResult(true); }; await proc.StartListeningAsync(); using (var dumpWriter = new MiniDumpWriter(p)) { await attached.Task.WithTimeout(10000, "Failed to attach within 10s"); await proc.ResumeAsync(TimeoutToken()); Debug.WriteLine("Waiting for exit"); dumpWriter.Cancel(); } } finally { TerminateProcess(proc); } } finally { DisposeProcess(p); } }
public virtual async Task AttachWithOutputRedirection() { var expectedOutput = new[] { "stdout", "stderr" }; string script = TestData.GetPath(@"TestData\DebuggerProject\AttachOutput.py"); var p = Process.Start(Version.InterpreterPath, "\"" + script + "\""); try { using (var dumpWriter = new MiniDumpWriter(p)) { Thread.Sleep(1000); var proc = PythonProcess.Attach(p.Id, PythonDebugOptions.RedirectOutput); try { var attached = new TaskCompletionSource <bool>(); proc.ProcessLoaded += (sender, args) => { Console.WriteLine("Process loaded"); attached.SetResult(true); }; await proc.StartListeningAsync(); await attached.Task.WithTimeout(20000, "Failed to attach within 20s"); await proc.ResumeAsync(TimeoutToken()); var bpHit = new TaskCompletionSource <bool>(); PythonThread thread = null; proc.BreakpointHit += (sender, args) => { thread = args.Thread; bpHit.SetResult(true); }; var bp = proc.AddBreakpoint(script, 5); await bp.AddAsync(TimeoutToken()); await bpHit.Task.WithTimeout(20000, "Failed to hit breakpoint within 20s"); Assert.IsNotNull(thread); var actualOutput = new List <string>(); proc.DebuggerOutput += (sender, e) => { Console.WriteLine("Debugger output: '{0}'", e.Output); actualOutput.Add(e.Output); }; var frame = thread.Frames[0]; Assert.AreEqual("False", (await frame.ExecuteTextAsync("attached", ct: CancellationTokens.After15s)).StringRepr); await frame.ExecuteTextAsync("attached = True", ct : TimeoutToken()); await proc.ResumeAsync(TimeoutToken()); WaitForExit(proc); AssertUtil.ArrayEquals(expectedOutput, actualOutput); } finally { await DetachProcessAsync(proc); } dumpWriter.Cancel(); } } finally { DisposeProcess(p); } }
public virtual async Task AttachAndStepWithBlankSysPrefix() { string script = TestData.GetPath(@"TestData\DebuggerProject\InfiniteRunBlankPrefix.py"); var p = Process.Start(Version.InterpreterPath, "\"" + script + "\""); try { using (var dumpWriter = new MiniDumpWriter(p)) { Thread.Sleep(1000); var proc = PythonProcess.Attach(p.Id); try { var attached = new TaskCompletionSource <bool>(); proc.ProcessLoaded += async(sender, args) => { Console.WriteLine("Process loaded"); await proc.ResumeAsync(TimeoutToken()); attached.SetResult(true); }; await proc.StartListeningAsync(); await attached.Task.WithTimeout(20000, "Failed to attach within 20s"); var bpHit = new TaskCompletionSource <bool>(); PythonThread thread = null; PythonStackFrame oldFrame = null; proc.BreakpointHit += (sender, args) => { Console.WriteLine("Breakpoint hit"); thread = args.Thread; oldFrame = args.Thread.Frames[0]; bpHit.SetResult(true); }; var bp = proc.AddBreakpoint(script, 6); await bp.AddAsync(TimeoutToken()); await bpHit.Task.WithTimeout(20000, "Failed to hit breakpoint within 20s"); var stepComplete = new TaskCompletionSource <bool>(); PythonStackFrame newFrame = null; proc.StepComplete += (sender, args) => { newFrame = args.Thread.Frames[0]; stepComplete.SetResult(true); }; await thread.StepOverAsync(TimeoutToken()); await stepComplete.Task.WithTimeout(20000, "Failed to complete the step within 20s"); Assert.AreEqual(oldFrame.FileName, newFrame.FileName); Assert.IsTrue(oldFrame.LineNo + 1 == newFrame.LineNo); } finally { await DetachProcessAsync(proc); } dumpWriter.Cancel(); } } finally { DisposeProcess(p); } }
public virtual async Task AttachReattach() { Process p = Process.Start(Version.InterpreterPath, "\"" + TestData.GetPath(@"TestData\DebuggerProject\InfiniteRun.py") + "\""); try { using (var dumpWriter = new MiniDumpWriter(p)) { Thread.Sleep(1000); for (int i = 0; i < 10; i++) { Console.WriteLine(i); var attached = new TaskCompletionSource <bool>(); var detached = new TaskCompletionSource <bool>(); var proc = PythonProcess.Attach(p.Id); proc.ProcessLoaded += (sender, args) => { attached.SetResult(true); }; proc.ProcessExited += (sender, args) => { detached.SetResult(true); }; await proc.StartListeningAsync(20000); await attached.Task.WithTimeout(10000, "Failed to attach within 10s"); await proc.DetachAsync(TimeoutToken()); await detached.Task.WithTimeout(10000, "Failed to detach within 10s"); } dumpWriter.Cancel(); } } finally { DisposeProcess(p); } }
public async Task AttachPtvsd() { var expectedOutput = new[] { "stdout", "stderr" }; string script = TestData.GetPath(@"TestData\DebuggerProject\AttachPtvsd.py"); var psi = new ProcessStartInfo(Version.InterpreterPath, PtvsdInterpreterArguments + " \"" + script + "\"") { WorkingDirectory = TestData.GetPath(), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true }; var p = Process.Start(psi); try { using (var dumpWriter = new MiniDumpWriter(p)) { PythonProcess proc = null; for (int i = 0; ; ++i) { Thread.Sleep(1000); try { proc = await PythonRemoteProcess.AttachAsync( new Uri("tcp://secret@localhost?opt=" + PythonDebugOptions.RedirectOutput), false, TimeoutToken()); break; } catch (SocketException) { // Failed to connect - the process might have not started yet, so keep trying a few more times. if (i >= 5 || p.HasExited) { throw; } } } try { var attached = new TaskCompletionSource <bool>(); proc.ProcessLoaded += async(sender, e) => { Console.WriteLine("Process loaded"); var bp = proc.AddBreakpoint(script, 10); await bp.AddAsync(TimeoutToken()); await proc.ResumeAsync(TimeoutToken()); attached.SetResult(true); }; var actualOutput = new List <string>(); proc.DebuggerOutput += (sender, e) => { actualOutput.Add(e.Output); }; var bpHit = new TaskCompletionSource <bool>(); proc.BreakpointHit += async(sender, args) => { Console.WriteLine("Breakpoint hit"); bpHit.SetResult(true); await proc.ResumeAsync(TimeoutToken()); }; await proc.StartListeningAsync(); await attached.Task.WithTimeout(20000, "Failed to attach within 20s"); await bpHit.Task.WithTimeout(20000, "Failed to hit breakpoint within 20s"); p.WaitForExit(DefaultWaitForExitTimeout); AssertUtil.ArrayEquals(expectedOutput, actualOutput); } finally { await DetachProcessAsync(proc); } dumpWriter.Cancel(); } } finally { Console.WriteLine(p.StandardOutput.ReadToEnd()); Console.WriteLine(p.StandardError.ReadToEnd()); DisposeProcess(p); } }
private async Task AttachTestTimeoutAsync(string hostCode) { var exe = CompileCode(hostCode); // start the test process w/ our handle var eventName = Guid.NewGuid().ToString(); EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName); ProcessStartInfo psi = new ProcessStartInfo(exe, eventName); psi.UseShellExecute = false; psi.RedirectStandardError = psi.RedirectStandardOutput = true; psi.CreateNoWindow = true; // Add Python to PATH so that the host can locate the DLL in case it's not in \Windows\System32 (e.g. for EPD) psi.EnvironmentVariables["PATH"] = Environment.GetEnvironmentVariable("PATH") + ";" + Path.GetDirectoryName(Version.InterpreterPath); Process p = Process.Start(psi); var outRecv = new OutputReceiver(); p.OutputDataReceived += outRecv.OutputDataReceived; p.ErrorDataReceived += outRecv.OutputDataReceived; p.BeginErrorReadLine(); p.BeginOutputReadLine(); try { using (var dumpWriter = new MiniDumpWriter(p)) { bool isAttached = false; // Start the attach with the GIL held. var attachStarted = new TaskCompletionSource <bool>(); var attachDone = new TaskCompletionSource <bool>(); // We run the Attach and StartListeningAsync on a separate thread, // because StartListeningAsync waits until debuggee has connected // back (which it won't do until handle is set). var attachTask = Task.Run(async() => { var proc = PythonProcess.Attach(p.Id); try { proc.ProcessLoaded += (sender, args) => { attachDone.SetResult(true); isAttached = true; }; attachStarted.SetResult(true); await proc.StartListeningAsync(10000); } finally { await DetachProcessAsync(proc); } }); await Task.WhenAny(attachTask, attachStarted.Task).Unwrap().WithTimeout(10000, "Failed to start attaching within 10s"); Assert.IsFalse(isAttached, "Should not have attached yet"); // we should be blocked handle.Set(); // let the code start running await Task.WhenAny(attachTask, attachDone.Task).Unwrap().WithTimeout(10000, "Failed to attach within 10s"); dumpWriter.Cancel(); } } finally { Debug.WriteLine(String.Format("Process output: {0}", outRecv.Output.ToString())); DisposeProcess(p); } }
public virtual async Task AttachThreadingStartNewThread() { // http://pytools.codeplex.com/workitem/638 // http://pytools.codeplex.com/discussions/285741#post724014 var psi = new ProcessStartInfo(Version.InterpreterPath, "\"" + TestData.GetPath(@"TestData\DebuggerProject\ThreadingStartNewThread.py") + "\""); psi.WorkingDirectory = TestData.GetPath(@"TestData\DebuggerProject"); psi.EnvironmentVariables["PYTHONPATH"] = @"..\.."; psi.UseShellExecute = false; psi.RedirectStandardOutput = true; psi.RedirectStandardError = true; Process p = Process.Start(psi); try { using (var dumpWriter = new MiniDumpWriter(p)) { if (p.WaitForExit(1000)) { Assert.Fail("Process exited"); } var proc = PythonProcess.Attach(p.Id); try { var attached = new TaskCompletionSource <bool>(); var readyToContinue = new TaskCompletionSource <bool>(); var threadBreakpointHit = new TaskCompletionSource <bool>(); proc.ProcessLoaded += async(sender, args) => { attached.TrySetResult(true); var bp = proc.AddBreakpoint("ThreadingStartNewThread.py", 9); await bp.AddAsync(TimeoutToken()); bp = proc.AddBreakpoint("ThreadingStartNewThread.py", 5); await bp.AddAsync(TimeoutToken()); await proc.ResumeAsync(TimeoutToken()); }; PythonThread mainThread = null; PythonThread bpThread = null; bool wrongLine = false; proc.BreakpointHit += async(sender, args) => { if (args.Breakpoint.LineNo == 9) { // stop running the infinite loop Debug.WriteLine(String.Format("First BP hit {0}", args.Thread.Id)); mainThread = args.Thread; await args.Thread.Frames[0].ExecuteTextAsync( "x = False", x => readyToContinue.TrySetResult(true), TimeoutToken()); } else if (args.Breakpoint.LineNo == 5) { // we hit the breakpoint on the new thread Debug.WriteLine(String.Format("Second BP hit {0}", args.Thread.Id)); bpThread = args.Thread; threadBreakpointHit.TrySetResult(true); await proc.ResumeAsync(TimeoutToken()); } else { Debug.WriteLine(String.Format("Hit breakpoint on wrong line number: {0}", args.Breakpoint.LineNo)); wrongLine = true; attached.TrySetResult(true); threadBreakpointHit.TrySetResult(true); await proc.ResumeAsync(TimeoutToken()); } }; await proc.StartListeningAsync(); await attached.Task.WithTimeout(30000, "Failed to attach within 30s"); await readyToContinue.Task.WithTimeout(30000, "Failed to hit the main thread breakpoint within 30s"); await proc.ResumeAsync(TimeoutToken()); await threadBreakpointHit.Task.WithTimeout(30000, "Failed to hit the background thread breakpoint within 30s"); Assert.IsFalse(wrongLine, "Breakpoint broke on the wrong line"); Assert.AreNotEqual(mainThread, bpThread); } finally { await DetachProcessAsync(proc); } } } finally { DisposeProcess(p); } }
public virtual async Task AttachNewThread_PyThreadState_New() { var hostCode = @"#include <Windows.h> #include <process.h> #include <Python.h> PyObject *g_pFunc; void Thread(void*) { printf(""Worker thread started %x\r\n"", GetCurrentThreadId()); while (true) { PyEval_AcquireLock(); PyInterpreterState* pMainInterpreterState = PyInterpreterState_Head(); auto pThisThreadState = PyThreadState_New(pMainInterpreterState); PyThreadState_Swap(pThisThreadState); PyObject *pValue; pValue = PyObject_CallObject(g_pFunc, 0); if (pValue != NULL) { //printf(""Result of call: %ld\n"", PyInt_AsLong(pValue)); Py_DECREF(pValue); } else { PyErr_Print(); return; } PyThreadState_Swap(NULL); PyThreadState_Clear(pThisThreadState); PyThreadState_Delete(pThisThreadState); PyEval_ReleaseLock(); Sleep(1000); } } void main() { PyObject *pName, *pModule; Py_SetPythonHome($PYTHON_HOME); Py_Initialize(); PyEval_InitThreads(); pName = CREATE_STRING(""gilstate_attach""); pModule = PyImport_Import(pName); Py_DECREF(pName); if (pModule != NULL) { g_pFunc = PyObject_GetAttrString(pModule, ""test""); if (g_pFunc && PyCallable_Check(g_pFunc)) { DWORD threadID; threadID = _beginthread(&Thread, 1024*1024, 0); threadID = _beginthread(&Thread, 1024*1024, 0); PyEval_ReleaseLock(); while (true); } else { if (PyErr_Occurred()) PyErr_Print(); } Py_XDECREF(g_pFunc); Py_DECREF(pModule); } else { PyErr_Print(); return; } Py_Finalize(); return; }".Replace("CREATE_STRING", CreateString); var exe = CompileCode(hostCode); File.WriteAllText(Path.Combine(Path.GetDirectoryName(exe), "gilstate_attach.py"), @"def test(): for i in range(10): print(i) return 0"); // start the test process w/ our handle Process p = RunHost(exe); try { using (var dumpWriter = new MiniDumpWriter(p)) { Thread.Sleep(1500); var attached = new TaskCompletionSource <bool>(); var bpHit = new TaskCompletionSource <bool>(); var proc = PythonProcess.Attach(p.Id); try { proc.ProcessLoaded += (sender, args) => { Console.WriteLine("Process loaded"); attached.SetResult(true); }; await proc.StartListeningAsync(); await attached.Task.WithTimeout(20000, "Failed to attach within 20s"); proc.BreakpointHit += (sender, args) => { Console.WriteLine("Breakpoint hit"); bpHit.SetResult(true); }; var bp = proc.AddBreakpoint("gilstate_attach.py", 3); await bp.AddAsync(TimeoutToken()); await bpHit.Task.WithTimeout(20000, "Failed to hit breakpoint within 20s"); } finally { await DetachProcessAsync(proc); } dumpWriter.Cancel(); } } finally { DisposeProcess(p); } }